Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (213 commits) V4L/DVB (12720): em28xx-cards: Add vendor/product id for Kworld DVD Maker 2 V4L/DVB (12713): em28xx: Cleanups at ir_i2c handler V4L/DVB (12712): em28xx: properly load ir-kbd-i2c when needed V4L/DVB (12701): saa7134: ir-kbd-i2c init data needs a persistent object V4L/DVB (12699): cx18: ir-kbd-i2c initialization data should point to a persistent object V4L/DVB (12698): em28xx: ir-kbd-i2c init data needs a persistent object V4L/DVB (12707): gspca - sn9c20x: Add SXGA support to MT9M111 V4L/DVB (12706): gspca - sn9c20x: disable exposure/gain controls for MT9M111 sensors. V4L/DVB (12705): gspca - sn9c20x: Add SXGA support to SOI968 V4L/DVB (12703): gspca - sn9c20x: Reduces size of object V4L/DVB (12704): gspca - sn9c20x: Fix exposure on SOI968 sensors V4L/DVB (12696): gspca - sonixj / sn9c102: Two drivers for 0c45:60fc and 0c45:613e. V4L/DVB (12695): gspca - vc032x: Do the LED work with the sensor hv7131r. V4L/DVB (12694): gspca - vc032x: Change the start exchanges of the sensor hv7131r. V4L/DVB (12693): gspca - sunplus: The brightness is signed. V4L/DVB (12692): gspca - sunplus: Optimize code. V4L/DVB (12691): gspca - sonixj: Don't use mdelay(). V4L/DVB (12690): gspca - pac7311: Webcam 06f8:3009 added. V4L/DVB (12686): dvb-core: check supported QAM modulations V4L/DVB (12685): dvb-core: check fe->ops.set_frontend return value ...
This commit is contained in:
Коммит
043fe50f80
|
@ -21,3 +21,5 @@
|
|||
20 -> Hauppauge WinTV-HVR1255 [0070:2251]
|
||||
21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295]
|
||||
22 -> Mygica X8506 DMB-TH [14f1:8651]
|
||||
23 -> Magic-Pro ProHDTV Extreme 2 [14f1:8657]
|
||||
24 -> Hauppauge WinTV-HVR1850 [0070:8541]
|
||||
|
|
|
@ -80,3 +80,4 @@
|
|||
79 -> Terratec Cinergy HT PCI MKII [153b:1177]
|
||||
80 -> Hauppauge WinTV-IR Only [0070:9290]
|
||||
81 -> Leadtek WinFast DTV1800 Hybrid [107d:6654]
|
||||
82 -> WinFast DTV2000 H rev. J [107d:6f2b]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
6 -> Terratec Cinergy 200 USB (em2800)
|
||||
7 -> Leadtek Winfast USB II (em2800) [0413:6023]
|
||||
8 -> Kworld USB2800 (em2800)
|
||||
9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker (em2820/em2840) [1b80:e302,2304:0207,2304:021a]
|
||||
9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker (em2820/em2840) [1b80:e302,1b80:e304,2304:0207,2304:021a]
|
||||
10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500]
|
||||
11 -> Terratec Hybrid XS (em2880) [0ccd:0042]
|
||||
12 -> Kworld PVR TV 2800 RF (em2820/em2840)
|
||||
|
@ -33,7 +33,7 @@
|
|||
34 -> Terratec Cinergy A Hybrid XS (em2860) [0ccd:004f]
|
||||
35 -> Typhoon DVD Maker (em2860)
|
||||
36 -> NetGMBH Cam (em2860)
|
||||
37 -> Gadmei UTV330 (em2860)
|
||||
37 -> Gadmei UTV330 (em2860) [eb1a:50a6]
|
||||
38 -> Yakumo MovieMixer (em2861)
|
||||
39 -> KWorld PVRTV 300U (em2861) [eb1a:e300]
|
||||
40 -> Plextor ConvertX PX-TV100U (em2861) [093b:a005]
|
||||
|
@ -67,3 +67,4 @@
|
|||
69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313]
|
||||
70 -> Evga inDtube (em2882)
|
||||
71 -> Silvercrest Webcam 1.3mpix (em2820/em2840)
|
||||
72 -> Gadmei UTV330+ (em2861)
|
||||
|
|
|
@ -167,3 +167,7 @@
|
|||
166 -> Beholder BeholdTV 607 RDS [5ace:6073]
|
||||
167 -> Beholder BeholdTV 609 RDS [5ace:6092]
|
||||
168 -> Beholder BeholdTV 609 RDS [5ace:6093]
|
||||
169 -> Compro VideoMate S350/S300 [185b:c900]
|
||||
170 -> AverMedia AverTV Studio 505 [1461:a115]
|
||||
171 -> Beholder BeholdTV X7 [5ace:7595]
|
||||
172 -> RoverMedia TV Link Pro FM [19d1:0138]
|
||||
|
|
|
@ -78,3 +78,4 @@ tuner=77 - TCL tuner MF02GIP-5N-E
|
|||
tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
|
||||
tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
|
||||
tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
|
||||
tuner=81 - Partsnic (Daewoo) PTI-5NF05
|
||||
|
|
|
@ -18,8 +18,8 @@ Table of Contents
|
|||
|
||||
1.0 Introduction
|
||||
|
||||
The file ../drivers/char/c-qcam.c is a device driver for the
|
||||
Logitech (nee Connectix) parallel port interface color CCD camera.
|
||||
The file ../../drivers/media/video/c-qcam.c is a device driver for
|
||||
the Logitech (nee Connectix) parallel port interface color CCD camera.
|
||||
This is a fairly inexpensive device for capturing images. Logitech
|
||||
does not currently provide information for developers, but many people
|
||||
have engineered several solutions for non-Microsoft use of the Color
|
||||
|
|
|
@ -140,6 +140,7 @@ spca500 04fc:7333 PalmPixDC85
|
|||
sunplus 04fc:ffff Pure DigitalDakota
|
||||
spca501 0506:00df 3Com HomeConnect Lite
|
||||
sunplus 052b:1513 Megapix V4
|
||||
sunplus 052b:1803 MegaImage VI
|
||||
tv8532 0545:808b Veo Stingray
|
||||
tv8532 0545:8333 Veo Stingray
|
||||
sunplus 0546:3155 Polaroid PDC3070
|
||||
|
@ -182,6 +183,7 @@ ov534 06f8:3002 Hercules Blog Webcam
|
|||
ov534 06f8:3003 Hercules Dualpix HD Weblog
|
||||
sonixj 06f8:3004 Hercules Classic Silver
|
||||
sonixj 06f8:3008 Hercules Deluxe Optical Glass
|
||||
pac7311 06f8:3009 Hercules Classic Link
|
||||
spca508 0733:0110 ViewQuest VQ110
|
||||
spca508 0130:0130 Clone Digital Webcam 11043
|
||||
spca501 0733:0401 Intel Create and Share
|
||||
|
@ -235,8 +237,10 @@ pac7311 093a:2621 PAC731x
|
|||
pac7311 093a:2622 Genius Eye 312
|
||||
pac7311 093a:2624 PAC7302
|
||||
pac7311 093a:2626 Labtec 2200
|
||||
pac7311 093a:2629 Genious iSlim 300
|
||||
pac7311 093a:262a Webcam 300k
|
||||
pac7311 093a:262c Philips SPC 230 NC
|
||||
jeilinj 0979:0280 Sakar 57379
|
||||
zc3xx 0ac8:0302 Z-star Vimicro zc0302
|
||||
vc032x 0ac8:0321 Vimicro generic vc0321
|
||||
vc032x 0ac8:0323 Vimicro Vc0323
|
||||
|
@ -247,6 +251,7 @@ zc3xx 0ac8:305b Z-star Vimicro zc0305b
|
|||
zc3xx 0ac8:307b Ldlc VC302+Ov7620
|
||||
vc032x 0ac8:c001 Sony embedded vimicro
|
||||
vc032x 0ac8:c002 Sony embedded vimicro
|
||||
vc032x 0ac8:c301 Samsung Q1 Ultra Premium
|
||||
spca508 0af9:0010 Hama USB Sightcam 100
|
||||
spca508 0af9:0011 Hama USB Sightcam 100
|
||||
sonixb 0c45:6001 Genius VideoCAM NB
|
||||
|
@ -284,6 +289,7 @@ sonixj 0c45:613a Microdia Sonix PC Camera
|
|||
sonixj 0c45:613b Surfer SN-206
|
||||
sonixj 0c45:613c Sonix Pccam168
|
||||
sonixj 0c45:6143 Sonix Pccam168
|
||||
sonixj 0c45:6148 Digitus DA-70811/ZSMC USB PC Camera ZS211/Microdia
|
||||
sn9c20x 0c45:6240 PC Camera (SN9C201 + MT9M001)
|
||||
sn9c20x 0c45:6242 PC Camera (SN9C201 + MT9M111)
|
||||
sn9c20x 0c45:6248 PC Camera (SN9C201 + OV9655)
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
Driver for I2C radios for the Silicon Labs Si4713 FM Radio Transmitters
|
||||
|
||||
Copyright (c) 2009 Nokia Corporation
|
||||
Contact: Eduardo Valentin <eduardo.valentin@nokia.com>
|
||||
|
||||
|
||||
Information about the Device
|
||||
============================
|
||||
This chip is a Silicon Labs product. It is a I2C device, currently on 0x63 address.
|
||||
Basically, it has transmission and signal noise level measurement features.
|
||||
|
||||
The Si4713 integrates transmit functions for FM broadcast stereo transmission.
|
||||
The chip also allows integrated receive power scanning to identify low signal
|
||||
power FM channels.
|
||||
|
||||
The chip is programmed using commands and responses. There are also several
|
||||
properties which can change the behavior of this chip.
|
||||
|
||||
Users must comply with local regulations on radio frequency (RF) transmission.
|
||||
|
||||
Device driver description
|
||||
=========================
|
||||
There are two modules to handle this device. One is a I2C device driver
|
||||
and the other is a platform driver.
|
||||
|
||||
The I2C device driver exports a v4l2-subdev interface to the kernel.
|
||||
All properties can also be accessed by v4l2 extended controls interface, by
|
||||
using the v4l2-subdev calls (g_ext_ctrls, s_ext_ctrls).
|
||||
|
||||
The platform device driver exports a v4l2 radio device interface to user land.
|
||||
So, it uses the I2C device driver as a sub device in order to send the user
|
||||
commands to the actual device. Basically it is a wrapper to the I2C device driver.
|
||||
|
||||
Applications can use v4l2 radio API to specify frequency of operation, mute state,
|
||||
etc. But mostly of its properties will be present in the extended controls.
|
||||
|
||||
When the v4l2 mute property is set to 1 (true), the driver will turn the chip off.
|
||||
|
||||
Properties description
|
||||
======================
|
||||
|
||||
The properties can be accessed using v4l2 extended controls.
|
||||
Here is an output from v4l2-ctl util:
|
||||
/ # v4l2-ctl -d /dev/radio0 --all -L
|
||||
Driver Info:
|
||||
Driver name : radio-si4713
|
||||
Card type : Silicon Labs Si4713 Modulator
|
||||
Bus info :
|
||||
Driver version: 0
|
||||
Capabilities : 0x00080800
|
||||
RDS Output
|
||||
Modulator
|
||||
Audio output: 0 (FM Modulator Audio Out)
|
||||
Frequency: 1408000 (88.000000 MHz)
|
||||
Video Standard = 0x00000000
|
||||
Modulator:
|
||||
Name : FM Modulator
|
||||
Capabilities : 62.5 Hz stereo rds
|
||||
Frequency range : 76.0 MHz - 108.0 MHz
|
||||
Subchannel modulation: stereo+rds
|
||||
|
||||
User Controls
|
||||
|
||||
mute (bool) : default=1 value=0
|
||||
|
||||
FM Radio Modulator Controls
|
||||
|
||||
rds_signal_deviation (int) : min=0 max=90000 step=10 default=200 value=200 flags=slider
|
||||
rds_program_id (int) : min=0 max=65535 step=1 default=0 value=0
|
||||
rds_program_type (int) : min=0 max=31 step=1 default=0 value=0
|
||||
rds_ps_name (str) : min=0 max=96 step=8 value='si4713 '
|
||||
rds_radio_text (str) : min=0 max=384 step=32 value=''
|
||||
audio_limiter_feature_enabled (bool) : default=1 value=1
|
||||
audio_limiter_release_time (int) : min=250 max=102390 step=50 default=5010 value=5010 flags=slider
|
||||
audio_limiter_deviation (int) : min=0 max=90000 step=10 default=66250 value=66250 flags=slider
|
||||
audio_compression_feature_enabl (bool) : default=1 value=1
|
||||
audio_compression_gain (int) : min=0 max=20 step=1 default=15 value=15 flags=slider
|
||||
audio_compression_threshold (int) : min=-40 max=0 step=1 default=-40 value=-40 flags=slider
|
||||
audio_compression_attack_time (int) : min=0 max=5000 step=500 default=0 value=0 flags=slider
|
||||
audio_compression_release_time (int) : min=100000 max=1000000 step=100000 default=1000000 value=1000000 flags=slider
|
||||
pilot_tone_feature_enabled (bool) : default=1 value=1
|
||||
pilot_tone_deviation (int) : min=0 max=90000 step=10 default=6750 value=6750 flags=slider
|
||||
pilot_tone_frequency (int) : min=0 max=19000 step=1 default=19000 value=19000 flags=slider
|
||||
pre_emphasis_settings (menu) : min=0 max=2 default=1 value=1
|
||||
tune_power_level (int) : min=0 max=120 step=1 default=88 value=88 flags=slider
|
||||
tune_antenna_capacitor (int) : min=0 max=191 step=1 default=0 value=110 flags=slider
|
||||
/ #
|
||||
|
||||
Here is a summary of them:
|
||||
|
||||
* Pilot is an audible tone sent by the device.
|
||||
|
||||
pilot_frequency - Configures the frequency of the stereo pilot tone.
|
||||
pilot_deviation - Configures pilot tone frequency deviation level.
|
||||
pilot_enabled - Enables or disables the pilot tone feature.
|
||||
|
||||
* The si4713 device is capable of applying audio compression to the transmitted signal.
|
||||
|
||||
acomp_enabled - Enables or disables the audio dynamic range control feature.
|
||||
acomp_gain - Sets the gain for audio dynamic range control.
|
||||
acomp_threshold - Sets the threshold level for audio dynamic range control.
|
||||
acomp_attack_time - Sets the attack time for audio dynamic range control.
|
||||
acomp_release_time - Sets the release time for audio dynamic range control.
|
||||
|
||||
* Limiter setups audio deviation limiter feature. Once a over deviation occurs,
|
||||
it is possible to adjust the front-end gain of the audio input and always
|
||||
prevent over deviation.
|
||||
|
||||
limiter_enabled - Enables or disables the limiter feature.
|
||||
limiter_deviation - Configures audio frequency deviation level.
|
||||
limiter_release_time - Sets the limiter release time.
|
||||
|
||||
* Tuning power
|
||||
|
||||
power_level - Sets the output power level for signal transmission.
|
||||
antenna_capacitor - This selects the value of antenna tuning capacitor manually
|
||||
or automatically if set to zero.
|
||||
|
||||
* RDS related
|
||||
|
||||
rds_ps_name - Sets the RDS ps name field for transmission.
|
||||
rds_radio_text - Sets the RDS radio text for transmission.
|
||||
rds_pi - Sets the RDS PI field for transmission.
|
||||
rds_pty - Sets the RDS PTY field for transmission.
|
||||
|
||||
* Region related
|
||||
|
||||
preemphasis - sets the preemphasis to be applied for transmission.
|
||||
|
||||
RNL
|
||||
===
|
||||
|
||||
This device also has an interface to measure received noise level. To do that, you should
|
||||
ioctl the device node. Here is an code of example:
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
struct si4713_rnl rnl;
|
||||
int fd = open("/dev/radio0", O_RDWR);
|
||||
int rval;
|
||||
|
||||
if (argc < 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
sscanf(argv[1], "%d", &rnl.frequency);
|
||||
|
||||
rval = ioctl(fd, SI4713_IOC_MEASURE_RNL, &rnl);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
|
||||
printf("received noise level: %d\n", rnl.rnl);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
The struct si4713_rnl and SI4713_IOC_MEASURE_RNL are defined under
|
||||
include/media/si4713.h.
|
||||
|
||||
Stereo/Mono and RDS subchannels
|
||||
===============================
|
||||
|
||||
The device can also be configured using the available sub channels for
|
||||
transmission. To do that use S/G_MODULATOR ioctl and configure txsubchans properly.
|
||||
Refer to v4l2-spec for proper use of this ioctl.
|
||||
|
||||
Testing
|
||||
=======
|
||||
Testing is usually done with v4l2-ctl utility for managing FM tuner cards.
|
||||
The tool can be found in v4l-dvb repository under v4l2-apps/util directory.
|
||||
|
||||
Example for setting rds ps name:
|
||||
# v4l2-ctl -d /dev/radio0 --set-ctrl=rds_ps_name="Dummy"
|
||||
|
|
@ -58,13 +58,24 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
|
|||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
|
||||
int ir_type, IR_KEYTAB_TYPE *ir_codes)
|
||||
int ir_type, struct ir_scancode_table *ir_codes)
|
||||
{
|
||||
int i;
|
||||
|
||||
ir->ir_type = ir_type;
|
||||
|
||||
memset(ir->ir_codes, sizeof(ir->ir_codes), 0);
|
||||
|
||||
/*
|
||||
* FIXME: This is a temporary workaround to use the new IR tables
|
||||
* with the old approach. Later patches will replace this to a
|
||||
* proper method
|
||||
*/
|
||||
|
||||
if (ir_codes)
|
||||
memcpy(ir->ir_codes, ir_codes, sizeof(ir->ir_codes));
|
||||
for (i = 0; i < ir_codes->size; i++)
|
||||
if (ir_codes->scan[i].scancode < IR_KEYTAB_SIZE)
|
||||
ir->ir_codes[ir_codes->scan[i].scancode] = ir_codes->scan[i].keycode;
|
||||
|
||||
dev->keycode = ir->ir_codes;
|
||||
dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -27,7 +27,7 @@ module_param_named(debug, tda18271_debug, int, 0644);
|
|||
MODULE_PARM_DESC(debug, "set debug level "
|
||||
"(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
|
||||
|
||||
static int tda18271_cal_on_startup;
|
||||
static int tda18271_cal_on_startup = -1;
|
||||
module_param_named(cal, tda18271_cal_on_startup, int, 0644);
|
||||
MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
|
||||
|
||||
|
@ -1192,10 +1192,25 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
|
|||
case 0:
|
||||
goto fail;
|
||||
case 1:
|
||||
{
|
||||
/* new tuner instance */
|
||||
int rf_cal_on_startup;
|
||||
|
||||
priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
|
||||
priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
|
||||
priv->config = (cfg) ? cfg->config : 0;
|
||||
|
||||
/* tda18271_cal_on_startup == -1 when cal
|
||||
* module option is unset */
|
||||
if (tda18271_cal_on_startup == -1) {
|
||||
/* honor attach-time configuration */
|
||||
rf_cal_on_startup =
|
||||
((cfg) && (cfg->rf_cal_on_startup)) ? 1 : 0;
|
||||
} else {
|
||||
/* module option overrides attach configuration */
|
||||
rf_cal_on_startup = tda18271_cal_on_startup;
|
||||
}
|
||||
|
||||
priv->cal_initialized = false;
|
||||
mutex_init(&priv->lock);
|
||||
|
||||
|
@ -1213,11 +1228,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
|
|||
mutex_lock(&priv->lock);
|
||||
tda18271_init_regs(fe);
|
||||
|
||||
if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2))
|
||||
if ((rf_cal_on_startup) && (priv->id == TDA18271HDC2))
|
||||
tda18271c2_rf_cal_init(fe);
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* existing tuner instance */
|
||||
fe->tuner_priv = priv;
|
||||
|
|
|
@ -137,17 +137,17 @@ extern int tda18271_debug;
|
|||
#define tda_printk(kern, fmt, arg...) \
|
||||
printk(kern "%s: " fmt, __func__, ##arg)
|
||||
|
||||
#define dprintk(kern, lvl, fmt, arg...) do {\
|
||||
#define tda_dprintk(lvl, fmt, arg...) do {\
|
||||
if (tda18271_debug & lvl) \
|
||||
tda_printk(kern, fmt, ##arg); } while (0)
|
||||
tda_printk(KERN_DEBUG, fmt, ##arg); } while (0)
|
||||
|
||||
#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg)
|
||||
#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING, fmt, ##arg)
|
||||
#define tda_err(fmt, arg...) tda_printk(KERN_ERR, fmt, ##arg)
|
||||
#define tda_dbg(fmt, arg...) dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg)
|
||||
#define tda_map(fmt, arg...) dprintk(KERN_DEBUG, DBG_MAP, fmt, ##arg)
|
||||
#define tda_reg(fmt, arg...) dprintk(KERN_DEBUG, DBG_REG, fmt, ##arg)
|
||||
#define tda_cal(fmt, arg...) dprintk(KERN_DEBUG, DBG_CAL, fmt, ##arg)
|
||||
#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg)
|
||||
#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING, fmt, ##arg)
|
||||
#define tda_err(fmt, arg...) tda_printk(KERN_ERR, fmt, ##arg)
|
||||
#define tda_dbg(fmt, arg...) tda_dprintk(DBG_INFO, fmt, ##arg)
|
||||
#define tda_map(fmt, arg...) tda_dprintk(DBG_MAP, fmt, ##arg)
|
||||
#define tda_reg(fmt, arg...) tda_dprintk(DBG_REG, fmt, ##arg)
|
||||
#define tda_cal(fmt, arg...) tda_dprintk(DBG_CAL, fmt, ##arg)
|
||||
|
||||
#define tda_fail(ret) \
|
||||
({ \
|
||||
|
|
|
@ -77,6 +77,9 @@ struct tda18271_config {
|
|||
/* use i2c gate provided by analog or digital demod */
|
||||
enum tda18271_i2c_gate gate;
|
||||
|
||||
/* force rf tracking filter calibration on startup */
|
||||
unsigned int rf_cal_on_startup:1;
|
||||
|
||||
/* some i2c providers cant write all 39 registers at once */
|
||||
unsigned int small_i2c:1;
|
||||
|
||||
|
|
|
@ -144,6 +144,8 @@ static inline int tuner_stereo(const int type, const int status)
|
|||
case TUNER_LG_NTSC_TAPE:
|
||||
case TUNER_TCL_MF02GIP_5N:
|
||||
return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
|
||||
case TUNER_PHILIPS_FM1216MK5:
|
||||
return status | TUNER_STEREO;
|
||||
default:
|
||||
return status & TUNER_STEREO;
|
||||
}
|
||||
|
@ -508,6 +510,10 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
|
|||
case TUNER_TCL_MF02GIP_5N:
|
||||
buffer[3] = 0x19;
|
||||
break;
|
||||
case TUNER_PHILIPS_FM1216MK5:
|
||||
buffer[2] = 0x88;
|
||||
buffer[3] = 0x09;
|
||||
break;
|
||||
case TUNER_TNF_5335MF:
|
||||
buffer[3] = 0x11;
|
||||
break;
|
||||
|
|
|
@ -1301,6 +1301,25 @@ static struct tuner_params tuner_fq1216lme_mk3_params[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */
|
||||
|
||||
static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = {
|
||||
/* The datasheet specified channel ranges and the bandswitch byte */
|
||||
/* The control byte value of 0x8e is just a guess */
|
||||
{ 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels 2 - B */
|
||||
{ 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels C - W+11 */
|
||||
{ 16 * 999.99 , 0x8e, 0x08, }, /* Channels W+12 - 69 */
|
||||
};
|
||||
|
||||
static struct tuner_params tuner_partsnic_pti_5nf05_params[] = {
|
||||
{
|
||||
.type = TUNER_PARAM_TYPE_NTSC,
|
||||
.ranges = tuner_partsnic_pti_5nf05_ranges,
|
||||
.count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges),
|
||||
.cb_first_if_lower_freq = 1, /* not specified but safe to do */
|
||||
},
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
struct tunertype tuners[] = {
|
||||
|
@ -1753,6 +1772,12 @@ struct tunertype tuners[] = {
|
|||
.params = tuner_fq1216lme_mk3_params,
|
||||
.count = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
|
||||
},
|
||||
|
||||
[TUNER_PARTSNIC_PTI_5NF05] = {
|
||||
.name = "Partsnic (Daewoo) PTI-5NF05",
|
||||
.params = tuner_partsnic_pti_5nf05_params,
|
||||
.count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params),
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL(tuners);
|
||||
|
||||
|
|
|
@ -2,6 +2,19 @@
|
|||
# DVB device configuration
|
||||
#
|
||||
|
||||
config DVB_MAX_ADAPTERS
|
||||
int "maximum number of DVB/ATSC adapters"
|
||||
depends on DVB_CORE
|
||||
default 8
|
||||
range 1 255
|
||||
help
|
||||
Maximum number of DVB/ATSC adapters. Increasing this number
|
||||
increases the memory consumption of the DVB subsystem even
|
||||
if a much lower number of DVB/ATSC adapters is present.
|
||||
Only values in the range 4-32 are tested.
|
||||
|
||||
If you are unsure about this, use the default value 8
|
||||
|
||||
config DVB_DYNAMIC_MINORS
|
||||
bool "Dynamic DVB minor allocation"
|
||||
depends on DVB_CORE
|
||||
|
|
|
@ -66,7 +66,7 @@ static int flexcop_sleep(struct dvb_frontend* fe)
|
|||
#endif
|
||||
|
||||
/* SkyStar2 DVB-S rev 2.3 */
|
||||
#if FE_SUPPORTED(MT312)
|
||||
#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
|
||||
static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
|
||||
|
@ -155,55 +155,34 @@ static struct mt312_config skystar23_samsung_tbdu18132_config = {
|
|||
.demod_address = 0x0e,
|
||||
};
|
||||
|
||||
static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
u8 buf[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf,
|
||||
.len = sizeof(buf) };
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
div = (params->frequency + (125/2)) / 125;
|
||||
|
||||
buf[0] = (div >> 8) & 0x7f;
|
||||
buf[1] = (div >> 0) & 0xff;
|
||||
buf[2] = 0x84 | ((div >> 10) & 0x60);
|
||||
buf[3] = 0x80;
|
||||
|
||||
if (params->frequency < 1550000)
|
||||
buf[3] |= 0x02;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skystar2_rev23_attach(struct flexcop_device *fc,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct dvb_frontend_ops *ops;
|
||||
|
||||
fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
|
||||
if (fc->fe != NULL) {
|
||||
struct dvb_frontend_ops *ops = &fc->fe->ops;
|
||||
ops->tuner_ops.set_params =
|
||||
skystar23_samsung_tbdu18132_tuner_set_params;
|
||||
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
|
||||
ops->diseqc_send_burst = flexcop_diseqc_send_burst;
|
||||
ops->set_tone = flexcop_set_tone;
|
||||
ops->set_voltage = flexcop_set_voltage;
|
||||
fc->fe_sleep = ops->sleep;
|
||||
ops->sleep = flexcop_sleep;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
|
||||
DVB_PLL_SAMSUNG_TBDU18132))
|
||||
return 0;
|
||||
|
||||
ops = &fc->fe->ops;
|
||||
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
|
||||
ops->diseqc_send_burst = flexcop_diseqc_send_burst;
|
||||
ops->set_tone = flexcop_set_tone;
|
||||
ops->set_voltage = flexcop_set_voltage;
|
||||
fc->fe_sleep = ops->sleep;
|
||||
ops->sleep = flexcop_sleep;
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
#define skystar2_rev23_attach NULL
|
||||
#endif
|
||||
|
||||
/* SkyStar2 DVB-S rev 2.6 */
|
||||
#if FE_SUPPORTED(STV0299)
|
||||
#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
|
||||
static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
|
||||
u32 srate, u32 ratio)
|
||||
{
|
||||
|
@ -232,31 +211,6 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
u8 buf[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = {
|
||||
.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
div = params->frequency / 125;
|
||||
|
||||
buf[0] = (div >> 8) & 0x7f;
|
||||
buf[1] = div & 0xff;
|
||||
buf[2] = 0x84; /* 0xC4 */
|
||||
buf[3] = 0x08;
|
||||
|
||||
if (params->frequency < 1500000)
|
||||
buf[3] |= 0x10;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 samsung_tbmu24112_inittab[] = {
|
||||
0x01, 0x15,
|
||||
0x02, 0x30,
|
||||
|
@ -318,15 +272,18 @@ static int skystar2_rev26_attach(struct flexcop_device *fc,
|
|||
struct i2c_adapter *i2c)
|
||||
{
|
||||
fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
|
||||
if (fc->fe != NULL) {
|
||||
struct dvb_frontend_ops *ops = &fc->fe->ops;
|
||||
ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
|
||||
ops->set_voltage = flexcop_set_voltage;
|
||||
fc->fe_sleep = ops->sleep;
|
||||
ops->sleep = flexcop_sleep;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
|
||||
DVB_PLL_SAMSUNG_TBMU24112))
|
||||
return 0;
|
||||
|
||||
fc->fe->ops.set_voltage = flexcop_set_voltage;
|
||||
fc->fe_sleep = fc->fe->ops.sleep;
|
||||
fc->fe->ops.sleep = flexcop_sleep;
|
||||
return 1;
|
||||
|
||||
}
|
||||
#else
|
||||
#define skystar2_rev26_attach NULL
|
||||
|
@ -421,7 +378,7 @@ static int skystar2_rev28_attach(struct flexcop_device *fc,
|
|||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
|
||||
i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
|
||||
if (!i2c_tuner)
|
||||
return 0;
|
||||
|
||||
|
@ -449,7 +406,7 @@ static int skystar2_rev28_attach(struct flexcop_device *fc,
|
|||
#endif
|
||||
|
||||
/* AirStar DVB-T */
|
||||
#if FE_SUPPORTED(MT352)
|
||||
#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
|
||||
static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
|
||||
{
|
||||
static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
|
||||
|
@ -467,32 +424,6 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
|
||||
{
|
||||
u32 div;
|
||||
unsigned char bs = 0;
|
||||
|
||||
if (buf_len < 5)
|
||||
return -EINVAL;
|
||||
|
||||
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
|
||||
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
|
||||
if (params->frequency >= 48000000 && params->frequency <= 154000000) \
|
||||
bs = 0x09;
|
||||
if (params->frequency >= 161000000 && params->frequency <= 439000000) \
|
||||
bs = 0x0a;
|
||||
if (params->frequency >= 447000000 && params->frequency <= 863000000) \
|
||||
bs = 0x08;
|
||||
|
||||
pllbuf[0] = 0x61;
|
||||
pllbuf[1] = div >> 8;
|
||||
pllbuf[2] = div & 0xff;
|
||||
pllbuf[3] = 0xcc;
|
||||
pllbuf[4] = bs;
|
||||
return 5;
|
||||
}
|
||||
|
||||
static struct mt352_config samsung_tdtc9251dh0_config = {
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = samsung_tdtc9251dh0_demod_init,
|
||||
|
@ -502,11 +433,11 @@ static int airstar_dvbt_attach(struct flexcop_device *fc,
|
|||
struct i2c_adapter *i2c)
|
||||
{
|
||||
fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
|
||||
if (fc->fe != NULL) {
|
||||
fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
if (!fc->fe)
|
||||
return 0;
|
||||
|
||||
return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
|
||||
DVB_PLL_SAMSUNG_TDTC9251DH0);
|
||||
}
|
||||
#else
|
||||
#define airstar_dvbt_attach NULL
|
||||
|
@ -580,54 +511,7 @@ static int airstar_atsc3_attach(struct flexcop_device *fc,
|
|||
#endif
|
||||
|
||||
/* CableStar2 DVB-C */
|
||||
#if FE_SUPPORTED(STV0297)
|
||||
static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
|
||||
struct dvb_frontend_parameters *fep)
|
||||
{
|
||||
struct flexcop_device *fc = fe->dvb->priv;
|
||||
u8 buf[4];
|
||||
u16 div;
|
||||
int ret;
|
||||
|
||||
/* 62.5 kHz * 10 */
|
||||
#define REF_FREQ 625
|
||||
#define FREQ_OFFSET 36125
|
||||
|
||||
div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
|
||||
/* 4 MHz = 4000 KHz */
|
||||
|
||||
buf[0] = (u8)( div >> 8) & 0x7f;
|
||||
buf[1] = (u8) div & 0xff;
|
||||
|
||||
/* F(osc) = N * Reference Freq. (62.5 kHz)
|
||||
* byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
|
||||
* byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
|
||||
* byte 4 : 1 * * AGD R3 R2 R1 R0
|
||||
* byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
|
||||
* AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
|
||||
buf[2] = 0x95;
|
||||
|
||||
/* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
|
||||
* 47 - 153 0 * 0 0 0 0 0 1 0x01
|
||||
* 153 - 430 0 * 0 0 0 0 1 0 0x02
|
||||
* 430 - 822 0 * 0 0 1 0 0 0 0x08
|
||||
* 822 - 862 1 * 0 0 1 0 0 0 0x88 */
|
||||
|
||||
if (fep->frequency <= 153000000) buf[3] = 0x01;
|
||||
else if (fep->frequency <= 430000000) buf[3] = 0x02;
|
||||
else if (fep->frequency <= 822000000) buf[3] = 0x08;
|
||||
else buf[3] = 0x88;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
|
||||
buf[0], buf[1], buf[2], buf[3]);
|
||||
ret = fc->i2c_request(&fc->fc_i2c_adap[2],
|
||||
FC_WRITE, 0x61, buf[0], &buf[1], 3);
|
||||
deb_tuner("tuner write returned: %d\n",ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
|
||||
static u8 alps_tdee4_stv0297_inittab[] = {
|
||||
0x80, 0x01,
|
||||
0x80, 0x00,
|
||||
|
@ -711,13 +595,25 @@ static int cablestar2_attach(struct flexcop_device *fc,
|
|||
{
|
||||
fc->fc_i2c_adap[0].no_base_addr = 1;
|
||||
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
|
||||
if (!fc->fe) {
|
||||
/* Reset for next frontend to try */
|
||||
fc->fc_i2c_adap[0].no_base_addr = 0;
|
||||
return 0;
|
||||
}
|
||||
fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
|
||||
if (!fc->fe)
|
||||
goto fail;
|
||||
|
||||
/* This tuner doesn't use the stv0297's I2C gate, but instead the
|
||||
* tuner is connected to a different flexcop I2C adapter. */
|
||||
if (fc->fe->ops.i2c_gate_ctrl)
|
||||
fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
|
||||
fc->fe->ops.i2c_gate_ctrl = NULL;
|
||||
|
||||
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
|
||||
&fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
|
||||
goto fail;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
/* Reset for next frontend to try */
|
||||
fc->fc_i2c_adap[0].no_base_addr = 0;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define cablestar2_attach NULL
|
||||
|
|
|
@ -1059,7 +1059,7 @@ static int dst_get_tuner_info(struct dst_state *state)
|
|||
dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
|
||||
}
|
||||
if (state->board_info[0] == 0xbc) {
|
||||
if (state->type_flags != DST_TYPE_IS_ATSC)
|
||||
if (state->dst_type != DST_TYPE_IS_ATSC)
|
||||
state->type_flags |= DST_TYPE_HAS_TS188;
|
||||
else
|
||||
state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
|
||||
|
|
|
@ -44,6 +44,14 @@
|
|||
#include "cx24116.h"
|
||||
#include "z0194a.h"
|
||||
|
||||
#define UNSET (-1U)
|
||||
|
||||
#define DM1105_BOARD_NOAUTO UNSET
|
||||
#define DM1105_BOARD_UNKNOWN 0
|
||||
#define DM1105_BOARD_DVBWORLD_2002 1
|
||||
#define DM1105_BOARD_DVBWORLD_2004 2
|
||||
#define DM1105_BOARD_AXESS_DM05 3
|
||||
|
||||
/* ----------------------------------------------- */
|
||||
/*
|
||||
* PCI ID's
|
||||
|
@ -153,20 +161,105 @@
|
|||
|
||||
/* GPIO's for LNB power control */
|
||||
#define DM1105_LNB_MASK 0x00000000
|
||||
#define DM1105_LNB_OFF 0x00020000
|
||||
#define DM1105_LNB_13V 0x00010100
|
||||
#define DM1105_LNB_18V 0x00000100
|
||||
|
||||
/* GPIO's for LNB power control for Axess DM05 */
|
||||
#define DM05_LNB_MASK 0x00000000
|
||||
#define DM05_LNB_OFF 0x00020000/* actually 13v */
|
||||
#define DM05_LNB_13V 0x00020000
|
||||
#define DM05_LNB_18V 0x00030000
|
||||
|
||||
static unsigned int card[] = {[0 ... 3] = UNSET };
|
||||
module_param_array(card, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(card, "card type");
|
||||
|
||||
static int ir_debug;
|
||||
module_param(ir_debug, int, 0644);
|
||||
MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
|
||||
|
||||
static unsigned int dm1105_devcount;
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
struct dm1105_board {
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct dm1105_subid {
|
||||
u16 subvendor;
|
||||
u16 subdevice;
|
||||
u32 card;
|
||||
};
|
||||
|
||||
static const struct dm1105_board dm1105_boards[] = {
|
||||
[DM1105_BOARD_UNKNOWN] = {
|
||||
.name = "UNKNOWN/GENERIC",
|
||||
},
|
||||
[DM1105_BOARD_DVBWORLD_2002] = {
|
||||
.name = "DVBWorld PCI 2002",
|
||||
},
|
||||
[DM1105_BOARD_DVBWORLD_2004] = {
|
||||
.name = "DVBWorld PCI 2004",
|
||||
},
|
||||
[DM1105_BOARD_AXESS_DM05] = {
|
||||
.name = "Axess/EasyTv DM05",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct dm1105_subid dm1105_subids[] = {
|
||||
{
|
||||
.subvendor = 0x0000,
|
||||
.subdevice = 0x2002,
|
||||
.card = DM1105_BOARD_DVBWORLD_2002,
|
||||
}, {
|
||||
.subvendor = 0x0001,
|
||||
.subdevice = 0x2002,
|
||||
.card = DM1105_BOARD_DVBWORLD_2002,
|
||||
}, {
|
||||
.subvendor = 0x0000,
|
||||
.subdevice = 0x2004,
|
||||
.card = DM1105_BOARD_DVBWORLD_2004,
|
||||
}, {
|
||||
.subvendor = 0x0001,
|
||||
.subdevice = 0x2004,
|
||||
.card = DM1105_BOARD_DVBWORLD_2004,
|
||||
}, {
|
||||
.subvendor = 0x195d,
|
||||
.subdevice = 0x1105,
|
||||
.card = DM1105_BOARD_AXESS_DM05,
|
||||
},
|
||||
};
|
||||
|
||||
static void dm1105_card_list(struct pci_dev *pci)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (0 == pci->subsystem_vendor &&
|
||||
0 == pci->subsystem_device) {
|
||||
printk(KERN_ERR
|
||||
"dm1105: Your board has no valid PCI Subsystem ID\n"
|
||||
"dm1105: and thus can't be autodetected\n"
|
||||
"dm1105: Please pass card=<n> insmod option to\n"
|
||||
"dm1105: workaround that. Redirect complaints to\n"
|
||||
"dm1105: the vendor of the TV card. Best regards,\n"
|
||||
"dm1105: -- tux\n");
|
||||
} else {
|
||||
printk(KERN_ERR
|
||||
"dm1105: Your board isn't known (yet) to the driver.\n"
|
||||
"dm1105: You can try to pick one of the existing\n"
|
||||
"dm1105: card configs via card=<n> insmod option.\n"
|
||||
"dm1105: Updating to the latest version might help\n"
|
||||
"dm1105: as well.\n");
|
||||
}
|
||||
printk(KERN_ERR "Here is a list of valid choices for the card=<n> "
|
||||
"insmod option:\n");
|
||||
for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++)
|
||||
printk(KERN_ERR "dm1105: card=%d -> %s\n",
|
||||
i, dm1105_boards[i].name);
|
||||
}
|
||||
|
||||
/* infrared remote control */
|
||||
struct infrared {
|
||||
struct input_dev *input_dev;
|
||||
|
@ -193,6 +286,8 @@ struct dm1105dvb {
|
|||
struct dvb_frontend *fe;
|
||||
struct dvb_net dvbnet;
|
||||
unsigned int full_ts_users;
|
||||
unsigned int boardnr;
|
||||
int nr;
|
||||
|
||||
/* i2c */
|
||||
struct i2c_adapter i2c_adap;
|
||||
|
@ -211,7 +306,6 @@ struct dm1105dvb {
|
|||
unsigned int PacketErrorCount;
|
||||
unsigned int dmarst;
|
||||
spinlock_t lock;
|
||||
|
||||
};
|
||||
|
||||
#define dm_io_mem(reg) ((unsigned long)(&dm1105dvb->io_mem[reg]))
|
||||
|
@ -326,16 +420,20 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
|
|||
static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
|
||||
u32 lnb_mask, lnb_13v, lnb_18v;
|
||||
u32 lnb_mask, lnb_13v, lnb_18v, lnb_off;
|
||||
|
||||
switch (dm1105dvb->pdev->subsystem_device) {
|
||||
case PCI_DEVICE_ID_DM05:
|
||||
switch (dm1105dvb->boardnr) {
|
||||
case DM1105_BOARD_AXESS_DM05:
|
||||
lnb_mask = DM05_LNB_MASK;
|
||||
lnb_off = DM05_LNB_OFF;
|
||||
lnb_13v = DM05_LNB_13V;
|
||||
lnb_18v = DM05_LNB_18V;
|
||||
break;
|
||||
case DM1105_BOARD_DVBWORLD_2002:
|
||||
case DM1105_BOARD_DVBWORLD_2004:
|
||||
default:
|
||||
lnb_mask = DM1105_LNB_MASK;
|
||||
lnb_off = DM1105_LNB_OFF;
|
||||
lnb_13v = DM1105_LNB_13V;
|
||||
lnb_18v = DM1105_LNB_18V;
|
||||
}
|
||||
|
@ -343,8 +441,10 @@ static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volta
|
|||
outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
|
||||
if (voltage == SEC_VOLTAGE_18)
|
||||
outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
|
||||
else
|
||||
else if (voltage == SEC_VOLTAGE_13)
|
||||
outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
|
||||
else
|
||||
outl(lnb_off, dm_io_mem(DM1105_GPIOVAL));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -477,7 +577,7 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
|
|||
int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
IR_KEYTAB_TYPE *ir_codes = ir_codes_dm1105_nec;
|
||||
struct ir_scancode_table *ir_codes = &ir_codes_dm1105_nec_table;
|
||||
int ir_type = IR_TYPE_OTHER;
|
||||
int err = -ENOMEM;
|
||||
|
||||
|
@ -589,8 +689,8 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
|
|||
{
|
||||
int ret;
|
||||
|
||||
switch (dm1105dvb->pdev->subsystem_device) {
|
||||
case PCI_DEVICE_ID_DW2004:
|
||||
switch (dm1105dvb->boardnr) {
|
||||
case DM1105_BOARD_DVBWORLD_2004:
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
cx24116_attach, &serit_sp2633_config,
|
||||
&dm1105dvb->i2c_adap);
|
||||
|
@ -598,6 +698,8 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
|
|||
dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
|
||||
|
||||
break;
|
||||
case DM1105_BOARD_DVBWORLD_2002:
|
||||
case DM1105_BOARD_AXESS_DM05:
|
||||
default:
|
||||
dm1105dvb->fe = dvb_attach(
|
||||
stv0299_attach, &sharp_z0194a_config,
|
||||
|
@ -676,11 +778,31 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
|
|||
struct dvb_demux *dvbdemux;
|
||||
struct dmx_demux *dmx;
|
||||
int ret = -ENOMEM;
|
||||
int i;
|
||||
|
||||
dm1105dvb = kzalloc(sizeof(struct dm1105dvb), GFP_KERNEL);
|
||||
if (!dm1105dvb)
|
||||
return -ENOMEM;
|
||||
|
||||
/* board config */
|
||||
dm1105dvb->nr = dm1105_devcount;
|
||||
dm1105dvb->boardnr = UNSET;
|
||||
if (card[dm1105dvb->nr] < ARRAY_SIZE(dm1105_boards))
|
||||
dm1105dvb->boardnr = card[dm1105dvb->nr];
|
||||
for (i = 0; UNSET == dm1105dvb->boardnr &&
|
||||
i < ARRAY_SIZE(dm1105_subids); i++)
|
||||
if (pdev->subsystem_vendor ==
|
||||
dm1105_subids[i].subvendor &&
|
||||
pdev->subsystem_device ==
|
||||
dm1105_subids[i].subdevice)
|
||||
dm1105dvb->boardnr = dm1105_subids[i].card;
|
||||
|
||||
if (UNSET == dm1105dvb->boardnr) {
|
||||
dm1105dvb->boardnr = DM1105_BOARD_UNKNOWN;
|
||||
dm1105_card_list(pdev);
|
||||
}
|
||||
|
||||
dm1105_devcount++;
|
||||
dm1105dvb->pdev = pdev;
|
||||
dm1105dvb->buffer_size = 5 * DM1105_DMA_BYTES;
|
||||
dm1105dvb->PacketErrorCount = 0;
|
||||
|
@ -853,6 +975,7 @@ static void __devexit dm1105_remove(struct pci_dev *pdev)
|
|||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
dm1105_devcount--;
|
||||
kfree(dm1105dvb);
|
||||
}
|
||||
|
||||
|
@ -861,17 +984,12 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = {
|
|||
.vendor = PCI_VENDOR_ID_TRIGEM,
|
||||
.device = PCI_DEVICE_ID_DM1105,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_DEVICE_ID_DW2002,
|
||||
}, {
|
||||
.vendor = PCI_VENDOR_ID_TRIGEM,
|
||||
.device = PCI_DEVICE_ID_DM1105,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_DEVICE_ID_DW2004,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
}, {
|
||||
.vendor = PCI_VENDOR_ID_AXESS,
|
||||
.device = PCI_DEVICE_ID_DM05,
|
||||
.subvendor = PCI_VENDOR_ID_AXESS,
|
||||
.subdevice = PCI_DEVICE_ID_DM05,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
}, {
|
||||
/* empty */
|
||||
},
|
||||
|
|
|
@ -430,6 +430,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
|
|||
/* stop feed but only mark the specified filter as stopped (state set) */
|
||||
static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
|
||||
{
|
||||
struct dmxdev_feed *feed;
|
||||
|
||||
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
|
||||
|
||||
switch (dmxdevfilter->type) {
|
||||
|
@ -438,7 +440,8 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
|
|||
dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
|
||||
break;
|
||||
case DMXDEV_TYPE_PES:
|
||||
dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts);
|
||||
list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
|
||||
feed->ts->stop_filtering(feed->ts);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -449,13 +452,23 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
|
|||
/* start feed associated with the specified filter */
|
||||
static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
|
||||
{
|
||||
struct dmxdev_feed *feed;
|
||||
int ret;
|
||||
|
||||
dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
|
||||
|
||||
switch (filter->type) {
|
||||
case DMXDEV_TYPE_SEC:
|
||||
return filter->feed.sec->start_filtering(filter->feed.sec);
|
||||
case DMXDEV_TYPE_PES:
|
||||
return filter->feed.ts->start_filtering(filter->feed.ts);
|
||||
list_for_each_entry(feed, &filter->feed.ts, next) {
|
||||
ret = feed->ts->start_filtering(feed->ts);
|
||||
if (ret < 0) {
|
||||
dvb_dmxdev_feed_stop(filter);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -487,6 +500,9 @@ static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
|
|||
|
||||
static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
|
||||
{
|
||||
struct dmxdev_feed *feed;
|
||||
struct dmx_demux *demux;
|
||||
|
||||
if (dmxdevfilter->state < DMXDEV_STATE_GO)
|
||||
return 0;
|
||||
|
||||
|
@ -503,13 +519,12 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
|
|||
dmxdevfilter->feed.sec = NULL;
|
||||
break;
|
||||
case DMXDEV_TYPE_PES:
|
||||
if (!dmxdevfilter->feed.ts)
|
||||
break;
|
||||
dvb_dmxdev_feed_stop(dmxdevfilter);
|
||||
dmxdevfilter->dev->demux->
|
||||
release_ts_feed(dmxdevfilter->dev->demux,
|
||||
dmxdevfilter->feed.ts);
|
||||
dmxdevfilter->feed.ts = NULL;
|
||||
demux = dmxdevfilter->dev->demux;
|
||||
list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
|
||||
demux->release_ts_feed(demux, feed->ts);
|
||||
feed->ts = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
|
||||
|
@ -521,19 +536,88 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
|
||||
{
|
||||
struct dmxdev_feed *feed, *tmp;
|
||||
|
||||
/* delete all PIDs */
|
||||
list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
|
||||
list_del(&feed->next);
|
||||
kfree(feed);
|
||||
}
|
||||
|
||||
BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
|
||||
}
|
||||
|
||||
static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
|
||||
{
|
||||
if (dmxdevfilter->state < DMXDEV_STATE_SET)
|
||||
return 0;
|
||||
|
||||
if (dmxdevfilter->type == DMXDEV_TYPE_PES)
|
||||
dvb_dmxdev_delete_pids(dmxdevfilter);
|
||||
|
||||
dmxdevfilter->type = DMXDEV_TYPE_NONE;
|
||||
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
|
||||
struct dmxdev_filter *filter,
|
||||
struct dmxdev_feed *feed)
|
||||
{
|
||||
struct timespec timeout = { 0 };
|
||||
struct dmx_pes_filter_params *para = &filter->params.pes;
|
||||
dmx_output_t otype;
|
||||
int ret;
|
||||
int ts_type;
|
||||
enum dmx_ts_pes ts_pes;
|
||||
struct dmx_ts_feed *tsfeed;
|
||||
|
||||
feed->ts = NULL;
|
||||
otype = para->output;
|
||||
|
||||
ts_pes = (enum dmx_ts_pes)para->pes_type;
|
||||
|
||||
if (ts_pes < DMX_PES_OTHER)
|
||||
ts_type = TS_DECODER;
|
||||
else
|
||||
ts_type = 0;
|
||||
|
||||
if (otype == DMX_OUT_TS_TAP)
|
||||
ts_type |= TS_PACKET;
|
||||
else if (otype == DMX_OUT_TSDEMUX_TAP)
|
||||
ts_type |= TS_PACKET | TS_DEMUX;
|
||||
else if (otype == DMX_OUT_TAP)
|
||||
ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
|
||||
|
||||
ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
|
||||
dvb_dmxdev_ts_callback);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tsfeed = feed->ts;
|
||||
tsfeed->priv = filter;
|
||||
|
||||
ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
|
||||
if (ret < 0) {
|
||||
dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = tsfeed->start_filtering(tsfeed);
|
||||
if (ret < 0) {
|
||||
dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
|
||||
{
|
||||
struct dmxdev *dmxdev = filter->dev;
|
||||
struct dmxdev_feed *feed;
|
||||
void *mem;
|
||||
int ret, i;
|
||||
|
||||
|
@ -631,56 +715,14 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
|
|||
break;
|
||||
}
|
||||
case DMXDEV_TYPE_PES:
|
||||
{
|
||||
struct timespec timeout = { 0 };
|
||||
struct dmx_pes_filter_params *para = &filter->params.pes;
|
||||
dmx_output_t otype;
|
||||
int ts_type;
|
||||
enum dmx_ts_pes ts_pes;
|
||||
struct dmx_ts_feed **tsfeed = &filter->feed.ts;
|
||||
|
||||
filter->feed.ts = NULL;
|
||||
otype = para->output;
|
||||
|
||||
ts_pes = (enum dmx_ts_pes)para->pes_type;
|
||||
|
||||
if (ts_pes < DMX_PES_OTHER)
|
||||
ts_type = TS_DECODER;
|
||||
else
|
||||
ts_type = 0;
|
||||
|
||||
if (otype == DMX_OUT_TS_TAP)
|
||||
ts_type |= TS_PACKET;
|
||||
else if (otype == DMX_OUT_TSDEMUX_TAP)
|
||||
ts_type |= TS_PACKET | TS_DEMUX;
|
||||
else if (otype == DMX_OUT_TAP)
|
||||
ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
|
||||
|
||||
ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
|
||||
tsfeed,
|
||||
dvb_dmxdev_ts_callback);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
(*tsfeed)->priv = filter;
|
||||
|
||||
ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
|
||||
32768, timeout);
|
||||
if (ret < 0) {
|
||||
dmxdev->demux->release_ts_feed(dmxdev->demux,
|
||||
*tsfeed);
|
||||
return ret;
|
||||
list_for_each_entry(feed, &filter->feed.ts, next) {
|
||||
ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
|
||||
if (ret < 0) {
|
||||
dvb_dmxdev_filter_stop(filter);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = filter->feed.ts->start_filtering(filter->feed.ts);
|
||||
if (ret < 0) {
|
||||
dmxdev->demux->release_ts_feed(dmxdev->demux,
|
||||
*tsfeed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -718,7 +760,7 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
|
|||
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
|
||||
dmxdevfilter->type = DMXDEV_TYPE_NONE;
|
||||
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
|
||||
dmxdevfilter->feed.ts = NULL;
|
||||
INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
|
||||
init_timer(&dmxdevfilter->timer);
|
||||
|
||||
dvbdev->users++;
|
||||
|
@ -760,6 +802,55 @@ static inline void invert_mode(dmx_filter_t *filter)
|
|||
filter->mode[i] ^= 0xff;
|
||||
}
|
||||
|
||||
static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
|
||||
struct dmxdev_filter *filter, u16 pid)
|
||||
{
|
||||
struct dmxdev_feed *feed;
|
||||
|
||||
if ((filter->type != DMXDEV_TYPE_PES) ||
|
||||
(filter->state < DMXDEV_STATE_SET))
|
||||
return -EINVAL;
|
||||
|
||||
/* only TS packet filters may have multiple PIDs */
|
||||
if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
|
||||
(!list_empty(&filter->feed.ts)))
|
||||
return -EINVAL;
|
||||
|
||||
feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
|
||||
if (feed == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
feed->pid = pid;
|
||||
list_add(&feed->next, &filter->feed.ts);
|
||||
|
||||
if (filter->state >= DMXDEV_STATE_GO)
|
||||
return dvb_dmxdev_start_feed(dmxdev, filter, feed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
|
||||
struct dmxdev_filter *filter, u16 pid)
|
||||
{
|
||||
struct dmxdev_feed *feed, *tmp;
|
||||
|
||||
if ((filter->type != DMXDEV_TYPE_PES) ||
|
||||
(filter->state < DMXDEV_STATE_SET))
|
||||
return -EINVAL;
|
||||
|
||||
list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
|
||||
if ((feed->pid == pid) && (feed->ts != NULL)) {
|
||||
feed->ts->stop_filtering(feed->ts);
|
||||
filter->dev->demux->release_ts_feed(filter->dev->demux,
|
||||
feed->ts);
|
||||
list_del(&feed->next);
|
||||
kfree(feed);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
|
||||
struct dmxdev_filter *dmxdevfilter,
|
||||
struct dmx_sct_filter_params *params)
|
||||
|
@ -784,7 +875,10 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
|
|||
struct dmxdev_filter *dmxdevfilter,
|
||||
struct dmx_pes_filter_params *params)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dvb_dmxdev_filter_stop(dmxdevfilter);
|
||||
dvb_dmxdev_filter_reset(dmxdevfilter);
|
||||
|
||||
if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
|
||||
return -EINVAL;
|
||||
|
@ -795,6 +889,11 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
|
|||
|
||||
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
|
||||
|
||||
ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
|
||||
dmxdevfilter->params.pes.pid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (params->flags & DMX_IMMEDIATE_START)
|
||||
return dvb_dmxdev_filter_start(dmxdevfilter);
|
||||
|
||||
|
@ -958,6 +1057,24 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
|
|||
&((struct dmx_stc *)parg)->base);
|
||||
break;
|
||||
|
||||
case DMX_ADD_PID:
|
||||
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
break;
|
||||
|
||||
case DMX_REMOVE_PID:
|
||||
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
|
|
|
@ -53,13 +53,20 @@ enum dmxdev_state {
|
|||
DMXDEV_STATE_TIMEDOUT
|
||||
};
|
||||
|
||||
struct dmxdev_feed {
|
||||
u16 pid;
|
||||
struct dmx_ts_feed *ts;
|
||||
struct list_head next;
|
||||
};
|
||||
|
||||
struct dmxdev_filter {
|
||||
union {
|
||||
struct dmx_section_filter *sec;
|
||||
} filter;
|
||||
|
||||
union {
|
||||
struct dmx_ts_feed *ts;
|
||||
/* list of TS and PES feeds (struct dmxdev_feed) */
|
||||
struct list_head ts;
|
||||
struct dmx_section_feed *sec;
|
||||
} feed;
|
||||
|
||||
|
|
|
@ -425,13 +425,9 @@ no_dvb_demux_tscheck:
|
|||
if ((DVR_FEED(feed)) && (dvr_done++))
|
||||
continue;
|
||||
|
||||
if (feed->pid == pid) {
|
||||
if (feed->pid == pid)
|
||||
dvb_dmx_swfilter_packet_type(feed, buf);
|
||||
if (DVR_FEED(feed))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (feed->pid == 0x2000)
|
||||
else if (feed->pid == 0x2000)
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open(
|
|||
#define FESTATE_ZIGZAG_FAST 32
|
||||
#define FESTATE_ZIGZAG_SLOW 64
|
||||
#define FESTATE_DISEQC 128
|
||||
#define FESTATE_ERROR 256
|
||||
#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)
|
||||
#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
|
||||
#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
|
||||
|
@ -269,6 +270,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
|
|||
{
|
||||
int autoinversion;
|
||||
int ready = 0;
|
||||
int fe_set_err = 0;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
int original_inversion = fepriv->parameters.inversion;
|
||||
u32 original_frequency = fepriv->parameters.frequency;
|
||||
|
@ -345,7 +347,11 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
|
|||
if (autoinversion)
|
||||
fepriv->parameters.inversion = fepriv->inversion;
|
||||
if (fe->ops.set_frontend)
|
||||
fe->ops.set_frontend(fe, &fepriv->parameters);
|
||||
fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters);
|
||||
if (fe_set_err < 0) {
|
||||
fepriv->state = FESTATE_ERROR;
|
||||
return fe_set_err;
|
||||
}
|
||||
|
||||
fepriv->parameters.frequency = original_frequency;
|
||||
fepriv->parameters.inversion = original_inversion;
|
||||
|
@ -357,6 +363,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
|
|||
static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
|
||||
{
|
||||
fe_status_t s = 0;
|
||||
int retval = 0;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
|
||||
/* if we've got no parameters, just keep idling */
|
||||
|
@ -370,8 +377,12 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
|
|||
if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
|
||||
if (fepriv->state & FESTATE_RETUNE) {
|
||||
if (fe->ops.set_frontend)
|
||||
fe->ops.set_frontend(fe, &fepriv->parameters);
|
||||
fepriv->state = FESTATE_TUNED;
|
||||
retval = fe->ops.set_frontend(fe,
|
||||
&fepriv->parameters);
|
||||
if (retval < 0)
|
||||
fepriv->state = FESTATE_ERROR;
|
||||
else
|
||||
fepriv->state = FESTATE_TUNED;
|
||||
}
|
||||
fepriv->delay = 3*HZ;
|
||||
fepriv->quality = 0;
|
||||
|
@ -449,7 +460,11 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
|
|||
fepriv->delay = fepriv->min_delay;
|
||||
|
||||
/* peform a tune */
|
||||
if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
|
||||
retval = dvb_frontend_swzigzag_autotune(fe,
|
||||
fepriv->check_wrapped);
|
||||
if (retval < 0) {
|
||||
return;
|
||||
} else if (retval) {
|
||||
/* OK, if we've run out of trials at the fast speed.
|
||||
* Drop back to slow for the _next_ attempt */
|
||||
fepriv->state = FESTATE_SEARCHING_SLOW;
|
||||
|
@ -823,6 +838,15 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
|
|||
}
|
||||
}
|
||||
|
||||
/* check for supported modulation */
|
||||
if (fe->ops.info.type == FE_QAM &&
|
||||
(parms->u.qam.modulation > QAM_AUTO ||
|
||||
!((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) {
|
||||
printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n",
|
||||
fe->dvb->num, fe->id, parms->u.qam.modulation);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1499,7 +1523,8 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
|
|||
|
||||
/* if retune was requested but hasn't occured yet, prevent
|
||||
* that user get signal state from previous tuning */
|
||||
if(fepriv->state == FESTATE_RETUNE) {
|
||||
if (fepriv->state == FESTATE_RETUNE ||
|
||||
fepriv->state == FESTATE_ERROR) {
|
||||
err=0;
|
||||
*status = 0;
|
||||
break;
|
||||
|
|
|
@ -30,7 +30,12 @@
|
|||
|
||||
#define DVB_MAJOR 212
|
||||
|
||||
#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
|
||||
#define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
|
||||
#else
|
||||
#warning invalid CONFIG_DVB_MAX_ADAPTERS value
|
||||
#define DVB_MAX_ADAPTERS 8
|
||||
#endif
|
||||
|
||||
#define DVB_UNSET (-1)
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ config DVB_USB_AF9005_REMOTE
|
|||
Afatech AF9005 based receiver.
|
||||
|
||||
config DVB_USB_DW2102
|
||||
tristate "DvbWorld DVB-S/S2 USB2.0 support"
|
||||
tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_PLL if !DVB_FE_CUSTOMISE
|
||||
select DVB_STV0299 if !DVB_FE_CUSTOMISE
|
||||
|
@ -262,9 +262,11 @@ config DVB_USB_DW2102
|
|||
select DVB_CX24116 if !DVB_FE_CUSTOMISE
|
||||
select DVB_SI21XX if !DVB_FE_CUSTOMISE
|
||||
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
|
||||
select DVB_MT312 if !DVB_FE_CUSTOMISE
|
||||
select DVB_ZL10039 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
|
||||
and the TeVii S650.
|
||||
and the TeVii S650, S630.
|
||||
|
||||
config DVB_USB_CINERGY_T2
|
||||
tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver"
|
||||
|
|
|
@ -38,41 +38,41 @@ static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_pr
|
|||
}
|
||||
|
||||
static struct dvb_usb_rc_key a800_rc_keys[] = {
|
||||
{ 0x02, 0x01, KEY_PROG1 }, /* SOURCE */
|
||||
{ 0x02, 0x00, KEY_POWER }, /* POWER */
|
||||
{ 0x02, 0x05, KEY_1 }, /* 1 */
|
||||
{ 0x02, 0x06, KEY_2 }, /* 2 */
|
||||
{ 0x02, 0x07, KEY_3 }, /* 3 */
|
||||
{ 0x02, 0x09, KEY_4 }, /* 4 */
|
||||
{ 0x02, 0x0a, KEY_5 }, /* 5 */
|
||||
{ 0x02, 0x0b, KEY_6 }, /* 6 */
|
||||
{ 0x02, 0x0d, KEY_7 }, /* 7 */
|
||||
{ 0x02, 0x0e, KEY_8 }, /* 8 */
|
||||
{ 0x02, 0x0f, KEY_9 }, /* 9 */
|
||||
{ 0x02, 0x12, KEY_LEFT }, /* L / DISPLAY */
|
||||
{ 0x02, 0x11, KEY_0 }, /* 0 */
|
||||
{ 0x02, 0x13, KEY_RIGHT }, /* R / CH RTN */
|
||||
{ 0x02, 0x17, KEY_PROG2 }, /* SNAP SHOT */
|
||||
{ 0x02, 0x10, KEY_PROG3 }, /* 16-CH PREV */
|
||||
{ 0x02, 0x1e, KEY_VOLUMEDOWN }, /* VOL DOWN */
|
||||
{ 0x02, 0x0c, KEY_ZOOM }, /* FULL SCREEN */
|
||||
{ 0x02, 0x1f, KEY_VOLUMEUP }, /* VOL UP */
|
||||
{ 0x02, 0x14, KEY_MUTE }, /* MUTE */
|
||||
{ 0x02, 0x08, KEY_AUDIO }, /* AUDIO */
|
||||
{ 0x02, 0x19, KEY_RECORD }, /* RECORD */
|
||||
{ 0x02, 0x18, KEY_PLAY }, /* PLAY */
|
||||
{ 0x02, 0x1b, KEY_STOP }, /* STOP */
|
||||
{ 0x02, 0x1a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
|
||||
{ 0x02, 0x1d, KEY_BACK }, /* << / RED */
|
||||
{ 0x02, 0x1c, KEY_FORWARD }, /* >> / YELLOW */
|
||||
{ 0x02, 0x03, KEY_TEXT }, /* TELETEXT */
|
||||
{ 0x02, 0x04, KEY_EPG }, /* EPG */
|
||||
{ 0x02, 0x15, KEY_MENU }, /* MENU */
|
||||
{ 0x0201, KEY_PROG1 }, /* SOURCE */
|
||||
{ 0x0200, KEY_POWER }, /* 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_PROG2 }, /* SNAP SHOT */
|
||||
{ 0x0210, KEY_PROG3 }, /* 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 */
|
||||
|
||||
{ 0x03, 0x03, KEY_CHANNELUP }, /* CH UP */
|
||||
{ 0x03, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
|
||||
{ 0x03, 0x01, KEY_FIRST }, /* |<< / GREEN */
|
||||
{ 0x03, 0x00, KEY_LAST }, /* >>| / BLUE */
|
||||
{ 0x0303, KEY_CHANNELUP }, /* CH UP */
|
||||
{ 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */
|
||||
{ 0x0301, KEY_FIRST }, /* |<< / GREEN */
|
||||
{ 0x0300, KEY_LAST }, /* >>| / BLUE */
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -35,43 +35,43 @@ MODULE_PARM_DESC(debug,
|
|||
|
||||
struct dvb_usb_rc_key af9005_rc_keys[] = {
|
||||
|
||||
{0x01, 0xb7, KEY_POWER},
|
||||
{0x01, 0xa7, KEY_VOLUMEUP},
|
||||
{0x01, 0x87, KEY_CHANNELUP},
|
||||
{0x01, 0x7f, KEY_MUTE},
|
||||
{0x01, 0xbf, KEY_VOLUMEDOWN},
|
||||
{0x01, 0x3f, KEY_CHANNELDOWN},
|
||||
{0x01, 0xdf, KEY_1},
|
||||
{0x01, 0x5f, KEY_2},
|
||||
{0x01, 0x9f, KEY_3},
|
||||
{0x01, 0x1f, KEY_4},
|
||||
{0x01, 0xef, KEY_5},
|
||||
{0x01, 0x6f, KEY_6},
|
||||
{0x01, 0xaf, KEY_7},
|
||||
{0x01, 0x27, KEY_8},
|
||||
{0x01, 0x07, KEY_9},
|
||||
{0x01, 0xcf, KEY_ZOOM},
|
||||
{0x01, 0x4f, KEY_0},
|
||||
{0x01, 0x8f, KEY_GOTO}, /* marked jump on the remote */
|
||||
{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 */
|
||||
|
||||
{0x00, 0xbd, KEY_POWER},
|
||||
{0x00, 0x7d, KEY_VOLUMEUP},
|
||||
{0x00, 0xfd, KEY_CHANNELUP},
|
||||
{0x00, 0x9d, KEY_MUTE},
|
||||
{0x00, 0x5d, KEY_VOLUMEDOWN},
|
||||
{0x00, 0xdd, KEY_CHANNELDOWN},
|
||||
{0x00, 0xad, KEY_1},
|
||||
{0x00, 0x6d, KEY_2},
|
||||
{0x00, 0xed, KEY_3},
|
||||
{0x00, 0x8d, KEY_4},
|
||||
{0x00, 0x4d, KEY_5},
|
||||
{0x00, 0xcd, KEY_6},
|
||||
{0x00, 0xb5, KEY_7},
|
||||
{0x00, 0x75, KEY_8},
|
||||
{0x00, 0xf5, KEY_9},
|
||||
{0x00, 0x95, KEY_ZOOM},
|
||||
{0x00, 0x55, KEY_0},
|
||||
{0x00, 0xd5, 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 af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys);
|
||||
|
@ -131,8 +131,8 @@ int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
|
|||
return 0;
|
||||
}
|
||||
for (i = 0; i < af9005_rc_keys_size; i++) {
|
||||
if (af9005_rc_keys[i].custom == cust
|
||||
&& af9005_rc_keys[i].data == dat) {
|
||||
if (rc5_custom(&af9005_rc_keys[i]) == cust
|
||||
&& rc5_data(&af9005_rc_keys[i]) == dat) {
|
||||
*event = af9005_rc_keys[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
deb_decode
|
||||
|
|
|
@ -538,24 +538,22 @@ exit:
|
|||
/* dump eeprom */
|
||||
static int af9015_eeprom_dump(struct dvb_usb_device *d)
|
||||
{
|
||||
char buf[4+3*16+1], buf2[4];
|
||||
u8 reg, val;
|
||||
|
||||
for (reg = 0; ; reg++) {
|
||||
if (reg % 16 == 0) {
|
||||
if (reg)
|
||||
deb_info("%s\n", buf);
|
||||
sprintf(buf, "%02x: ", reg);
|
||||
deb_info(KERN_CONT "\n");
|
||||
deb_info(KERN_DEBUG "%02x:", reg);
|
||||
}
|
||||
if (af9015_read_reg_i2c(d, AF9015_I2C_EEPROM, reg, &val) == 0)
|
||||
sprintf(buf2, "%02x ", val);
|
||||
deb_info(KERN_CONT " %02x", val);
|
||||
else
|
||||
strcpy(buf2, "-- ");
|
||||
strcat(buf, buf2);
|
||||
deb_info(KERN_CONT " --");
|
||||
if (reg == 0xff)
|
||||
break;
|
||||
}
|
||||
deb_info("%s\n", buf);
|
||||
deb_info(KERN_CONT "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1045,8 +1043,8 @@ static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (!buf[1] && keymap[i].custom == buf[0] &&
|
||||
keymap[i].data == buf[2]) {
|
||||
if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
|
||||
rc5_data(&keymap[i]) == buf[2]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
break;
|
||||
|
@ -1266,6 +1264,7 @@ static struct usb_device_id af9015_usb_table[] = {
|
|||
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
|
||||
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
|
||||
{USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
|
||||
/* 25 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
|
||||
{0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
|
||||
|
@ -1346,7 +1345,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
{
|
||||
.name = "KWorld PlusTV Dual DVB-T Stick " \
|
||||
"(DVB-T 399U)",
|
||||
.cold_ids = {&af9015_usb_table[4], NULL},
|
||||
.cold_ids = {&af9015_usb_table[4],
|
||||
&af9015_usb_table[25], NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -121,21 +121,21 @@ enum af9015_remote {
|
|||
|
||||
/* Leadtek WinFast DTV Dongle Gold */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
|
||||
{ 0x00, 0x1e, KEY_1 },
|
||||
{ 0x00, 0x1f, KEY_2 },
|
||||
{ 0x00, 0x20, KEY_3 },
|
||||
{ 0x00, 0x21, KEY_4 },
|
||||
{ 0x00, 0x22, KEY_5 },
|
||||
{ 0x00, 0x23, KEY_6 },
|
||||
{ 0x00, 0x24, KEY_7 },
|
||||
{ 0x00, 0x25, KEY_8 },
|
||||
{ 0x00, 0x26, KEY_9 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x28, KEY_ENTER },
|
||||
{ 0x00, 0x4f, KEY_VOLUMEUP },
|
||||
{ 0x00, 0x50, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x51, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x52, KEY_CHANNELUP },
|
||||
{ 0x001e, KEY_1 },
|
||||
{ 0x001f, KEY_2 },
|
||||
{ 0x0020, KEY_3 },
|
||||
{ 0x0021, KEY_4 },
|
||||
{ 0x0022, KEY_5 },
|
||||
{ 0x0023, KEY_6 },
|
||||
{ 0x0024, KEY_7 },
|
||||
{ 0x0025, KEY_8 },
|
||||
{ 0x0026, KEY_9 },
|
||||
{ 0x0027, KEY_0 },
|
||||
{ 0x0028, KEY_ENTER },
|
||||
{ 0x004f, KEY_VOLUMEUP },
|
||||
{ 0x0050, KEY_VOLUMEDOWN },
|
||||
{ 0x0051, KEY_CHANNELDOWN },
|
||||
{ 0x0052, KEY_CHANNELUP },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_leadtek[] = {
|
||||
|
@ -193,60 +193,60 @@ static u8 af9015_ir_table_leadtek[] = {
|
|||
|
||||
/* TwinHan AzureWave AD-TU700(704J) */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_twinhan[] = {
|
||||
{ 0x05, 0x3f, KEY_POWER },
|
||||
{ 0x00, 0x19, KEY_FAVORITES }, /* Favorite List */
|
||||
{ 0x00, 0x04, KEY_TEXT }, /* Teletext */
|
||||
{ 0x00, 0x0e, KEY_POWER },
|
||||
{ 0x00, 0x0e, KEY_INFO }, /* Preview */
|
||||
{ 0x00, 0x08, KEY_EPG }, /* Info/EPG */
|
||||
{ 0x00, 0x0f, KEY_LIST }, /* Record List */
|
||||
{ 0x00, 0x1e, KEY_1 },
|
||||
{ 0x00, 0x1f, KEY_2 },
|
||||
{ 0x00, 0x20, KEY_3 },
|
||||
{ 0x00, 0x21, KEY_4 },
|
||||
{ 0x00, 0x22, KEY_5 },
|
||||
{ 0x00, 0x23, KEY_6 },
|
||||
{ 0x00, 0x24, KEY_7 },
|
||||
{ 0x00, 0x25, KEY_8 },
|
||||
{ 0x00, 0x26, KEY_9 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x29, KEY_CANCEL }, /* Cancel */
|
||||
{ 0x00, 0x4c, KEY_CLEAR }, /* Clear */
|
||||
{ 0x00, 0x2a, KEY_BACK }, /* Back */
|
||||
{ 0x00, 0x2b, KEY_TAB }, /* Tab */
|
||||
{ 0x00, 0x52, KEY_UP }, /* up arrow */
|
||||
{ 0x00, 0x51, KEY_DOWN }, /* down arrow */
|
||||
{ 0x00, 0x4f, KEY_RIGHT }, /* right arrow */
|
||||
{ 0x00, 0x50, KEY_LEFT }, /* left arrow */
|
||||
{ 0x00, 0x28, KEY_ENTER }, /* Enter / ok */
|
||||
{ 0x02, 0x52, KEY_VOLUMEUP },
|
||||
{ 0x02, 0x51, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x4e, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x4b, KEY_CHANNELUP },
|
||||
{ 0x00, 0x4a, KEY_RECORD },
|
||||
{ 0x01, 0x11, KEY_PLAY },
|
||||
{ 0x00, 0x17, KEY_PAUSE },
|
||||
{ 0x00, 0x0c, KEY_REWIND }, /* FR << */
|
||||
{ 0x00, 0x11, KEY_FASTFORWARD }, /* FF >> */
|
||||
{ 0x01, 0x15, KEY_PREVIOUS }, /* Replay */
|
||||
{ 0x01, 0x0e, KEY_NEXT }, /* Skip */
|
||||
{ 0x00, 0x13, KEY_CAMERA }, /* Capture */
|
||||
{ 0x01, 0x0f, KEY_LANGUAGE }, /* SAP */
|
||||
{ 0x01, 0x13, KEY_TV2 }, /* PIP */
|
||||
{ 0x00, 0x1d, KEY_ZOOM }, /* Full Screen */
|
||||
{ 0x01, 0x17, KEY_SUBTITLE }, /* Subtitle / CC */
|
||||
{ 0x00, 0x10, KEY_MUTE },
|
||||
{ 0x01, 0x19, KEY_AUDIO }, /* L/R */ /* TODO better event */
|
||||
{ 0x01, 0x16, KEY_SLEEP }, /* Hibernate */
|
||||
{ 0x01, 0x16, KEY_SWITCHVIDEOMODE },
|
||||
{ 0x053f, KEY_POWER },
|
||||
{ 0x0019, KEY_FAVORITES }, /* Favorite List */
|
||||
{ 0x0004, KEY_TEXT }, /* Teletext */
|
||||
{ 0x000e, KEY_POWER },
|
||||
{ 0x000e, KEY_INFO }, /* Preview */
|
||||
{ 0x0008, KEY_EPG }, /* Info/EPG */
|
||||
{ 0x000f, KEY_LIST }, /* Record List */
|
||||
{ 0x001e, KEY_1 },
|
||||
{ 0x001f, KEY_2 },
|
||||
{ 0x0020, KEY_3 },
|
||||
{ 0x0021, KEY_4 },
|
||||
{ 0x0022, KEY_5 },
|
||||
{ 0x0023, KEY_6 },
|
||||
{ 0x0024, KEY_7 },
|
||||
{ 0x0025, KEY_8 },
|
||||
{ 0x0026, KEY_9 },
|
||||
{ 0x0027, KEY_0 },
|
||||
{ 0x0029, KEY_CANCEL }, /* Cancel */
|
||||
{ 0x004c, KEY_CLEAR }, /* Clear */
|
||||
{ 0x002a, KEY_BACK }, /* Back */
|
||||
{ 0x002b, KEY_TAB }, /* Tab */
|
||||
{ 0x0052, KEY_UP }, /* up arrow */
|
||||
{ 0x0051, KEY_DOWN }, /* down arrow */
|
||||
{ 0x004f, KEY_RIGHT }, /* right arrow */
|
||||
{ 0x0050, KEY_LEFT }, /* left arrow */
|
||||
{ 0x0028, KEY_ENTER }, /* Enter / ok */
|
||||
{ 0x0252, KEY_VOLUMEUP },
|
||||
{ 0x0251, KEY_VOLUMEDOWN },
|
||||
{ 0x004e, KEY_CHANNELDOWN },
|
||||
{ 0x004b, KEY_CHANNELUP },
|
||||
{ 0x004a, KEY_RECORD },
|
||||
{ 0x0111, KEY_PLAY },
|
||||
{ 0x0017, KEY_PAUSE },
|
||||
{ 0x000c, KEY_REWIND }, /* FR << */
|
||||
{ 0x0011, KEY_FASTFORWARD }, /* FF >> */
|
||||
{ 0x0115, KEY_PREVIOUS }, /* Replay */
|
||||
{ 0x010e, KEY_NEXT }, /* Skip */
|
||||
{ 0x0013, KEY_CAMERA }, /* Capture */
|
||||
{ 0x010f, KEY_LANGUAGE }, /* SAP */
|
||||
{ 0x0113, KEY_TV2 }, /* PIP */
|
||||
{ 0x001d, KEY_ZOOM }, /* Full Screen */
|
||||
{ 0x0117, KEY_SUBTITLE }, /* Subtitle / CC */
|
||||
{ 0x0010, KEY_MUTE },
|
||||
{ 0x0119, KEY_AUDIO }, /* L/R */ /* TODO better event */
|
||||
{ 0x0116, KEY_SLEEP }, /* Hibernate */
|
||||
{ 0x0116, KEY_SWITCHVIDEOMODE },
|
||||
/* A/V */ /* TODO does not work */
|
||||
{ 0x00, 0x06, KEY_AGAIN }, /* Recall */
|
||||
{ 0x01, 0x16, KEY_KPPLUS }, /* Zoom+ */ /* TODO does not work */
|
||||
{ 0x01, 0x16, KEY_KPMINUS }, /* Zoom- */ /* TODO does not work */
|
||||
{ 0x02, 0x15, KEY_RED },
|
||||
{ 0x02, 0x0a, KEY_GREEN },
|
||||
{ 0x02, 0x1c, KEY_YELLOW },
|
||||
{ 0x02, 0x05, KEY_BLUE },
|
||||
{ 0x0006, KEY_AGAIN }, /* Recall */
|
||||
{ 0x0116, KEY_KPPLUS }, /* Zoom+ */ /* TODO does not work */
|
||||
{ 0x0116, KEY_KPMINUS }, /* Zoom- */ /* TODO does not work */
|
||||
{ 0x0215, KEY_RED },
|
||||
{ 0x020a, KEY_GREEN },
|
||||
{ 0x021c, KEY_YELLOW },
|
||||
{ 0x0205, KEY_BLUE },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_twinhan[] = {
|
||||
|
@ -304,24 +304,24 @@ static u8 af9015_ir_table_twinhan[] = {
|
|||
|
||||
/* A-Link DTU(m) */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_a_link[] = {
|
||||
{ 0x00, 0x1e, KEY_1 },
|
||||
{ 0x00, 0x1f, KEY_2 },
|
||||
{ 0x00, 0x20, KEY_3 },
|
||||
{ 0x00, 0x21, KEY_4 },
|
||||
{ 0x00, 0x22, KEY_5 },
|
||||
{ 0x00, 0x23, KEY_6 },
|
||||
{ 0x00, 0x24, KEY_7 },
|
||||
{ 0x00, 0x25, KEY_8 },
|
||||
{ 0x00, 0x26, KEY_9 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x2e, KEY_CHANNELUP },
|
||||
{ 0x00, 0x2d, KEY_CHANNELDOWN },
|
||||
{ 0x04, 0x28, KEY_ZOOM },
|
||||
{ 0x00, 0x41, KEY_MUTE },
|
||||
{ 0x00, 0x42, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x43, KEY_VOLUMEUP },
|
||||
{ 0x00, 0x44, KEY_GOTO }, /* jump */
|
||||
{ 0x05, 0x45, KEY_POWER },
|
||||
{ 0x001e, KEY_1 },
|
||||
{ 0x001f, KEY_2 },
|
||||
{ 0x0020, KEY_3 },
|
||||
{ 0x0021, KEY_4 },
|
||||
{ 0x0022, KEY_5 },
|
||||
{ 0x0023, KEY_6 },
|
||||
{ 0x0024, KEY_7 },
|
||||
{ 0x0025, KEY_8 },
|
||||
{ 0x0026, KEY_9 },
|
||||
{ 0x0027, KEY_0 },
|
||||
{ 0x002e, KEY_CHANNELUP },
|
||||
{ 0x002d, KEY_CHANNELDOWN },
|
||||
{ 0x0428, KEY_ZOOM },
|
||||
{ 0x0041, KEY_MUTE },
|
||||
{ 0x0042, KEY_VOLUMEDOWN },
|
||||
{ 0x0043, KEY_VOLUMEUP },
|
||||
{ 0x0044, KEY_GOTO }, /* jump */
|
||||
{ 0x0545, KEY_POWER },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_a_link[] = {
|
||||
|
@ -347,24 +347,24 @@ static u8 af9015_ir_table_a_link[] = {
|
|||
|
||||
/* MSI DIGIVOX mini II V3.0 */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_msi[] = {
|
||||
{ 0x00, 0x1e, KEY_1 },
|
||||
{ 0x00, 0x1f, KEY_2 },
|
||||
{ 0x00, 0x20, KEY_3 },
|
||||
{ 0x00, 0x21, KEY_4 },
|
||||
{ 0x00, 0x22, KEY_5 },
|
||||
{ 0x00, 0x23, KEY_6 },
|
||||
{ 0x00, 0x24, KEY_7 },
|
||||
{ 0x00, 0x25, KEY_8 },
|
||||
{ 0x00, 0x26, KEY_9 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x03, 0x0f, KEY_CHANNELUP },
|
||||
{ 0x03, 0x0e, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x42, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x43, KEY_VOLUMEUP },
|
||||
{ 0x05, 0x45, KEY_POWER },
|
||||
{ 0x00, 0x52, KEY_UP }, /* up */
|
||||
{ 0x00, 0x51, KEY_DOWN }, /* down */
|
||||
{ 0x00, 0x28, KEY_ENTER },
|
||||
{ 0x001e, KEY_1 },
|
||||
{ 0x001f, KEY_2 },
|
||||
{ 0x0020, KEY_3 },
|
||||
{ 0x0021, KEY_4 },
|
||||
{ 0x0022, KEY_5 },
|
||||
{ 0x0023, KEY_6 },
|
||||
{ 0x0024, KEY_7 },
|
||||
{ 0x0025, KEY_8 },
|
||||
{ 0x0026, KEY_9 },
|
||||
{ 0x0027, KEY_0 },
|
||||
{ 0x030f, KEY_CHANNELUP },
|
||||
{ 0x030e, KEY_CHANNELDOWN },
|
||||
{ 0x0042, KEY_VOLUMEDOWN },
|
||||
{ 0x0043, KEY_VOLUMEUP },
|
||||
{ 0x0545, KEY_POWER },
|
||||
{ 0x0052, KEY_UP }, /* up */
|
||||
{ 0x0051, KEY_DOWN }, /* down */
|
||||
{ 0x0028, KEY_ENTER },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_msi[] = {
|
||||
|
@ -390,42 +390,42 @@ static u8 af9015_ir_table_msi[] = {
|
|||
|
||||
/* MYGICTV U718 */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_mygictv[] = {
|
||||
{ 0x00, 0x3d, KEY_SWITCHVIDEOMODE },
|
||||
{ 0x003d, KEY_SWITCHVIDEOMODE },
|
||||
/* TV / AV */
|
||||
{ 0x05, 0x45, KEY_POWER },
|
||||
{ 0x00, 0x1e, KEY_1 },
|
||||
{ 0x00, 0x1f, KEY_2 },
|
||||
{ 0x00, 0x20, KEY_3 },
|
||||
{ 0x00, 0x21, KEY_4 },
|
||||
{ 0x00, 0x22, KEY_5 },
|
||||
{ 0x00, 0x23, KEY_6 },
|
||||
{ 0x00, 0x24, KEY_7 },
|
||||
{ 0x00, 0x25, KEY_8 },
|
||||
{ 0x00, 0x26, KEY_9 },
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x41, KEY_MUTE },
|
||||
{ 0x00, 0x2a, KEY_ESC }, /* Esc */
|
||||
{ 0x00, 0x2e, KEY_CHANNELUP },
|
||||
{ 0x00, 0x2d, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x42, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x43, KEY_VOLUMEUP },
|
||||
{ 0x00, 0x52, KEY_UP }, /* up arrow */
|
||||
{ 0x00, 0x51, KEY_DOWN }, /* down arrow */
|
||||
{ 0x00, 0x4f, KEY_RIGHT }, /* right arrow */
|
||||
{ 0x00, 0x50, KEY_LEFT }, /* left arrow */
|
||||
{ 0x00, 0x28, KEY_ENTER }, /* ok */
|
||||
{ 0x01, 0x15, KEY_RECORD },
|
||||
{ 0x03, 0x13, KEY_PLAY },
|
||||
{ 0x01, 0x13, KEY_PAUSE },
|
||||
{ 0x01, 0x16, KEY_STOP },
|
||||
{ 0x03, 0x07, KEY_REWIND }, /* FR << */
|
||||
{ 0x03, 0x09, KEY_FASTFORWARD }, /* FF >> */
|
||||
{ 0x00, 0x3b, KEY_TIME }, /* TimeShift */
|
||||
{ 0x00, 0x3e, KEY_CAMERA }, /* Snapshot */
|
||||
{ 0x03, 0x16, KEY_CYCLEWINDOWS }, /* yellow, min / max */
|
||||
{ 0x00, 0x00, KEY_ZOOM }, /* 'select' (?) */
|
||||
{ 0x03, 0x16, KEY_SHUFFLE }, /* Shuffle */
|
||||
{ 0x03, 0x45, KEY_POWER },
|
||||
{ 0x0545, KEY_POWER },
|
||||
{ 0x001e, KEY_1 },
|
||||
{ 0x001f, KEY_2 },
|
||||
{ 0x0020, KEY_3 },
|
||||
{ 0x0021, KEY_4 },
|
||||
{ 0x0022, KEY_5 },
|
||||
{ 0x0023, KEY_6 },
|
||||
{ 0x0024, KEY_7 },
|
||||
{ 0x0025, KEY_8 },
|
||||
{ 0x0026, KEY_9 },
|
||||
{ 0x0027, KEY_0 },
|
||||
{ 0x0041, KEY_MUTE },
|
||||
{ 0x002a, KEY_ESC }, /* Esc */
|
||||
{ 0x002e, KEY_CHANNELUP },
|
||||
{ 0x002d, KEY_CHANNELDOWN },
|
||||
{ 0x0042, KEY_VOLUMEDOWN },
|
||||
{ 0x0043, KEY_VOLUMEUP },
|
||||
{ 0x0052, KEY_UP }, /* up arrow */
|
||||
{ 0x0051, KEY_DOWN }, /* down arrow */
|
||||
{ 0x004f, KEY_RIGHT }, /* right arrow */
|
||||
{ 0x0050, KEY_LEFT }, /* left arrow */
|
||||
{ 0x0028, KEY_ENTER }, /* ok */
|
||||
{ 0x0115, KEY_RECORD },
|
||||
{ 0x0313, KEY_PLAY },
|
||||
{ 0x0113, KEY_PAUSE },
|
||||
{ 0x0116, KEY_STOP },
|
||||
{ 0x0307, KEY_REWIND }, /* FR << */
|
||||
{ 0x0309, KEY_FASTFORWARD }, /* FF >> */
|
||||
{ 0x003b, KEY_TIME }, /* TimeShift */
|
||||
{ 0x003e, KEY_CAMERA }, /* Snapshot */
|
||||
{ 0x0316, KEY_CYCLEWINDOWS }, /* yellow, min / max */
|
||||
{ 0x0000, KEY_ZOOM }, /* 'select' (?) */
|
||||
{ 0x0316, KEY_SHUFFLE }, /* Shuffle */
|
||||
{ 0x0345, KEY_POWER },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_mygictv[] = {
|
||||
|
@ -516,41 +516,41 @@ static u8 af9015_ir_table_kworld[] = {
|
|||
|
||||
/* AverMedia Volar X */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_avermedia[] = {
|
||||
{ 0x05, 0x3d, KEY_PROG1 }, /* SOURCE */
|
||||
{ 0x05, 0x12, KEY_POWER }, /* POWER */
|
||||
{ 0x05, 0x1e, KEY_1 }, /* 1 */
|
||||
{ 0x05, 0x1f, KEY_2 }, /* 2 */
|
||||
{ 0x05, 0x20, KEY_3 }, /* 3 */
|
||||
{ 0x05, 0x21, KEY_4 }, /* 4 */
|
||||
{ 0x05, 0x22, KEY_5 }, /* 5 */
|
||||
{ 0x05, 0x23, KEY_6 }, /* 6 */
|
||||
{ 0x05, 0x24, KEY_7 }, /* 7 */
|
||||
{ 0x05, 0x25, KEY_8 }, /* 8 */
|
||||
{ 0x05, 0x26, KEY_9 }, /* 9 */
|
||||
{ 0x05, 0x3f, KEY_LEFT }, /* L / DISPLAY */
|
||||
{ 0x05, 0x27, KEY_0 }, /* 0 */
|
||||
{ 0x05, 0x0f, KEY_RIGHT }, /* R / CH RTN */
|
||||
{ 0x05, 0x18, KEY_PROG2 }, /* SNAP SHOT */
|
||||
{ 0x05, 0x1c, KEY_PROG3 }, /* 16-CH PREV */
|
||||
{ 0x05, 0x2d, KEY_VOLUMEDOWN }, /* VOL DOWN */
|
||||
{ 0x05, 0x3e, KEY_ZOOM }, /* FULL SCREEN */
|
||||
{ 0x05, 0x2e, KEY_VOLUMEUP }, /* VOL UP */
|
||||
{ 0x05, 0x10, KEY_MUTE }, /* MUTE */
|
||||
{ 0x05, 0x04, KEY_AUDIO }, /* AUDIO */
|
||||
{ 0x05, 0x15, KEY_RECORD }, /* RECORD */
|
||||
{ 0x05, 0x11, KEY_PLAY }, /* PLAY */
|
||||
{ 0x05, 0x16, KEY_STOP }, /* STOP */
|
||||
{ 0x05, 0x0c, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
|
||||
{ 0x05, 0x05, KEY_BACK }, /* << / RED */
|
||||
{ 0x05, 0x09, KEY_FORWARD }, /* >> / YELLOW */
|
||||
{ 0x05, 0x17, KEY_TEXT }, /* TELETEXT */
|
||||
{ 0x05, 0x0a, KEY_EPG }, /* EPG */
|
||||
{ 0x05, 0x13, KEY_MENU }, /* MENU */
|
||||
{ 0x053d, KEY_PROG1 }, /* SOURCE */
|
||||
{ 0x0512, KEY_POWER }, /* POWER */
|
||||
{ 0x051e, KEY_1 }, /* 1 */
|
||||
{ 0x051f, KEY_2 }, /* 2 */
|
||||
{ 0x0520, KEY_3 }, /* 3 */
|
||||
{ 0x0521, KEY_4 }, /* 4 */
|
||||
{ 0x0522, KEY_5 }, /* 5 */
|
||||
{ 0x0523, KEY_6 }, /* 6 */
|
||||
{ 0x0524, KEY_7 }, /* 7 */
|
||||
{ 0x0525, KEY_8 }, /* 8 */
|
||||
{ 0x0526, KEY_9 }, /* 9 */
|
||||
{ 0x053f, KEY_LEFT }, /* L / DISPLAY */
|
||||
{ 0x0527, KEY_0 }, /* 0 */
|
||||
{ 0x050f, KEY_RIGHT }, /* R / CH RTN */
|
||||
{ 0x0518, KEY_PROG2 }, /* SNAP SHOT */
|
||||
{ 0x051c, KEY_PROG3 }, /* 16-CH PREV */
|
||||
{ 0x052d, KEY_VOLUMEDOWN }, /* VOL DOWN */
|
||||
{ 0x053e, KEY_ZOOM }, /* FULL SCREEN */
|
||||
{ 0x052e, KEY_VOLUMEUP }, /* VOL UP */
|
||||
{ 0x0510, KEY_MUTE }, /* MUTE */
|
||||
{ 0x0504, KEY_AUDIO }, /* AUDIO */
|
||||
{ 0x0515, KEY_RECORD }, /* RECORD */
|
||||
{ 0x0511, KEY_PLAY }, /* PLAY */
|
||||
{ 0x0516, KEY_STOP }, /* STOP */
|
||||
{ 0x050c, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
|
||||
{ 0x0505, KEY_BACK }, /* << / RED */
|
||||
{ 0x0509, KEY_FORWARD }, /* >> / YELLOW */
|
||||
{ 0x0517, KEY_TEXT }, /* TELETEXT */
|
||||
{ 0x050a, KEY_EPG }, /* EPG */
|
||||
{ 0x0513, KEY_MENU }, /* MENU */
|
||||
|
||||
{ 0x05, 0x0e, KEY_CHANNELUP }, /* CH UP */
|
||||
{ 0x05, 0x0d, KEY_CHANNELDOWN }, /* CH DOWN */
|
||||
{ 0x05, 0x19, KEY_FIRST }, /* |<< / GREEN */
|
||||
{ 0x05, 0x08, KEY_LAST }, /* >>| / BLUE */
|
||||
{ 0x050e, KEY_CHANNELUP }, /* CH UP */
|
||||
{ 0x050d, KEY_CHANNELDOWN }, /* CH DOWN */
|
||||
{ 0x0519, KEY_FIRST }, /* |<< / GREEN */
|
||||
{ 0x0508, KEY_LAST }, /* >>| / BLUE */
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_avermedia[] = {
|
||||
|
@ -622,34 +622,34 @@ static u8 af9015_ir_table_avermedia_ks[] = {
|
|||
|
||||
/* Digittrade DVB-T USB Stick */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = {
|
||||
{ 0x01, 0x0f, KEY_LAST }, /* RETURN */
|
||||
{ 0x05, 0x17, KEY_TEXT }, /* TELETEXT */
|
||||
{ 0x01, 0x08, KEY_EPG }, /* EPG */
|
||||
{ 0x05, 0x13, KEY_POWER }, /* POWER */
|
||||
{ 0x01, 0x09, KEY_ZOOM }, /* FULLSCREEN */
|
||||
{ 0x00, 0x40, KEY_AUDIO }, /* DUAL SOUND */
|
||||
{ 0x00, 0x2c, KEY_PRINT }, /* SNAPSHOT */
|
||||
{ 0x05, 0x16, KEY_SUBTITLE }, /* SUBTITLE */
|
||||
{ 0x00, 0x52, KEY_CHANNELUP }, /* CH Up */
|
||||
{ 0x00, 0x51, KEY_CHANNELDOWN },/* Ch Dn */
|
||||
{ 0x00, 0x57, KEY_VOLUMEUP }, /* Vol Up */
|
||||
{ 0x00, 0x56, KEY_VOLUMEDOWN }, /* Vol Dn */
|
||||
{ 0x01, 0x10, KEY_MUTE }, /* MUTE */
|
||||
{ 0x00, 0x27, KEY_0 },
|
||||
{ 0x00, 0x1e, KEY_1 },
|
||||
{ 0x00, 0x1f, KEY_2 },
|
||||
{ 0x00, 0x20, KEY_3 },
|
||||
{ 0x00, 0x21, KEY_4 },
|
||||
{ 0x00, 0x22, KEY_5 },
|
||||
{ 0x00, 0x23, KEY_6 },
|
||||
{ 0x00, 0x24, KEY_7 },
|
||||
{ 0x00, 0x25, KEY_8 },
|
||||
{ 0x00, 0x26, KEY_9 },
|
||||
{ 0x01, 0x17, KEY_PLAYPAUSE }, /* TIMESHIFT */
|
||||
{ 0x01, 0x15, KEY_RECORD }, /* RECORD */
|
||||
{ 0x03, 0x13, KEY_PLAY }, /* PLAY */
|
||||
{ 0x01, 0x16, KEY_STOP }, /* STOP */
|
||||
{ 0x01, 0x13, KEY_PAUSE }, /* PAUSE */
|
||||
{ 0x010f, KEY_LAST }, /* RETURN */
|
||||
{ 0x0517, KEY_TEXT }, /* TELETEXT */
|
||||
{ 0x0108, KEY_EPG }, /* EPG */
|
||||
{ 0x0513, KEY_POWER }, /* POWER */
|
||||
{ 0x0109, KEY_ZOOM }, /* FULLSCREEN */
|
||||
{ 0x0040, KEY_AUDIO }, /* DUAL SOUND */
|
||||
{ 0x002c, KEY_PRINT }, /* SNAPSHOT */
|
||||
{ 0x0516, KEY_SUBTITLE }, /* SUBTITLE */
|
||||
{ 0x0052, KEY_CHANNELUP }, /* CH Up */
|
||||
{ 0x0051, KEY_CHANNELDOWN },/* Ch Dn */
|
||||
{ 0x0057, KEY_VOLUMEUP }, /* Vol Up */
|
||||
{ 0x0056, KEY_VOLUMEDOWN }, /* Vol Dn */
|
||||
{ 0x0110, KEY_MUTE }, /* MUTE */
|
||||
{ 0x0027, KEY_0 },
|
||||
{ 0x001e, KEY_1 },
|
||||
{ 0x001f, KEY_2 },
|
||||
{ 0x0020, KEY_3 },
|
||||
{ 0x0021, KEY_4 },
|
||||
{ 0x0022, KEY_5 },
|
||||
{ 0x0023, KEY_6 },
|
||||
{ 0x0024, KEY_7 },
|
||||
{ 0x0025, KEY_8 },
|
||||
{ 0x0026, KEY_9 },
|
||||
{ 0x0117, KEY_PLAYPAUSE }, /* TIMESHIFT */
|
||||
{ 0x0115, KEY_RECORD }, /* RECORD */
|
||||
{ 0x0313, KEY_PLAY }, /* PLAY */
|
||||
{ 0x0116, KEY_STOP }, /* STOP */
|
||||
{ 0x0113, KEY_PAUSE }, /* PAUSE */
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_digittrade[] = {
|
||||
|
@ -685,34 +685,34 @@ static u8 af9015_ir_table_digittrade[] = {
|
|||
|
||||
/* TREKSTOR DVB-T USB Stick */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_trekstor[] = {
|
||||
{ 0x07, 0x04, KEY_AGAIN }, /* Home */
|
||||
{ 0x07, 0x05, KEY_MUTE }, /* Mute */
|
||||
{ 0x07, 0x06, KEY_UP }, /* Up */
|
||||
{ 0x07, 0x07, KEY_DOWN }, /* Down */
|
||||
{ 0x07, 0x09, KEY_RIGHT }, /* Right */
|
||||
{ 0x07, 0x0a, KEY_ENTER }, /* OK */
|
||||
{ 0x07, 0x0b, KEY_FASTFORWARD }, /* Fast forward */
|
||||
{ 0x07, 0x0c, KEY_REWIND }, /* Rewind */
|
||||
{ 0x07, 0x0d, KEY_PLAY }, /* Play/Pause */
|
||||
{ 0x07, 0x0e, KEY_VOLUMEUP }, /* Volume + */
|
||||
{ 0x07, 0x0f, KEY_VOLUMEDOWN }, /* Volume - */
|
||||
{ 0x07, 0x10, KEY_RECORD }, /* Record */
|
||||
{ 0x07, 0x11, KEY_STOP }, /* Stop */
|
||||
{ 0x07, 0x12, KEY_ZOOM }, /* TV */
|
||||
{ 0x07, 0x13, KEY_EPG }, /* Info/EPG */
|
||||
{ 0x07, 0x14, KEY_CHANNELDOWN }, /* Channel - */
|
||||
{ 0x07, 0x15, KEY_CHANNELUP }, /* Channel + */
|
||||
{ 0x07, 0x1e, KEY_1 },
|
||||
{ 0x07, 0x1f, KEY_2 },
|
||||
{ 0x07, 0x20, KEY_3 },
|
||||
{ 0x07, 0x21, KEY_4 },
|
||||
{ 0x07, 0x22, KEY_5 },
|
||||
{ 0x07, 0x23, KEY_6 },
|
||||
{ 0x07, 0x24, KEY_7 },
|
||||
{ 0x07, 0x25, KEY_8 },
|
||||
{ 0x07, 0x26, KEY_9 },
|
||||
{ 0x07, 0x08, KEY_LEFT }, /* LEFT */
|
||||
{ 0x07, 0x27, KEY_0 },
|
||||
{ 0x0704, KEY_AGAIN }, /* Home */
|
||||
{ 0x0705, KEY_MUTE }, /* Mute */
|
||||
{ 0x0706, KEY_UP }, /* Up */
|
||||
{ 0x0707, KEY_DOWN }, /* Down */
|
||||
{ 0x0709, KEY_RIGHT }, /* Right */
|
||||
{ 0x070a, KEY_ENTER }, /* OK */
|
||||
{ 0x070b, KEY_FASTFORWARD }, /* Fast forward */
|
||||
{ 0x070c, KEY_REWIND }, /* Rewind */
|
||||
{ 0x070d, KEY_PLAY }, /* Play/Pause */
|
||||
{ 0x070e, KEY_VOLUMEUP }, /* Volume + */
|
||||
{ 0x070f, KEY_VOLUMEDOWN }, /* Volume - */
|
||||
{ 0x0710, KEY_RECORD }, /* Record */
|
||||
{ 0x0711, KEY_STOP }, /* Stop */
|
||||
{ 0x0712, KEY_ZOOM }, /* TV */
|
||||
{ 0x0713, KEY_EPG }, /* Info/EPG */
|
||||
{ 0x0714, KEY_CHANNELDOWN }, /* Channel - */
|
||||
{ 0x0715, KEY_CHANNELUP }, /* Channel + */
|
||||
{ 0x071e, KEY_1 },
|
||||
{ 0x071f, KEY_2 },
|
||||
{ 0x0720, KEY_3 },
|
||||
{ 0x0721, KEY_4 },
|
||||
{ 0x0722, KEY_5 },
|
||||
{ 0x0723, KEY_6 },
|
||||
{ 0x0724, KEY_7 },
|
||||
{ 0x0725, KEY_8 },
|
||||
{ 0x0726, KEY_9 },
|
||||
{ 0x0708, KEY_LEFT }, /* LEFT */
|
||||
{ 0x0727, KEY_0 },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_trekstor[] = {
|
||||
|
|
|
@ -389,8 +389,8 @@ static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == ircode[0] &&
|
||||
keymap[i].data == ircode[1]) {
|
||||
if (rc5_custom(&keymap[i]) == ircode[0] &&
|
||||
rc5_data(&keymap[i]) == ircode[1]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
return 0;
|
||||
|
@ -400,50 +400,50 @@ static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
}
|
||||
|
||||
static struct dvb_usb_rc_key anysee_rc_keys[] = {
|
||||
{ 0x01, 0x00, KEY_0 },
|
||||
{ 0x01, 0x01, KEY_1 },
|
||||
{ 0x01, 0x02, KEY_2 },
|
||||
{ 0x01, 0x03, KEY_3 },
|
||||
{ 0x01, 0x04, KEY_4 },
|
||||
{ 0x01, 0x05, KEY_5 },
|
||||
{ 0x01, 0x06, KEY_6 },
|
||||
{ 0x01, 0x07, KEY_7 },
|
||||
{ 0x01, 0x08, KEY_8 },
|
||||
{ 0x01, 0x09, KEY_9 },
|
||||
{ 0x01, 0x0a, KEY_POWER },
|
||||
{ 0x01, 0x0b, KEY_DOCUMENTS }, /* * */
|
||||
{ 0x01, 0x19, KEY_FAVORITES },
|
||||
{ 0x01, 0x20, KEY_SLEEP },
|
||||
{ 0x01, 0x21, KEY_MODE }, /* 4:3 / 16:9 select */
|
||||
{ 0x01, 0x22, KEY_ZOOM },
|
||||
{ 0x01, 0x47, KEY_TEXT },
|
||||
{ 0x01, 0x16, KEY_TV }, /* TV / radio select */
|
||||
{ 0x01, 0x1e, KEY_LANGUAGE }, /* Second Audio Program */
|
||||
{ 0x01, 0x1a, KEY_SUBTITLE },
|
||||
{ 0x01, 0x1b, KEY_CAMERA }, /* screenshot */
|
||||
{ 0x01, 0x42, KEY_MUTE },
|
||||
{ 0x01, 0x0e, KEY_MENU },
|
||||
{ 0x01, 0x0f, KEY_EPG },
|
||||
{ 0x01, 0x17, KEY_INFO },
|
||||
{ 0x01, 0x10, KEY_EXIT },
|
||||
{ 0x01, 0x13, KEY_VOLUMEUP },
|
||||
{ 0x01, 0x12, KEY_VOLUMEDOWN },
|
||||
{ 0x01, 0x11, KEY_CHANNELUP },
|
||||
{ 0x01, 0x14, KEY_CHANNELDOWN },
|
||||
{ 0x01, 0x15, KEY_OK },
|
||||
{ 0x01, 0x1d, KEY_RED },
|
||||
{ 0x01, 0x1f, KEY_GREEN },
|
||||
{ 0x01, 0x1c, KEY_YELLOW },
|
||||
{ 0x01, 0x44, KEY_BLUE },
|
||||
{ 0x01, 0x0c, KEY_SHUFFLE }, /* snapshot */
|
||||
{ 0x01, 0x48, KEY_STOP },
|
||||
{ 0x01, 0x50, KEY_PLAY },
|
||||
{ 0x01, 0x51, KEY_PAUSE },
|
||||
{ 0x01, 0x49, KEY_RECORD },
|
||||
{ 0x01, 0x18, KEY_PREVIOUS }, /* |<< */
|
||||
{ 0x01, 0x0d, KEY_NEXT }, /* >>| */
|
||||
{ 0x01, 0x24, KEY_PROG1 }, /* F1 */
|
||||
{ 0x01, 0x25, KEY_PROG2 }, /* F2 */
|
||||
{ 0x0100, KEY_0 },
|
||||
{ 0x0101, KEY_1 },
|
||||
{ 0x0102, KEY_2 },
|
||||
{ 0x0103, KEY_3 },
|
||||
{ 0x0104, KEY_4 },
|
||||
{ 0x0105, KEY_5 },
|
||||
{ 0x0106, KEY_6 },
|
||||
{ 0x0107, KEY_7 },
|
||||
{ 0x0108, KEY_8 },
|
||||
{ 0x0109, KEY_9 },
|
||||
{ 0x010a, KEY_POWER },
|
||||
{ 0x010b, KEY_DOCUMENTS }, /* * */
|
||||
{ 0x0119, KEY_FAVORITES },
|
||||
{ 0x0120, KEY_SLEEP },
|
||||
{ 0x0121, KEY_MODE }, /* 4:3 / 16:9 select */
|
||||
{ 0x0122, KEY_ZOOM },
|
||||
{ 0x0147, KEY_TEXT },
|
||||
{ 0x0116, KEY_TV }, /* TV / radio select */
|
||||
{ 0x011e, KEY_LANGUAGE }, /* Second Audio Program */
|
||||
{ 0x011a, KEY_SUBTITLE },
|
||||
{ 0x011b, KEY_CAMERA }, /* screenshot */
|
||||
{ 0x0142, KEY_MUTE },
|
||||
{ 0x010e, KEY_MENU },
|
||||
{ 0x010f, KEY_EPG },
|
||||
{ 0x0117, KEY_INFO },
|
||||
{ 0x0110, KEY_EXIT },
|
||||
{ 0x0113, KEY_VOLUMEUP },
|
||||
{ 0x0112, KEY_VOLUMEDOWN },
|
||||
{ 0x0111, KEY_CHANNELUP },
|
||||
{ 0x0114, KEY_CHANNELDOWN },
|
||||
{ 0x0115, KEY_OK },
|
||||
{ 0x011d, KEY_RED },
|
||||
{ 0x011f, KEY_GREEN },
|
||||
{ 0x011c, KEY_YELLOW },
|
||||
{ 0x0144, KEY_BLUE },
|
||||
{ 0x010c, KEY_SHUFFLE }, /* snapshot */
|
||||
{ 0x0148, KEY_STOP },
|
||||
{ 0x0150, KEY_PLAY },
|
||||
{ 0x0151, KEY_PAUSE },
|
||||
{ 0x0149, KEY_RECORD },
|
||||
{ 0x0118, KEY_PREVIOUS }, /* |<< */
|
||||
{ 0x010d, KEY_NEXT }, /* >>| */
|
||||
{ 0x0124, KEY_PROG1 }, /* F1 */
|
||||
{ 0x0125, KEY_PROG2 }, /* F2 */
|
||||
};
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
|
|
|
@ -85,43 +85,43 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
}
|
||||
|
||||
static struct dvb_usb_rc_key cinergyt2_rc_keys[] = {
|
||||
{ 0x04, 0x01, KEY_POWER },
|
||||
{ 0x04, 0x02, KEY_1 },
|
||||
{ 0x04, 0x03, KEY_2 },
|
||||
{ 0x04, 0x04, KEY_3 },
|
||||
{ 0x04, 0x05, KEY_4 },
|
||||
{ 0x04, 0x06, KEY_5 },
|
||||
{ 0x04, 0x07, KEY_6 },
|
||||
{ 0x04, 0x08, KEY_7 },
|
||||
{ 0x04, 0x09, KEY_8 },
|
||||
{ 0x04, 0x0a, KEY_9 },
|
||||
{ 0x04, 0x0c, KEY_0 },
|
||||
{ 0x04, 0x0b, KEY_VIDEO },
|
||||
{ 0x04, 0x0d, KEY_REFRESH },
|
||||
{ 0x04, 0x0e, KEY_SELECT },
|
||||
{ 0x04, 0x0f, KEY_EPG },
|
||||
{ 0x04, 0x10, KEY_UP },
|
||||
{ 0x04, 0x14, KEY_DOWN },
|
||||
{ 0x04, 0x11, KEY_LEFT },
|
||||
{ 0x04, 0x13, KEY_RIGHT },
|
||||
{ 0x04, 0x12, KEY_OK },
|
||||
{ 0x04, 0x15, KEY_TEXT },
|
||||
{ 0x04, 0x16, KEY_INFO },
|
||||
{ 0x04, 0x17, KEY_RED },
|
||||
{ 0x04, 0x18, KEY_GREEN },
|
||||
{ 0x04, 0x19, KEY_YELLOW },
|
||||
{ 0x04, 0x1a, KEY_BLUE },
|
||||
{ 0x04, 0x1c, KEY_VOLUMEUP },
|
||||
{ 0x04, 0x1e, KEY_VOLUMEDOWN },
|
||||
{ 0x04, 0x1d, KEY_MUTE },
|
||||
{ 0x04, 0x1b, KEY_CHANNELUP },
|
||||
{ 0x04, 0x1f, KEY_CHANNELDOWN },
|
||||
{ 0x04, 0x40, KEY_PAUSE },
|
||||
{ 0x04, 0x4c, KEY_PLAY },
|
||||
{ 0x04, 0x58, KEY_RECORD },
|
||||
{ 0x04, 0x54, KEY_PREVIOUS },
|
||||
{ 0x04, 0x48, KEY_STOP },
|
||||
{ 0x04, 0x5c, KEY_NEXT }
|
||||
{ 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 */
|
||||
|
|
|
@ -275,6 +275,7 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
|
|||
param.tps = cpu_to_le16(compute_tps(fep));
|
||||
param.freq = cpu_to_le32(fep->frequency / 1000);
|
||||
param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
|
||||
param.flags = 0;
|
||||
|
||||
err = dvb_usb_generic_rw(state->d,
|
||||
(char *)¶m, sizeof(param),
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include "mxl5005s.h"
|
||||
#include "dib7000p.h"
|
||||
#include "dib0070.h"
|
||||
#include "lgs8gl5.h"
|
||||
#include "lgs8gxx.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_cxusb_debug;
|
||||
|
@ -392,8 +392,8 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == ircode[2] &&
|
||||
keymap[i].data == ircode[3]) {
|
||||
if (rc5_custom(&keymap[i]) == ircode[2] &&
|
||||
rc5_data(&keymap[i]) == ircode[3]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
|
||||
|
@ -420,8 +420,8 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
|
|||
return 0;
|
||||
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == ircode[1] &&
|
||||
keymap[i].data == ircode[2]) {
|
||||
if (rc5_custom(&keymap[i]) == ircode[1] &&
|
||||
rc5_data(&keymap[i]) == ircode[2]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
|
||||
|
@ -446,8 +446,8 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
|
|||
return 0;
|
||||
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == ircode[0] &&
|
||||
keymap[i].data == ircode[1]) {
|
||||
if (rc5_custom(&keymap[i]) == ircode[0] &&
|
||||
rc5_data(&keymap[i]) == ircode[1]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
|
||||
|
@ -459,128 +459,128 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
|
|||
}
|
||||
|
||||
static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
|
||||
{ 0xfe, 0x02, KEY_TV },
|
||||
{ 0xfe, 0x0e, KEY_MP3 },
|
||||
{ 0xfe, 0x1a, KEY_DVD },
|
||||
{ 0xfe, 0x1e, KEY_FAVORITES },
|
||||
{ 0xfe, 0x16, KEY_SETUP },
|
||||
{ 0xfe, 0x46, KEY_POWER2 },
|
||||
{ 0xfe, 0x0a, KEY_EPG },
|
||||
{ 0xfe, 0x49, KEY_BACK },
|
||||
{ 0xfe, 0x4d, KEY_MENU },
|
||||
{ 0xfe, 0x51, KEY_UP },
|
||||
{ 0xfe, 0x5b, KEY_LEFT },
|
||||
{ 0xfe, 0x5f, KEY_RIGHT },
|
||||
{ 0xfe, 0x53, KEY_DOWN },
|
||||
{ 0xfe, 0x5e, KEY_OK },
|
||||
{ 0xfe, 0x59, KEY_INFO },
|
||||
{ 0xfe, 0x55, KEY_TAB },
|
||||
{ 0xfe, 0x0f, KEY_PREVIOUSSONG },/* Replay */
|
||||
{ 0xfe, 0x12, KEY_NEXTSONG }, /* Skip */
|
||||
{ 0xfe, 0x42, KEY_ENTER }, /* Windows/Start */
|
||||
{ 0xfe, 0x15, KEY_VOLUMEUP },
|
||||
{ 0xfe, 0x05, KEY_VOLUMEDOWN },
|
||||
{ 0xfe, 0x11, KEY_CHANNELUP },
|
||||
{ 0xfe, 0x09, KEY_CHANNELDOWN },
|
||||
{ 0xfe, 0x52, KEY_CAMERA },
|
||||
{ 0xfe, 0x5a, KEY_TUNER }, /* Live */
|
||||
{ 0xfe, 0x19, KEY_OPEN },
|
||||
{ 0xfe, 0x0b, KEY_1 },
|
||||
{ 0xfe, 0x17, KEY_2 },
|
||||
{ 0xfe, 0x1b, KEY_3 },
|
||||
{ 0xfe, 0x07, KEY_4 },
|
||||
{ 0xfe, 0x50, KEY_5 },
|
||||
{ 0xfe, 0x54, KEY_6 },
|
||||
{ 0xfe, 0x48, KEY_7 },
|
||||
{ 0xfe, 0x4c, KEY_8 },
|
||||
{ 0xfe, 0x58, KEY_9 },
|
||||
{ 0xfe, 0x13, KEY_ANGLE }, /* Aspect */
|
||||
{ 0xfe, 0x03, KEY_0 },
|
||||
{ 0xfe, 0x1f, KEY_ZOOM },
|
||||
{ 0xfe, 0x43, KEY_REWIND },
|
||||
{ 0xfe, 0x47, KEY_PLAYPAUSE },
|
||||
{ 0xfe, 0x4f, KEY_FASTFORWARD },
|
||||
{ 0xfe, 0x57, KEY_MUTE },
|
||||
{ 0xfe, 0x0d, KEY_STOP },
|
||||
{ 0xfe, 0x01, KEY_RECORD },
|
||||
{ 0xfe, 0x4e, KEY_POWER },
|
||||
{ 0xfe02, KEY_TV },
|
||||
{ 0xfe0e, KEY_MP3 },
|
||||
{ 0xfe1a, KEY_DVD },
|
||||
{ 0xfe1e, KEY_FAVORITES },
|
||||
{ 0xfe16, KEY_SETUP },
|
||||
{ 0xfe46, KEY_POWER2 },
|
||||
{ 0xfe0a, KEY_EPG },
|
||||
{ 0xfe49, KEY_BACK },
|
||||
{ 0xfe4d, KEY_MENU },
|
||||
{ 0xfe51, KEY_UP },
|
||||
{ 0xfe5b, KEY_LEFT },
|
||||
{ 0xfe5f, KEY_RIGHT },
|
||||
{ 0xfe53, KEY_DOWN },
|
||||
{ 0xfe5e, KEY_OK },
|
||||
{ 0xfe59, KEY_INFO },
|
||||
{ 0xfe55, KEY_TAB },
|
||||
{ 0xfe0f, KEY_PREVIOUSSONG },/* Replay */
|
||||
{ 0xfe12, KEY_NEXTSONG }, /* Skip */
|
||||
{ 0xfe42, KEY_ENTER }, /* Windows/Start */
|
||||
{ 0xfe15, KEY_VOLUMEUP },
|
||||
{ 0xfe05, KEY_VOLUMEDOWN },
|
||||
{ 0xfe11, KEY_CHANNELUP },
|
||||
{ 0xfe09, KEY_CHANNELDOWN },
|
||||
{ 0xfe52, KEY_CAMERA },
|
||||
{ 0xfe5a, KEY_TUNER }, /* Live */
|
||||
{ 0xfe19, KEY_OPEN },
|
||||
{ 0xfe0b, KEY_1 },
|
||||
{ 0xfe17, KEY_2 },
|
||||
{ 0xfe1b, KEY_3 },
|
||||
{ 0xfe07, KEY_4 },
|
||||
{ 0xfe50, KEY_5 },
|
||||
{ 0xfe54, KEY_6 },
|
||||
{ 0xfe48, KEY_7 },
|
||||
{ 0xfe4c, KEY_8 },
|
||||
{ 0xfe58, KEY_9 },
|
||||
{ 0xfe13, KEY_ANGLE }, /* Aspect */
|
||||
{ 0xfe03, KEY_0 },
|
||||
{ 0xfe1f, KEY_ZOOM },
|
||||
{ 0xfe43, KEY_REWIND },
|
||||
{ 0xfe47, KEY_PLAYPAUSE },
|
||||
{ 0xfe4f, KEY_FASTFORWARD },
|
||||
{ 0xfe57, KEY_MUTE },
|
||||
{ 0xfe0d, KEY_STOP },
|
||||
{ 0xfe01, KEY_RECORD },
|
||||
{ 0xfe4e, KEY_POWER },
|
||||
};
|
||||
|
||||
static struct dvb_usb_rc_key dvico_portable_rc_keys[] = {
|
||||
{ 0xfc, 0x02, KEY_SETUP }, /* Profile */
|
||||
{ 0xfc, 0x43, KEY_POWER2 },
|
||||
{ 0xfc, 0x06, KEY_EPG },
|
||||
{ 0xfc, 0x5a, KEY_BACK },
|
||||
{ 0xfc, 0x05, KEY_MENU },
|
||||
{ 0xfc, 0x47, KEY_INFO },
|
||||
{ 0xfc, 0x01, KEY_TAB },
|
||||
{ 0xfc, 0x42, KEY_PREVIOUSSONG },/* Replay */
|
||||
{ 0xfc, 0x49, KEY_VOLUMEUP },
|
||||
{ 0xfc, 0x09, KEY_VOLUMEDOWN },
|
||||
{ 0xfc, 0x54, KEY_CHANNELUP },
|
||||
{ 0xfc, 0x0b, KEY_CHANNELDOWN },
|
||||
{ 0xfc, 0x16, KEY_CAMERA },
|
||||
{ 0xfc, 0x40, KEY_TUNER }, /* ATV/DTV */
|
||||
{ 0xfc, 0x45, KEY_OPEN },
|
||||
{ 0xfc, 0x19, KEY_1 },
|
||||
{ 0xfc, 0x18, KEY_2 },
|
||||
{ 0xfc, 0x1b, KEY_3 },
|
||||
{ 0xfc, 0x1a, KEY_4 },
|
||||
{ 0xfc, 0x58, KEY_5 },
|
||||
{ 0xfc, 0x59, KEY_6 },
|
||||
{ 0xfc, 0x15, KEY_7 },
|
||||
{ 0xfc, 0x14, KEY_8 },
|
||||
{ 0xfc, 0x17, KEY_9 },
|
||||
{ 0xfc, 0x44, KEY_ANGLE }, /* Aspect */
|
||||
{ 0xfc, 0x55, KEY_0 },
|
||||
{ 0xfc, 0x07, KEY_ZOOM },
|
||||
{ 0xfc, 0x0a, KEY_REWIND },
|
||||
{ 0xfc, 0x08, KEY_PLAYPAUSE },
|
||||
{ 0xfc, 0x4b, KEY_FASTFORWARD },
|
||||
{ 0xfc, 0x5b, KEY_MUTE },
|
||||
{ 0xfc, 0x04, KEY_STOP },
|
||||
{ 0xfc, 0x56, KEY_RECORD },
|
||||
{ 0xfc, 0x57, KEY_POWER },
|
||||
{ 0xfc, 0x41, KEY_UNKNOWN }, /* INPUT */
|
||||
{ 0xfc, 0x00, KEY_UNKNOWN }, /* HD */
|
||||
{ 0xfc02, KEY_SETUP }, /* Profile */
|
||||
{ 0xfc43, KEY_POWER2 },
|
||||
{ 0xfc06, KEY_EPG },
|
||||
{ 0xfc5a, KEY_BACK },
|
||||
{ 0xfc05, KEY_MENU },
|
||||
{ 0xfc47, KEY_INFO },
|
||||
{ 0xfc01, KEY_TAB },
|
||||
{ 0xfc42, KEY_PREVIOUSSONG },/* Replay */
|
||||
{ 0xfc49, KEY_VOLUMEUP },
|
||||
{ 0xfc09, KEY_VOLUMEDOWN },
|
||||
{ 0xfc54, KEY_CHANNELUP },
|
||||
{ 0xfc0b, KEY_CHANNELDOWN },
|
||||
{ 0xfc16, KEY_CAMERA },
|
||||
{ 0xfc40, KEY_TUNER }, /* ATV/DTV */
|
||||
{ 0xfc45, KEY_OPEN },
|
||||
{ 0xfc19, KEY_1 },
|
||||
{ 0xfc18, KEY_2 },
|
||||
{ 0xfc1b, KEY_3 },
|
||||
{ 0xfc1a, KEY_4 },
|
||||
{ 0xfc58, KEY_5 },
|
||||
{ 0xfc59, KEY_6 },
|
||||
{ 0xfc15, KEY_7 },
|
||||
{ 0xfc14, KEY_8 },
|
||||
{ 0xfc17, KEY_9 },
|
||||
{ 0xfc44, KEY_ANGLE }, /* Aspect */
|
||||
{ 0xfc55, KEY_0 },
|
||||
{ 0xfc07, KEY_ZOOM },
|
||||
{ 0xfc0a, KEY_REWIND },
|
||||
{ 0xfc08, KEY_PLAYPAUSE },
|
||||
{ 0xfc4b, KEY_FASTFORWARD },
|
||||
{ 0xfc5b, KEY_MUTE },
|
||||
{ 0xfc04, KEY_STOP },
|
||||
{ 0xfc56, KEY_RECORD },
|
||||
{ 0xfc57, KEY_POWER },
|
||||
{ 0xfc41, KEY_UNKNOWN }, /* INPUT */
|
||||
{ 0xfc00, KEY_UNKNOWN }, /* HD */
|
||||
};
|
||||
|
||||
static struct dvb_usb_rc_key d680_dmb_rc_keys[] = {
|
||||
{ 0x00, 0x38, KEY_UNKNOWN }, /* TV/AV */
|
||||
{ 0x08, 0x0c, KEY_ZOOM },
|
||||
{ 0x08, 0x00, KEY_0 },
|
||||
{ 0x00, 0x01, KEY_1 },
|
||||
{ 0x08, 0x02, KEY_2 },
|
||||
{ 0x00, 0x03, KEY_3 },
|
||||
{ 0x08, 0x04, KEY_4 },
|
||||
{ 0x00, 0x05, KEY_5 },
|
||||
{ 0x08, 0x06, KEY_6 },
|
||||
{ 0x00, 0x07, KEY_7 },
|
||||
{ 0x08, 0x08, KEY_8 },
|
||||
{ 0x00, 0x09, KEY_9 },
|
||||
{ 0x00, 0x0a, KEY_MUTE },
|
||||
{ 0x08, 0x29, KEY_BACK },
|
||||
{ 0x00, 0x12, KEY_CHANNELUP },
|
||||
{ 0x08, 0x13, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x2b, KEY_VOLUMEUP },
|
||||
{ 0x08, 0x2c, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x20, KEY_UP },
|
||||
{ 0x08, 0x21, KEY_DOWN },
|
||||
{ 0x00, 0x11, KEY_LEFT },
|
||||
{ 0x08, 0x10, KEY_RIGHT },
|
||||
{ 0x00, 0x0d, KEY_OK },
|
||||
{ 0x08, 0x1f, KEY_RECORD },
|
||||
{ 0x00, 0x17, KEY_PLAYPAUSE },
|
||||
{ 0x08, 0x16, KEY_PLAYPAUSE },
|
||||
{ 0x00, 0x0b, KEY_STOP },
|
||||
{ 0x08, 0x27, KEY_FASTFORWARD },
|
||||
{ 0x00, 0x26, KEY_REWIND },
|
||||
{ 0x08, 0x1e, KEY_UNKNOWN }, /* Time Shift */
|
||||
{ 0x00, 0x0e, KEY_UNKNOWN }, /* Snapshot */
|
||||
{ 0x08, 0x2d, KEY_UNKNOWN }, /* Mouse Cursor */
|
||||
{ 0x00, 0x0f, KEY_UNKNOWN }, /* Minimize/Maximize */
|
||||
{ 0x08, 0x14, KEY_UNKNOWN }, /* Shuffle */
|
||||
{ 0x00, 0x25, KEY_POWER },
|
||||
{ 0x0038, KEY_UNKNOWN }, /* TV/AV */
|
||||
{ 0x080c, KEY_ZOOM },
|
||||
{ 0x0800, KEY_0 },
|
||||
{ 0x0001, KEY_1 },
|
||||
{ 0x0802, KEY_2 },
|
||||
{ 0x0003, KEY_3 },
|
||||
{ 0x0804, KEY_4 },
|
||||
{ 0x0005, KEY_5 },
|
||||
{ 0x0806, KEY_6 },
|
||||
{ 0x0007, KEY_7 },
|
||||
{ 0x0808, KEY_8 },
|
||||
{ 0x0009, KEY_9 },
|
||||
{ 0x000a, KEY_MUTE },
|
||||
{ 0x0829, KEY_BACK },
|
||||
{ 0x0012, KEY_CHANNELUP },
|
||||
{ 0x0813, KEY_CHANNELDOWN },
|
||||
{ 0x002b, KEY_VOLUMEUP },
|
||||
{ 0x082c, KEY_VOLUMEDOWN },
|
||||
{ 0x0020, KEY_UP },
|
||||
{ 0x0821, KEY_DOWN },
|
||||
{ 0x0011, KEY_LEFT },
|
||||
{ 0x0810, KEY_RIGHT },
|
||||
{ 0x000d, KEY_OK },
|
||||
{ 0x081f, KEY_RECORD },
|
||||
{ 0x0017, KEY_PLAYPAUSE },
|
||||
{ 0x0816, KEY_PLAYPAUSE },
|
||||
{ 0x000b, KEY_STOP },
|
||||
{ 0x0827, KEY_FASTFORWARD },
|
||||
{ 0x0026, KEY_REWIND },
|
||||
{ 0x081e, KEY_UNKNOWN }, /* Time Shift */
|
||||
{ 0x000e, KEY_UNKNOWN }, /* Snapshot */
|
||||
{ 0x082d, KEY_UNKNOWN }, /* Mouse Cursor */
|
||||
{ 0x000f, KEY_UNKNOWN }, /* Minimize/Maximize */
|
||||
{ 0x0814, KEY_UNKNOWN }, /* Shuffle */
|
||||
{ 0x0025, KEY_POWER },
|
||||
};
|
||||
|
||||
static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
|
||||
|
@ -1094,8 +1094,18 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static struct lgs8gl5_config lgs8gl5_cfg = {
|
||||
static struct lgs8gxx_config d680_lgs8gl5_cfg = {
|
||||
.prod = LGS8GXX_PROD_LGS8GL5,
|
||||
.demod_address = 0x19,
|
||||
.serial_ts = 0,
|
||||
.ts_clk_pol = 0,
|
||||
.ts_clk_gated = 1,
|
||||
.if_clk_freq = 30400, /* 30.4 MHz */
|
||||
.if_freq = 5725, /* 5.725 MHz */
|
||||
.if_neg_center = 0,
|
||||
.ext_adc = 0,
|
||||
.adc_signed = 0,
|
||||
.if_neg_edge = 0,
|
||||
};
|
||||
|
||||
static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
|
@ -1135,7 +1145,7 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
msleep(100);
|
||||
|
||||
/* Attach frontend */
|
||||
adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap);
|
||||
adap->fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap);
|
||||
if (adap->fe == NULL)
|
||||
return -EIO;
|
||||
|
||||
|
|
|
@ -310,7 +310,7 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
|
|||
struct i2c_adapter *tun_i2c;
|
||||
tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
|
||||
return dvb_attach(mt2266_attach, adap->fe, tun_i2c,
|
||||
&stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;;
|
||||
&stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
|
||||
|
@ -509,7 +509,8 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
|
|||
return 0;
|
||||
}
|
||||
for (i=0;i<d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
|
||||
if (rc5_custom(&keymap[i]) == key[3-2] &&
|
||||
rc5_data(&keymap[i]) == key[3-3]) {
|
||||
st->rc_counter = 0;
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
|
@ -522,7 +523,8 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
|
|||
default: {
|
||||
/* RC-5 protocol changes toggle bit on new keypress */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
|
||||
if (rc5_custom(&keymap[i]) == key[3-2] &&
|
||||
rc5_data(&keymap[i]) == key[3-3]) {
|
||||
if (d->last_event == keymap[i].event &&
|
||||
key[3-1] == st->rc_toggle) {
|
||||
st->rc_counter++;
|
||||
|
@ -616,8 +618,8 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
|
|||
|
||||
/* Find the key in the map */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (keymap[i].custom == poll_reply.system_lsb &&
|
||||
keymap[i].data == poll_reply.data) {
|
||||
if (rc5_custom(&keymap[i]) == poll_reply.system_lsb &&
|
||||
rc5_data(&keymap[i]) == poll_reply.data) {
|
||||
*event = keymap[i].event;
|
||||
found = 1;
|
||||
break;
|
||||
|
@ -684,193 +686,193 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
|
||||
static struct dvb_usb_rc_key dib0700_rc_keys[] = {
|
||||
/* Key codes for the tiny Pinnacle remote*/
|
||||
{ 0x07, 0x00, KEY_MUTE },
|
||||
{ 0x07, 0x01, KEY_MENU }, // Pinnacle logo
|
||||
{ 0x07, 0x39, KEY_POWER },
|
||||
{ 0x07, 0x03, KEY_VOLUMEUP },
|
||||
{ 0x07, 0x09, KEY_VOLUMEDOWN },
|
||||
{ 0x07, 0x06, KEY_CHANNELUP },
|
||||
{ 0x07, 0x0c, KEY_CHANNELDOWN },
|
||||
{ 0x07, 0x0f, KEY_1 },
|
||||
{ 0x07, 0x15, KEY_2 },
|
||||
{ 0x07, 0x10, KEY_3 },
|
||||
{ 0x07, 0x18, KEY_4 },
|
||||
{ 0x07, 0x1b, KEY_5 },
|
||||
{ 0x07, 0x1e, KEY_6 },
|
||||
{ 0x07, 0x11, KEY_7 },
|
||||
{ 0x07, 0x21, KEY_8 },
|
||||
{ 0x07, 0x12, KEY_9 },
|
||||
{ 0x07, 0x27, KEY_0 },
|
||||
{ 0x07, 0x24, KEY_SCREEN }, // 'Square' key
|
||||
{ 0x07, 0x2a, KEY_TEXT }, // 'T' key
|
||||
{ 0x07, 0x2d, KEY_REWIND },
|
||||
{ 0x07, 0x30, KEY_PLAY },
|
||||
{ 0x07, 0x33, KEY_FASTFORWARD },
|
||||
{ 0x07, 0x36, KEY_RECORD },
|
||||
{ 0x07, 0x3c, KEY_STOP },
|
||||
{ 0x07, 0x3f, KEY_CANCEL }, // '?' key
|
||||
{ 0x0700, KEY_MUTE },
|
||||
{ 0x0701, KEY_MENU }, /* Pinnacle logo */
|
||||
{ 0x0739, KEY_POWER },
|
||||
{ 0x0703, KEY_VOLUMEUP },
|
||||
{ 0x0709, KEY_VOLUMEDOWN },
|
||||
{ 0x0706, KEY_CHANNELUP },
|
||||
{ 0x070c, KEY_CHANNELDOWN },
|
||||
{ 0x070f, KEY_1 },
|
||||
{ 0x0715, KEY_2 },
|
||||
{ 0x0710, KEY_3 },
|
||||
{ 0x0718, KEY_4 },
|
||||
{ 0x071b, KEY_5 },
|
||||
{ 0x071e, KEY_6 },
|
||||
{ 0x0711, KEY_7 },
|
||||
{ 0x0721, KEY_8 },
|
||||
{ 0x0712, KEY_9 },
|
||||
{ 0x0727, KEY_0 },
|
||||
{ 0x0724, KEY_SCREEN }, /* 'Square' key */
|
||||
{ 0x072a, KEY_TEXT }, /* 'T' key */
|
||||
{ 0x072d, KEY_REWIND },
|
||||
{ 0x0730, KEY_PLAY },
|
||||
{ 0x0733, KEY_FASTFORWARD },
|
||||
{ 0x0736, KEY_RECORD },
|
||||
{ 0x073c, KEY_STOP },
|
||||
{ 0x073f, KEY_CANCEL }, /* '?' key */
|
||||
/* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
|
||||
{ 0xeb, 0x01, KEY_POWER },
|
||||
{ 0xeb, 0x02, KEY_1 },
|
||||
{ 0xeb, 0x03, KEY_2 },
|
||||
{ 0xeb, 0x04, KEY_3 },
|
||||
{ 0xeb, 0x05, KEY_4 },
|
||||
{ 0xeb, 0x06, KEY_5 },
|
||||
{ 0xeb, 0x07, KEY_6 },
|
||||
{ 0xeb, 0x08, KEY_7 },
|
||||
{ 0xeb, 0x09, KEY_8 },
|
||||
{ 0xeb, 0x0a, KEY_9 },
|
||||
{ 0xeb, 0x0b, KEY_VIDEO },
|
||||
{ 0xeb, 0x0c, KEY_0 },
|
||||
{ 0xeb, 0x0d, KEY_REFRESH },
|
||||
{ 0xeb, 0x0f, KEY_EPG },
|
||||
{ 0xeb, 0x10, KEY_UP },
|
||||
{ 0xeb, 0x11, KEY_LEFT },
|
||||
{ 0xeb, 0x12, KEY_OK },
|
||||
{ 0xeb, 0x13, KEY_RIGHT },
|
||||
{ 0xeb, 0x14, KEY_DOWN },
|
||||
{ 0xeb, 0x16, KEY_INFO },
|
||||
{ 0xeb, 0x17, KEY_RED },
|
||||
{ 0xeb, 0x18, KEY_GREEN },
|
||||
{ 0xeb, 0x19, KEY_YELLOW },
|
||||
{ 0xeb, 0x1a, KEY_BLUE },
|
||||
{ 0xeb, 0x1b, KEY_CHANNELUP },
|
||||
{ 0xeb, 0x1c, KEY_VOLUMEUP },
|
||||
{ 0xeb, 0x1d, KEY_MUTE },
|
||||
{ 0xeb, 0x1e, KEY_VOLUMEDOWN },
|
||||
{ 0xeb, 0x1f, KEY_CHANNELDOWN },
|
||||
{ 0xeb, 0x40, KEY_PAUSE },
|
||||
{ 0xeb, 0x41, KEY_HOME },
|
||||
{ 0xeb, 0x42, KEY_MENU }, /* DVD Menu */
|
||||
{ 0xeb, 0x43, KEY_SUBTITLE },
|
||||
{ 0xeb, 0x44, KEY_TEXT }, /* Teletext */
|
||||
{ 0xeb, 0x45, KEY_DELETE },
|
||||
{ 0xeb, 0x46, KEY_TV },
|
||||
{ 0xeb, 0x47, KEY_DVD },
|
||||
{ 0xeb, 0x48, KEY_STOP },
|
||||
{ 0xeb, 0x49, KEY_VIDEO },
|
||||
{ 0xeb, 0x4a, KEY_AUDIO }, /* Music */
|
||||
{ 0xeb, 0x4b, KEY_SCREEN }, /* Pic */
|
||||
{ 0xeb, 0x4c, KEY_PLAY },
|
||||
{ 0xeb, 0x4d, KEY_BACK },
|
||||
{ 0xeb, 0x4e, KEY_REWIND },
|
||||
{ 0xeb, 0x4f, KEY_FASTFORWARD },
|
||||
{ 0xeb, 0x54, KEY_PREVIOUS },
|
||||
{ 0xeb, 0x58, KEY_RECORD },
|
||||
{ 0xeb, 0x5c, KEY_NEXT },
|
||||
{ 0xeb01, KEY_POWER },
|
||||
{ 0xeb02, KEY_1 },
|
||||
{ 0xeb03, KEY_2 },
|
||||
{ 0xeb04, KEY_3 },
|
||||
{ 0xeb05, KEY_4 },
|
||||
{ 0xeb06, KEY_5 },
|
||||
{ 0xeb07, KEY_6 },
|
||||
{ 0xeb08, KEY_7 },
|
||||
{ 0xeb09, KEY_8 },
|
||||
{ 0xeb0a, KEY_9 },
|
||||
{ 0xeb0b, KEY_VIDEO },
|
||||
{ 0xeb0c, KEY_0 },
|
||||
{ 0xeb0d, KEY_REFRESH },
|
||||
{ 0xeb0f, KEY_EPG },
|
||||
{ 0xeb10, KEY_UP },
|
||||
{ 0xeb11, KEY_LEFT },
|
||||
{ 0xeb12, KEY_OK },
|
||||
{ 0xeb13, KEY_RIGHT },
|
||||
{ 0xeb14, KEY_DOWN },
|
||||
{ 0xeb16, KEY_INFO },
|
||||
{ 0xeb17, KEY_RED },
|
||||
{ 0xeb18, KEY_GREEN },
|
||||
{ 0xeb19, KEY_YELLOW },
|
||||
{ 0xeb1a, KEY_BLUE },
|
||||
{ 0xeb1b, KEY_CHANNELUP },
|
||||
{ 0xeb1c, KEY_VOLUMEUP },
|
||||
{ 0xeb1d, KEY_MUTE },
|
||||
{ 0xeb1e, KEY_VOLUMEDOWN },
|
||||
{ 0xeb1f, KEY_CHANNELDOWN },
|
||||
{ 0xeb40, KEY_PAUSE },
|
||||
{ 0xeb41, KEY_HOME },
|
||||
{ 0xeb42, KEY_MENU }, /* DVD Menu */
|
||||
{ 0xeb43, KEY_SUBTITLE },
|
||||
{ 0xeb44, KEY_TEXT }, /* Teletext */
|
||||
{ 0xeb45, KEY_DELETE },
|
||||
{ 0xeb46, KEY_TV },
|
||||
{ 0xeb47, KEY_DVD },
|
||||
{ 0xeb48, KEY_STOP },
|
||||
{ 0xeb49, KEY_VIDEO },
|
||||
{ 0xeb4a, KEY_AUDIO }, /* Music */
|
||||
{ 0xeb4b, KEY_SCREEN }, /* Pic */
|
||||
{ 0xeb4c, KEY_PLAY },
|
||||
{ 0xeb4d, KEY_BACK },
|
||||
{ 0xeb4e, KEY_REWIND },
|
||||
{ 0xeb4f, KEY_FASTFORWARD },
|
||||
{ 0xeb54, KEY_PREVIOUS },
|
||||
{ 0xeb58, KEY_RECORD },
|
||||
{ 0xeb5c, KEY_NEXT },
|
||||
|
||||
/* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
|
||||
{ 0x1e, 0x00, KEY_0 },
|
||||
{ 0x1e, 0x01, KEY_1 },
|
||||
{ 0x1e, 0x02, KEY_2 },
|
||||
{ 0x1e, 0x03, KEY_3 },
|
||||
{ 0x1e, 0x04, KEY_4 },
|
||||
{ 0x1e, 0x05, KEY_5 },
|
||||
{ 0x1e, 0x06, KEY_6 },
|
||||
{ 0x1e, 0x07, KEY_7 },
|
||||
{ 0x1e, 0x08, KEY_8 },
|
||||
{ 0x1e, 0x09, KEY_9 },
|
||||
{ 0x1e, 0x0a, KEY_KPASTERISK },
|
||||
{ 0x1e, 0x0b, KEY_RED },
|
||||
{ 0x1e, 0x0c, KEY_RADIO },
|
||||
{ 0x1e, 0x0d, KEY_MENU },
|
||||
{ 0x1e, 0x0e, KEY_GRAVE }, /* # */
|
||||
{ 0x1e, 0x0f, KEY_MUTE },
|
||||
{ 0x1e, 0x10, KEY_VOLUMEUP },
|
||||
{ 0x1e, 0x11, KEY_VOLUMEDOWN },
|
||||
{ 0x1e, 0x12, KEY_CHANNEL },
|
||||
{ 0x1e, 0x14, KEY_UP },
|
||||
{ 0x1e, 0x15, KEY_DOWN },
|
||||
{ 0x1e, 0x16, KEY_LEFT },
|
||||
{ 0x1e, 0x17, KEY_RIGHT },
|
||||
{ 0x1e, 0x18, KEY_VIDEO },
|
||||
{ 0x1e, 0x19, KEY_AUDIO },
|
||||
{ 0x1e, 0x1a, KEY_MEDIA },
|
||||
{ 0x1e, 0x1b, KEY_EPG },
|
||||
{ 0x1e, 0x1c, KEY_TV },
|
||||
{ 0x1e, 0x1e, KEY_NEXT },
|
||||
{ 0x1e, 0x1f, KEY_BACK },
|
||||
{ 0x1e, 0x20, KEY_CHANNELUP },
|
||||
{ 0x1e, 0x21, KEY_CHANNELDOWN },
|
||||
{ 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
|
||||
{ 0x1e, 0x25, KEY_OK },
|
||||
{ 0x1e, 0x29, KEY_BLUE},
|
||||
{ 0x1e, 0x2e, KEY_GREEN },
|
||||
{ 0x1e, 0x30, KEY_PAUSE },
|
||||
{ 0x1e, 0x32, KEY_REWIND },
|
||||
{ 0x1e, 0x34, KEY_FASTFORWARD },
|
||||
{ 0x1e, 0x35, KEY_PLAY },
|
||||
{ 0x1e, 0x36, KEY_STOP },
|
||||
{ 0x1e, 0x37, KEY_RECORD },
|
||||
{ 0x1e, 0x38, KEY_YELLOW },
|
||||
{ 0x1e, 0x3b, KEY_GOTO },
|
||||
{ 0x1e, 0x3d, KEY_POWER },
|
||||
{ 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_MEDIA },
|
||||
{ 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 },
|
||||
|
||||
/* Key codes for the Leadtek Winfast DTV Dongle */
|
||||
{ 0x00, 0x42, KEY_POWER },
|
||||
{ 0x07, 0x7c, KEY_TUNER },
|
||||
{ 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */
|
||||
{ 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/
|
||||
{ 0x0f, 0x71, KEY_DOT }, /* frequency */
|
||||
{ 0x07, 0x43, KEY_0 },
|
||||
{ 0x0c, 0x41, KEY_1 },
|
||||
{ 0x04, 0x43, KEY_2 },
|
||||
{ 0x0b, 0x7f, KEY_3 },
|
||||
{ 0x0e, 0x41, KEY_4 },
|
||||
{ 0x06, 0x43, KEY_5 },
|
||||
{ 0x09, 0x7f, KEY_6 },
|
||||
{ 0x0d, 0x7e, KEY_7 },
|
||||
{ 0x05, 0x7c, KEY_8 },
|
||||
{ 0x0a, 0x40, KEY_9 },
|
||||
{ 0x0e, 0x4e, KEY_CLEAR },
|
||||
{ 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */
|
||||
{ 0x0f, 0x41, KEY_LAST }, /* recall */
|
||||
{ 0x03, 0x42, KEY_MUTE },
|
||||
{ 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/
|
||||
{ 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */
|
||||
{ 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
|
||||
{ 0x0b, 0x70, KEY_RECORD },
|
||||
{ 0x03, 0x7d, KEY_VOLUMEUP },
|
||||
{ 0x01, 0x7d, KEY_VOLUMEDOWN },
|
||||
{ 0x02, 0x42, KEY_CHANNELUP },
|
||||
{ 0x00, 0x7d, KEY_CHANNELDOWN },
|
||||
{ 0x0042, KEY_POWER },
|
||||
{ 0x077c, KEY_TUNER },
|
||||
{ 0x0f4e, KEY_PRINT }, /* PREVIEW */
|
||||
{ 0x0840, KEY_SCREEN }, /* full screen toggle*/
|
||||
{ 0x0f71, KEY_DOT }, /* frequency */
|
||||
{ 0x0743, KEY_0 },
|
||||
{ 0x0c41, KEY_1 },
|
||||
{ 0x0443, KEY_2 },
|
||||
{ 0x0b7f, KEY_3 },
|
||||
{ 0x0e41, KEY_4 },
|
||||
{ 0x0643, KEY_5 },
|
||||
{ 0x097f, KEY_6 },
|
||||
{ 0x0d7e, KEY_7 },
|
||||
{ 0x057c, KEY_8 },
|
||||
{ 0x0a40, KEY_9 },
|
||||
{ 0x0e4e, KEY_CLEAR },
|
||||
{ 0x047c, KEY_CHANNEL }, /* show channel number */
|
||||
{ 0x0f41, KEY_LAST }, /* recall */
|
||||
{ 0x0342, KEY_MUTE },
|
||||
{ 0x064c, KEY_RESERVED }, /* PIP button*/
|
||||
{ 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
|
||||
{ 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
|
||||
{ 0x0b70, KEY_RECORD },
|
||||
{ 0x037d, KEY_VOLUMEUP },
|
||||
{ 0x017d, KEY_VOLUMEDOWN },
|
||||
{ 0x0242, KEY_CHANNELUP },
|
||||
{ 0x007d, KEY_CHANNELDOWN },
|
||||
|
||||
/* Key codes for Nova-TD "credit card" remote control. */
|
||||
{ 0x1d, 0x00, KEY_0 },
|
||||
{ 0x1d, 0x01, KEY_1 },
|
||||
{ 0x1d, 0x02, KEY_2 },
|
||||
{ 0x1d, 0x03, KEY_3 },
|
||||
{ 0x1d, 0x04, KEY_4 },
|
||||
{ 0x1d, 0x05, KEY_5 },
|
||||
{ 0x1d, 0x06, KEY_6 },
|
||||
{ 0x1d, 0x07, KEY_7 },
|
||||
{ 0x1d, 0x08, KEY_8 },
|
||||
{ 0x1d, 0x09, KEY_9 },
|
||||
{ 0x1d, 0x0a, KEY_TEXT },
|
||||
{ 0x1d, 0x0d, KEY_MENU },
|
||||
{ 0x1d, 0x0f, KEY_MUTE },
|
||||
{ 0x1d, 0x10, KEY_VOLUMEUP },
|
||||
{ 0x1d, 0x11, KEY_VOLUMEDOWN },
|
||||
{ 0x1d, 0x12, KEY_CHANNEL },
|
||||
{ 0x1d, 0x14, KEY_UP },
|
||||
{ 0x1d, 0x15, KEY_DOWN },
|
||||
{ 0x1d, 0x16, KEY_LEFT },
|
||||
{ 0x1d, 0x17, KEY_RIGHT },
|
||||
{ 0x1d, 0x1c, KEY_TV },
|
||||
{ 0x1d, 0x1e, KEY_NEXT },
|
||||
{ 0x1d, 0x1f, KEY_BACK },
|
||||
{ 0x1d, 0x20, KEY_CHANNELUP },
|
||||
{ 0x1d, 0x21, KEY_CHANNELDOWN },
|
||||
{ 0x1d, 0x24, KEY_LAST },
|
||||
{ 0x1d, 0x25, KEY_OK },
|
||||
{ 0x1d, 0x30, KEY_PAUSE },
|
||||
{ 0x1d, 0x32, KEY_REWIND },
|
||||
{ 0x1d, 0x34, KEY_FASTFORWARD },
|
||||
{ 0x1d, 0x35, KEY_PLAY },
|
||||
{ 0x1d, 0x36, KEY_STOP },
|
||||
{ 0x1d, 0x37, KEY_RECORD },
|
||||
{ 0x1d, 0x3b, KEY_GOTO },
|
||||
{ 0x1d, 0x3d, KEY_POWER },
|
||||
{ 0x1d00, KEY_0 },
|
||||
{ 0x1d01, KEY_1 },
|
||||
{ 0x1d02, KEY_2 },
|
||||
{ 0x1d03, KEY_3 },
|
||||
{ 0x1d04, KEY_4 },
|
||||
{ 0x1d05, KEY_5 },
|
||||
{ 0x1d06, KEY_6 },
|
||||
{ 0x1d07, KEY_7 },
|
||||
{ 0x1d08, KEY_8 },
|
||||
{ 0x1d09, KEY_9 },
|
||||
{ 0x1d0a, KEY_TEXT },
|
||||
{ 0x1d0d, KEY_MENU },
|
||||
{ 0x1d0f, KEY_MUTE },
|
||||
{ 0x1d10, KEY_VOLUMEUP },
|
||||
{ 0x1d11, KEY_VOLUMEDOWN },
|
||||
{ 0x1d12, KEY_CHANNEL },
|
||||
{ 0x1d14, KEY_UP },
|
||||
{ 0x1d15, KEY_DOWN },
|
||||
{ 0x1d16, KEY_LEFT },
|
||||
{ 0x1d17, KEY_RIGHT },
|
||||
{ 0x1d1c, KEY_TV },
|
||||
{ 0x1d1e, KEY_NEXT },
|
||||
{ 0x1d1f, KEY_BACK },
|
||||
{ 0x1d20, KEY_CHANNELUP },
|
||||
{ 0x1d21, KEY_CHANNELDOWN },
|
||||
{ 0x1d24, KEY_LAST },
|
||||
{ 0x1d25, KEY_OK },
|
||||
{ 0x1d30, KEY_PAUSE },
|
||||
{ 0x1d32, KEY_REWIND },
|
||||
{ 0x1d34, KEY_FASTFORWARD },
|
||||
{ 0x1d35, KEY_PLAY },
|
||||
{ 0x1d36, KEY_STOP },
|
||||
{ 0x1d37, KEY_RECORD },
|
||||
{ 0x1d3b, KEY_GOTO },
|
||||
{ 0x1d3d, KEY_POWER },
|
||||
};
|
||||
|
||||
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
|
||||
|
@ -1497,6 +1499,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
|
|||
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) },
|
||||
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) },
|
||||
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) },
|
||||
{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) },
|
||||
{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) },
|
||||
{ 0 } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
|
||||
|
@ -1624,7 +1628,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
}
|
||||
},
|
||||
|
||||
.num_device_descs = 4,
|
||||
.num_device_descs = 5,
|
||||
.devices = {
|
||||
{ "Pinnacle PCTV 2000e",
|
||||
{ &dib0700_usb_id_table[11], NULL },
|
||||
|
@ -1642,6 +1646,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
{ &dib0700_usb_id_table[14], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "YUAN High-Tech DiBcom STK7700D",
|
||||
{ &dib0700_usb_id_table[55], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
|
@ -1822,7 +1830,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 8,
|
||||
.num_device_descs = 9,
|
||||
.devices = {
|
||||
{ "Terratec Cinergy HT USB XE",
|
||||
{ &dib0700_usb_id_table[27], NULL },
|
||||
|
@ -1856,7 +1864,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
{ &dib0700_usb_id_table[51], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
|
||||
{ "YUAN High-Tech STK7700D",
|
||||
{ &dib0700_usb_id_table[54], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
},
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
.rc_key_map = dib0700_rc_keys,
|
||||
|
|
|
@ -318,132 +318,132 @@ EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
|
|||
*/
|
||||
struct dvb_usb_rc_key dibusb_rc_keys[] = {
|
||||
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
|
||||
{ 0x00, 0x16, KEY_POWER },
|
||||
{ 0x00, 0x10, KEY_MUTE },
|
||||
{ 0x00, 0x03, KEY_1 },
|
||||
{ 0x00, 0x01, KEY_2 },
|
||||
{ 0x00, 0x06, KEY_3 },
|
||||
{ 0x00, 0x09, KEY_4 },
|
||||
{ 0x00, 0x1d, KEY_5 },
|
||||
{ 0x00, 0x1f, KEY_6 },
|
||||
{ 0x00, 0x0d, KEY_7 },
|
||||
{ 0x00, 0x19, KEY_8 },
|
||||
{ 0x00, 0x1b, KEY_9 },
|
||||
{ 0x00, 0x15, KEY_0 },
|
||||
{ 0x00, 0x05, KEY_CHANNELUP },
|
||||
{ 0x00, 0x02, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x1e, KEY_VOLUMEUP },
|
||||
{ 0x00, 0x0a, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x11, KEY_RECORD },
|
||||
{ 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
|
||||
{ 0x00, 0x14, KEY_PLAY },
|
||||
{ 0x00, 0x1a, KEY_STOP },
|
||||
{ 0x00, 0x40, KEY_REWIND },
|
||||
{ 0x00, 0x12, KEY_FASTFORWARD },
|
||||
{ 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
|
||||
{ 0x00, 0x4c, KEY_PAUSE },
|
||||
{ 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
|
||||
{ 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
|
||||
{ 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 */
|
||||
{ 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
|
||||
{ 0x00, 0x1c, KEY_EPG }, /* EPG */
|
||||
{ 0x00, 0x00, KEY_TAB }, /* Tab */
|
||||
{ 0x00, 0x48, KEY_INFO }, /* Preview */
|
||||
{ 0x00, 0x04, KEY_LIST }, /* RecordList */
|
||||
{ 0x00, 0x0f, KEY_TEXT }, /* Teletext */
|
||||
{ 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. */
|
||||
{ 0x86, 0x12, KEY_POWER },
|
||||
{ 0x86, 0x0f, KEY_SELECT }, /* source */
|
||||
{ 0x86, 0x0c, KEY_UNKNOWN }, /* scan */
|
||||
{ 0x86, 0x0b, KEY_EPG },
|
||||
{ 0x86, 0x10, KEY_MUTE },
|
||||
{ 0x86, 0x01, KEY_1 },
|
||||
{ 0x86, 0x02, KEY_2 },
|
||||
{ 0x86, 0x03, KEY_3 },
|
||||
{ 0x86, 0x04, KEY_4 },
|
||||
{ 0x86, 0x05, KEY_5 },
|
||||
{ 0x86, 0x06, KEY_6 },
|
||||
{ 0x86, 0x07, KEY_7 },
|
||||
{ 0x86, 0x08, KEY_8 },
|
||||
{ 0x86, 0x09, KEY_9 },
|
||||
{ 0x86, 0x0a, KEY_0 },
|
||||
{ 0x86, 0x18, KEY_ZOOM },
|
||||
{ 0x86, 0x1c, KEY_UNKNOWN }, /* preview */
|
||||
{ 0x86, 0x13, KEY_UNKNOWN }, /* snap */
|
||||
{ 0x86, 0x00, KEY_UNDO },
|
||||
{ 0x86, 0x1d, KEY_RECORD },
|
||||
{ 0x86, 0x0d, KEY_STOP },
|
||||
{ 0x86, 0x0e, KEY_PAUSE },
|
||||
{ 0x86, 0x16, KEY_PLAY },
|
||||
{ 0x86, 0x11, KEY_BACK },
|
||||
{ 0x86, 0x19, KEY_FORWARD },
|
||||
{ 0x86, 0x14, KEY_UNKNOWN }, /* pip */
|
||||
{ 0x86, 0x15, KEY_ESC },
|
||||
{ 0x86, 0x1a, KEY_UP },
|
||||
{ 0x86, 0x1e, KEY_DOWN },
|
||||
{ 0x86, 0x1f, KEY_LEFT },
|
||||
{ 0x86, 0x1b, KEY_RIGHT },
|
||||
{ 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. */
|
||||
{ 0x80, 0x00, KEY_MUTE },
|
||||
{ 0x80, 0x01, KEY_TEXT },
|
||||
{ 0x80, 0x02, KEY_HOME },
|
||||
{ 0x80, 0x03, KEY_POWER },
|
||||
{ 0x8000, KEY_MUTE },
|
||||
{ 0x8001, KEY_TEXT },
|
||||
{ 0x8002, KEY_HOME },
|
||||
{ 0x8003, KEY_POWER },
|
||||
|
||||
{ 0x80, 0x04, KEY_RED },
|
||||
{ 0x80, 0x05, KEY_GREEN },
|
||||
{ 0x80, 0x06, KEY_YELLOW },
|
||||
{ 0x80, 0x07, KEY_BLUE },
|
||||
{ 0x8004, KEY_RED },
|
||||
{ 0x8005, KEY_GREEN },
|
||||
{ 0x8006, KEY_YELLOW },
|
||||
{ 0x8007, KEY_BLUE },
|
||||
|
||||
{ 0x80, 0x08, KEY_DVD },
|
||||
{ 0x80, 0x09, KEY_AUDIO },
|
||||
{ 0x80, 0x0a, KEY_MEDIA }, /* Pictures */
|
||||
{ 0x80, 0x0b, KEY_VIDEO },
|
||||
{ 0x8008, KEY_DVD },
|
||||
{ 0x8009, KEY_AUDIO },
|
||||
{ 0x800a, KEY_MEDIA }, /* Pictures */
|
||||
{ 0x800b, KEY_VIDEO },
|
||||
|
||||
{ 0x80, 0x0c, KEY_BACK },
|
||||
{ 0x80, 0x0d, KEY_UP },
|
||||
{ 0x80, 0x0e, KEY_RADIO },
|
||||
{ 0x80, 0x0f, KEY_EPG },
|
||||
{ 0x800c, KEY_BACK },
|
||||
{ 0x800d, KEY_UP },
|
||||
{ 0x800e, KEY_RADIO },
|
||||
{ 0x800f, KEY_EPG },
|
||||
|
||||
{ 0x80, 0x10, KEY_LEFT },
|
||||
{ 0x80, 0x11, KEY_OK },
|
||||
{ 0x80, 0x12, KEY_RIGHT },
|
||||
{ 0x80, 0x13, KEY_UNKNOWN }, /* SAP */
|
||||
{ 0x8010, KEY_LEFT },
|
||||
{ 0x8011, KEY_OK },
|
||||
{ 0x8012, KEY_RIGHT },
|
||||
{ 0x8013, KEY_UNKNOWN }, /* SAP */
|
||||
|
||||
{ 0x80, 0x14, KEY_TV },
|
||||
{ 0x80, 0x15, KEY_DOWN },
|
||||
{ 0x80, 0x16, KEY_MENU }, /* DVD Menu */
|
||||
{ 0x80, 0x17, KEY_LAST },
|
||||
{ 0x8014, KEY_TV },
|
||||
{ 0x8015, KEY_DOWN },
|
||||
{ 0x8016, KEY_MENU }, /* DVD Menu */
|
||||
{ 0x8017, KEY_LAST },
|
||||
|
||||
{ 0x80, 0x18, KEY_RECORD },
|
||||
{ 0x80, 0x19, KEY_STOP },
|
||||
{ 0x80, 0x1a, KEY_PAUSE },
|
||||
{ 0x80, 0x1b, KEY_PLAY },
|
||||
{ 0x8018, KEY_RECORD },
|
||||
{ 0x8019, KEY_STOP },
|
||||
{ 0x801a, KEY_PAUSE },
|
||||
{ 0x801b, KEY_PLAY },
|
||||
|
||||
{ 0x80, 0x1c, KEY_PREVIOUS },
|
||||
{ 0x80, 0x1d, KEY_REWIND },
|
||||
{ 0x80, 0x1e, KEY_FASTFORWARD },
|
||||
{ 0x80, 0x1f, KEY_NEXT},
|
||||
{ 0x801c, KEY_PREVIOUS },
|
||||
{ 0x801d, KEY_REWIND },
|
||||
{ 0x801e, KEY_FASTFORWARD },
|
||||
{ 0x801f, KEY_NEXT},
|
||||
|
||||
{ 0x80, 0x40, KEY_1 },
|
||||
{ 0x80, 0x41, KEY_2 },
|
||||
{ 0x80, 0x42, KEY_3 },
|
||||
{ 0x80, 0x43, KEY_CHANNELUP },
|
||||
{ 0x8040, KEY_1 },
|
||||
{ 0x8041, KEY_2 },
|
||||
{ 0x8042, KEY_3 },
|
||||
{ 0x8043, KEY_CHANNELUP },
|
||||
|
||||
{ 0x80, 0x44, KEY_4 },
|
||||
{ 0x80, 0x45, KEY_5 },
|
||||
{ 0x80, 0x46, KEY_6 },
|
||||
{ 0x80, 0x47, KEY_CHANNELDOWN },
|
||||
{ 0x8044, KEY_4 },
|
||||
{ 0x8045, KEY_5 },
|
||||
{ 0x8046, KEY_6 },
|
||||
{ 0x8047, KEY_CHANNELDOWN },
|
||||
|
||||
{ 0x80, 0x48, KEY_7 },
|
||||
{ 0x80, 0x49, KEY_8 },
|
||||
{ 0x80, 0x4a, KEY_9 },
|
||||
{ 0x80, 0x4b, KEY_VOLUMEUP },
|
||||
{ 0x8048, KEY_7 },
|
||||
{ 0x8049, KEY_8 },
|
||||
{ 0x804a, KEY_9 },
|
||||
{ 0x804b, KEY_VOLUMEUP },
|
||||
|
||||
{ 0x80, 0x4c, KEY_CLEAR },
|
||||
{ 0x80, 0x4d, KEY_0 },
|
||||
{ 0x80, 0x4e, KEY_ENTER },
|
||||
{ 0x80, 0x4f, KEY_VOLUMEDOWN },
|
||||
{ 0x804c, KEY_CLEAR },
|
||||
{ 0x804d, KEY_0 },
|
||||
{ 0x804e, KEY_ENTER },
|
||||
{ 0x804f, KEY_VOLUMEDOWN },
|
||||
};
|
||||
EXPORT_SYMBOL(dibusb_rc_keys);
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ static struct usb_device_id dibusb_dib3000mc_table [] = {
|
|||
/* 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);
|
||||
|
@ -66,7 +68,7 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
|
|||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.count = 8,
|
||||
.endpoint = 0x06,
|
||||
.u = {
|
||||
.bulk = {
|
||||
|
@ -88,7 +90,7 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
|
|||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.num_device_descs = 7,
|
||||
.num_device_descs = 8,
|
||||
.devices = {
|
||||
{ "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
|
||||
{ &dibusb_dib3000mc_table[0], NULL },
|
||||
|
@ -119,6 +121,10 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
|
|||
{ &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 },
|
||||
}
|
||||
};
|
||||
|
|
|
@ -162,61 +162,61 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
|
|||
}
|
||||
|
||||
static struct dvb_usb_rc_key digitv_rc_keys[] = {
|
||||
{ 0x5f, 0x55, KEY_0 },
|
||||
{ 0x6f, 0x55, KEY_1 },
|
||||
{ 0x9f, 0x55, KEY_2 },
|
||||
{ 0xaf, 0x55, KEY_3 },
|
||||
{ 0x5f, 0x56, KEY_4 },
|
||||
{ 0x6f, 0x56, KEY_5 },
|
||||
{ 0x9f, 0x56, KEY_6 },
|
||||
{ 0xaf, 0x56, KEY_7 },
|
||||
{ 0x5f, 0x59, KEY_8 },
|
||||
{ 0x6f, 0x59, KEY_9 },
|
||||
{ 0x9f, 0x59, KEY_TV },
|
||||
{ 0xaf, 0x59, KEY_AUX },
|
||||
{ 0x5f, 0x5a, KEY_DVD },
|
||||
{ 0x6f, 0x5a, KEY_POWER },
|
||||
{ 0x9f, 0x5a, KEY_MHP }, /* labelled 'Picture' */
|
||||
{ 0xaf, 0x5a, KEY_AUDIO },
|
||||
{ 0x5f, 0x65, KEY_INFO },
|
||||
{ 0x6f, 0x65, KEY_F13 }, /* 16:9 */
|
||||
{ 0x9f, 0x65, KEY_F14 }, /* 14:9 */
|
||||
{ 0xaf, 0x65, KEY_EPG },
|
||||
{ 0x5f, 0x66, KEY_EXIT },
|
||||
{ 0x6f, 0x66, KEY_MENU },
|
||||
{ 0x9f, 0x66, KEY_UP },
|
||||
{ 0xaf, 0x66, KEY_DOWN },
|
||||
{ 0x5f, 0x69, KEY_LEFT },
|
||||
{ 0x6f, 0x69, KEY_RIGHT },
|
||||
{ 0x9f, 0x69, KEY_ENTER },
|
||||
{ 0xaf, 0x69, KEY_CHANNELUP },
|
||||
{ 0x5f, 0x6a, KEY_CHANNELDOWN },
|
||||
{ 0x6f, 0x6a, KEY_VOLUMEUP },
|
||||
{ 0x9f, 0x6a, KEY_VOLUMEDOWN },
|
||||
{ 0xaf, 0x6a, KEY_RED },
|
||||
{ 0x5f, 0x95, KEY_GREEN },
|
||||
{ 0x6f, 0x95, KEY_YELLOW },
|
||||
{ 0x9f, 0x95, KEY_BLUE },
|
||||
{ 0xaf, 0x95, KEY_SUBTITLE },
|
||||
{ 0x5f, 0x96, KEY_F15 }, /* AD */
|
||||
{ 0x6f, 0x96, KEY_TEXT },
|
||||
{ 0x9f, 0x96, KEY_MUTE },
|
||||
{ 0xaf, 0x96, KEY_REWIND },
|
||||
{ 0x5f, 0x99, KEY_STOP },
|
||||
{ 0x6f, 0x99, KEY_PLAY },
|
||||
{ 0x9f, 0x99, KEY_FASTFORWARD },
|
||||
{ 0xaf, 0x99, KEY_F16 }, /* chapter */
|
||||
{ 0x5f, 0x9a, KEY_PAUSE },
|
||||
{ 0x6f, 0x9a, KEY_PLAY },
|
||||
{ 0x9f, 0x9a, KEY_RECORD },
|
||||
{ 0xaf, 0x9a, KEY_F17 }, /* picture in picture */
|
||||
{ 0x5f, 0xa5, KEY_KPPLUS }, /* zoom in */
|
||||
{ 0x6f, 0xa5, KEY_KPMINUS }, /* zoom out */
|
||||
{ 0x9f, 0xa5, KEY_F18 }, /* capture */
|
||||
{ 0xaf, 0xa5, KEY_F19 }, /* web */
|
||||
{ 0x5f, 0xa6, KEY_EMAIL },
|
||||
{ 0x6f, 0xa6, KEY_PHONE },
|
||||
{ 0x9f, 0xa6, KEY_PC },
|
||||
{ 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_MHP }, /* 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)
|
||||
|
@ -238,8 +238,8 @@ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
if (key[1] != 0)
|
||||
{
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (d->props.rc_key_map[i].custom == key[1] &&
|
||||
d->props.rc_key_map[i].data == key[2]) {
|
||||
if (rc5_custom(&d->props.rc_key_map[i]) == key[1] &&
|
||||
rc5_data(&d->props.rc_key_map[i]) == key[2]) {
|
||||
*event = d->props.rc_key_map[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
return 0;
|
||||
|
|
|
@ -58,24 +58,24 @@ static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
|
|||
/* remote control */
|
||||
/* key list for the tiny remote control (Yakumo, don't know about the others) */
|
||||
static struct dvb_usb_rc_key dtt200u_rc_keys[] = {
|
||||
{ 0x80, 0x01, KEY_MUTE },
|
||||
{ 0x80, 0x02, KEY_CHANNELDOWN },
|
||||
{ 0x80, 0x03, KEY_VOLUMEDOWN },
|
||||
{ 0x80, 0x04, KEY_1 },
|
||||
{ 0x80, 0x05, KEY_2 },
|
||||
{ 0x80, 0x06, KEY_3 },
|
||||
{ 0x80, 0x07, KEY_4 },
|
||||
{ 0x80, 0x08, KEY_5 },
|
||||
{ 0x80, 0x09, KEY_6 },
|
||||
{ 0x80, 0x0a, KEY_7 },
|
||||
{ 0x80, 0x0c, KEY_ZOOM },
|
||||
{ 0x80, 0x0d, KEY_0 },
|
||||
{ 0x80, 0x0e, KEY_SELECT },
|
||||
{ 0x80, 0x12, KEY_POWER },
|
||||
{ 0x80, 0x1a, KEY_CHANNELUP },
|
||||
{ 0x80, 0x1b, KEY_8 },
|
||||
{ 0x80, 0x1e, KEY_VOLUMEUP },
|
||||
{ 0x80, 0x1f, KEY_9 },
|
||||
{ 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)
|
||||
|
|
|
@ -19,7 +19,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
|
||||
strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
|
||||
d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
|
||||
d->i2c_adap.algo = d->props.i2c_algo;
|
||||
d->i2c_adap.algo_data = NULL;
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#define USB_VID_GIGABYTE 0x1044
|
||||
#define USB_VID_YUAN 0x1164
|
||||
#define USB_VID_XTENSIONS 0x1ae7
|
||||
#define USB_VID_HUMAX_COEX 0x10b9
|
||||
|
||||
/* Product IDs */
|
||||
#define USB_PID_ADSTECH_USB2_COLD 0xa333
|
||||
|
@ -103,6 +104,7 @@
|
|||
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
|
||||
#define USB_PID_INTEL_CE9500 0x9500
|
||||
#define USB_PID_KWORLD_399U 0xe399
|
||||
#define USB_PID_KWORLD_399U_2 0xe400
|
||||
#define USB_PID_KWORLD_395U 0xe396
|
||||
#define USB_PID_KWORLD_395U_2 0xe39b
|
||||
#define USB_PID_KWORLD_395U_3 0xe395
|
||||
|
@ -252,6 +254,8 @@
|
|||
#define USB_PID_YUAN_STK7700PH 0x1f08
|
||||
#define USB_PID_YUAN_PD378S 0x2edc
|
||||
#define USB_PID_YUAN_MC770 0x0871
|
||||
#define USB_PID_YUAN_STK7700D 0x1efc
|
||||
#define USB_PID_YUAN_STK7700D_2 0x1e8c
|
||||
#define USB_PID_DW2102 0x2102
|
||||
#define USB_PID_XTENSIONS_XD_380 0x0381
|
||||
#define USB_PID_TELESTAR_STARSTICK_2 0x8000
|
||||
|
@ -259,5 +263,7 @@
|
|||
#define USB_PID_SONY_PLAYTV 0x0003
|
||||
#define USB_PID_ELGATO_EYETV_DTT 0x0021
|
||||
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,71 @@
|
|||
#include "dvb-usb-common.h"
|
||||
#include <linux/usb/input.h>
|
||||
|
||||
static int dvb_usb_getkeycode(struct input_dev *dev,
|
||||
int scancode, int *keycode)
|
||||
{
|
||||
struct dvb_usb_device *d = input_get_drvdata(dev);
|
||||
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
int i;
|
||||
|
||||
/* See if we can match the raw key code. */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++)
|
||||
if (keymap[i].scan == scancode) {
|
||||
*keycode = keymap[i].event;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If is there extra space, returns KEY_RESERVED,
|
||||
* otherwise, input core won't let dvb_usb_setkeycode
|
||||
* to work
|
||||
*/
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++)
|
||||
if (keymap[i].event == KEY_RESERVED ||
|
||||
keymap[i].event == KEY_UNKNOWN) {
|
||||
*keycode = KEY_RESERVED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dvb_usb_setkeycode(struct input_dev *dev,
|
||||
int scancode, int keycode)
|
||||
{
|
||||
struct dvb_usb_device *d = input_get_drvdata(dev);
|
||||
|
||||
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
|
||||
int i;
|
||||
|
||||
/* Search if it is replacing an existing keycode */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++)
|
||||
if (keymap[i].scan == scancode) {
|
||||
keymap[i].event = keycode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search if is there a clean entry. If so, use it */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++)
|
||||
if (keymap[i].event == KEY_RESERVED ||
|
||||
keymap[i].event == KEY_UNKNOWN) {
|
||||
keymap[i].scan = scancode;
|
||||
keymap[i].event = keycode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Remote-control poll function - called every dib->rc_query_interval ms to see
|
||||
* whether the remote control has received anything.
|
||||
*
|
||||
|
@ -111,6 +176,8 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
|
|||
input_dev->phys = d->rc_phys;
|
||||
usb_to_input_id(d->udev, &input_dev->id);
|
||||
input_dev->dev.parent = &d->udev->dev;
|
||||
input_dev->getkeycode = dvb_usb_getkeycode;
|
||||
input_dev->setkeycode = dvb_usb_setkeycode;
|
||||
|
||||
/* set the bits for the keys */
|
||||
deb_rc("key map size: %d\n", d->props.rc_key_map_size);
|
||||
|
@ -128,6 +195,8 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
|
|||
input_dev->rep[REP_PERIOD] = d->props.rc_interval;
|
||||
input_dev->rep[REP_DELAY] = d->props.rc_interval + 150;
|
||||
|
||||
input_set_drvdata(input_dev, d);
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
input_free_device(input_dev);
|
||||
|
@ -178,8 +247,8 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
|
|||
}
|
||||
/* See if we can match the raw key code. */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++)
|
||||
if (keymap[i].custom == keybuf[1] &&
|
||||
keymap[i].data == keybuf[3]) {
|
||||
if (rc5_custom(&keymap[i]) == keybuf[1] &&
|
||||
rc5_data(&keymap[i]) == keybuf[3]) {
|
||||
*event = keymap[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
return 0;
|
||||
|
|
|
@ -81,10 +81,25 @@ struct dvb_usb_device_description {
|
|||
* @event: the input event assigned to key identified by custom and data
|
||||
*/
|
||||
struct dvb_usb_rc_key {
|
||||
u8 custom,data;
|
||||
u16 scan;
|
||||
u32 event;
|
||||
};
|
||||
|
||||
static inline u8 rc5_custom(struct dvb_usb_rc_key *key)
|
||||
{
|
||||
return (key->scan >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static inline u8 rc5_data(struct dvb_usb_rc_key *key)
|
||||
{
|
||||
return key->scan & 0xff;
|
||||
}
|
||||
|
||||
static inline u8 rc5_scan(struct dvb_usb_rc_key *key)
|
||||
{
|
||||
return key->scan & 0xffff;
|
||||
}
|
||||
|
||||
struct dvb_usb_device;
|
||||
struct dvb_usb_adapter;
|
||||
struct usb_data_stream;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* DVB USB framework compliant Linux driver for the
|
||||
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
|
||||
* TeVii S600, S650 Cards
|
||||
* TeVii S600, S630, S650 Cards
|
||||
* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
@ -18,6 +18,8 @@
|
|||
#include "eds1547.h"
|
||||
#include "cx24116.h"
|
||||
#include "tda1002x.h"
|
||||
#include "mt312.h"
|
||||
#include "zl10039.h"
|
||||
|
||||
#ifndef USB_PID_DW2102
|
||||
#define USB_PID_DW2102 0x2102
|
||||
|
@ -39,6 +41,10 @@
|
|||
#define USB_PID_TEVII_S650 0xd650
|
||||
#endif
|
||||
|
||||
#ifndef USB_PID_TEVII_S630
|
||||
#define USB_PID_TEVII_S630 0xd630
|
||||
#endif
|
||||
|
||||
#define DW210X_READ_MSG 0
|
||||
#define DW210X_WRITE_MSG 1
|
||||
|
||||
|
@ -436,6 +442,69 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
|||
return num;
|
||||
}
|
||||
|
||||
static int s630_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int ret = 0;
|
||||
|
||||
if (!d)
|
||||
return -ENODEV;
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
switch (num) {
|
||||
case 2: { /* read */
|
||||
u8 ibuf[msg[1].len], obuf[3];
|
||||
obuf[0] = msg[1].len;
|
||||
obuf[1] = (msg[0].addr << 1);
|
||||
obuf[2] = msg[0].buf[0];
|
||||
|
||||
ret = dw210x_op_rw(d->udev, 0x90, 0, 0,
|
||||
obuf, 3, DW210X_WRITE_MSG);
|
||||
msleep(5);
|
||||
ret = dw210x_op_rw(d->udev, 0x91, 0, 0,
|
||||
ibuf, msg[1].len, DW210X_READ_MSG);
|
||||
memcpy(msg[1].buf, ibuf, msg[1].len);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
switch (msg[0].addr) {
|
||||
case 0x60:
|
||||
case 0x0e: {
|
||||
/* write to zl10313, zl10039 register, */
|
||||
u8 obuf[msg[0].len + 2];
|
||||
obuf[0] = msg[0].len + 1;
|
||||
obuf[1] = (msg[0].addr << 1);
|
||||
memcpy(obuf + 2, msg[0].buf, msg[0].len);
|
||||
ret = dw210x_op_rw(d->udev, 0x80, 0, 0,
|
||||
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
}
|
||||
case (DW2102_RC_QUERY): {
|
||||
u8 ibuf[4];
|
||||
ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
|
||||
ibuf, 4, DW210X_READ_MSG);
|
||||
msg[0].buf[0] = ibuf[3];
|
||||
break;
|
||||
}
|
||||
case (DW2102_VOLTAGE_CTRL): {
|
||||
u8 obuf[2];
|
||||
obuf[0] = 0x03;
|
||||
obuf[1] = msg[0].buf[0];
|
||||
ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
|
||||
obuf, 2, DW210X_WRITE_MSG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
|
@ -466,6 +535,11 @@ static struct i2c_algorithm dw3101_i2c_algo = {
|
|||
.functionality = dw210x_i2c_func,
|
||||
};
|
||||
|
||||
static struct i2c_algorithm s630_i2c_algo = {
|
||||
.master_xfer = s630_i2c_transfer,
|
||||
.functionality = dw210x_i2c_func,
|
||||
};
|
||||
|
||||
static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
|
||||
{
|
||||
int i;
|
||||
|
@ -490,6 +564,37 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
|
|||
return 0;
|
||||
};
|
||||
|
||||
static int s630_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
|
||||
{
|
||||
int i, ret;
|
||||
u8 buf[3], eeprom[256], eepromline[16];
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
buf[0] = 1;
|
||||
buf[1] = 0xa0;
|
||||
buf[2] = i;
|
||||
ret = dw210x_op_rw(d->udev, 0x90, 0, 0,
|
||||
buf, 3, DW210X_WRITE_MSG);
|
||||
ret = dw210x_op_rw(d->udev, 0x91, 0, 0,
|
||||
buf, 1, DW210X_READ_MSG);
|
||||
if (ret < 0) {
|
||||
err("read eeprom failed.");
|
||||
return -1;
|
||||
} else {
|
||||
eepromline[i % 16] = buf[0];
|
||||
eeprom[i] = buf[0];
|
||||
}
|
||||
|
||||
if ((i % 16) == 15) {
|
||||
deb_xfer("%02x: ", i - 15);
|
||||
debug_dump(eepromline, 16, deb_xfer);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(mac, eeprom + 16, 6);
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
|
||||
{
|
||||
static u8 command_13v[1] = {0x00};
|
||||
|
@ -535,6 +640,10 @@ static struct tda10023_config dw3101_tda10023_config = {
|
|||
.invert = 1,
|
||||
};
|
||||
|
||||
static struct mt312_config zl313_config = {
|
||||
.demod_address = 0x0e,
|
||||
};
|
||||
|
||||
static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
|
||||
{
|
||||
if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
|
||||
|
@ -596,6 +705,18 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int s630_frontend_attach(struct dvb_usb_adapter *d)
|
||||
{
|
||||
d->fe = dvb_attach(mt312_attach, &zl313_config,
|
||||
&d->dev->i2c_adap);
|
||||
if (d->fe != NULL) {
|
||||
d->fe->ops.set_voltage = dw210x_set_voltage;
|
||||
info("Attached zl10313!\n");
|
||||
return 0;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
|
||||
|
@ -619,123 +740,131 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int s630_zl10039_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
dvb_attach(zl10039_attach, adap->fe, 0x60,
|
||||
&adap->dev->i2c_adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_usb_rc_key dw210x_rc_keys[] = {
|
||||
{ 0xf8, 0x0a, KEY_Q }, /*power*/
|
||||
{ 0xf8, 0x0c, KEY_M }, /*mute*/
|
||||
{ 0xf8, 0x11, KEY_1 },
|
||||
{ 0xf8, 0x12, KEY_2 },
|
||||
{ 0xf8, 0x13, KEY_3 },
|
||||
{ 0xf8, 0x14, KEY_4 },
|
||||
{ 0xf8, 0x15, KEY_5 },
|
||||
{ 0xf8, 0x16, KEY_6 },
|
||||
{ 0xf8, 0x17, KEY_7 },
|
||||
{ 0xf8, 0x18, KEY_8 },
|
||||
{ 0xf8, 0x19, KEY_9 },
|
||||
{ 0xf8, 0x10, KEY_0 },
|
||||
{ 0xf8, 0x1c, KEY_PAGEUP }, /*ch+*/
|
||||
{ 0xf8, 0x0f, KEY_PAGEDOWN }, /*ch-*/
|
||||
{ 0xf8, 0x1a, KEY_O }, /*vol+*/
|
||||
{ 0xf8, 0x0e, KEY_Z }, /*vol-*/
|
||||
{ 0xf8, 0x04, KEY_R }, /*rec*/
|
||||
{ 0xf8, 0x09, KEY_D }, /*fav*/
|
||||
{ 0xf8, 0x08, KEY_BACKSPACE }, /*rewind*/
|
||||
{ 0xf8, 0x07, KEY_A }, /*fast*/
|
||||
{ 0xf8, 0x0b, KEY_P }, /*pause*/
|
||||
{ 0xf8, 0x02, KEY_ESC }, /*cancel*/
|
||||
{ 0xf8, 0x03, KEY_G }, /*tab*/
|
||||
{ 0xf8, 0x00, KEY_UP }, /*up*/
|
||||
{ 0xf8, 0x1f, KEY_ENTER }, /*ok*/
|
||||
{ 0xf8, 0x01, KEY_DOWN }, /*down*/
|
||||
{ 0xf8, 0x05, KEY_C }, /*cap*/
|
||||
{ 0xf8, 0x06, KEY_S }, /*stop*/
|
||||
{ 0xf8, 0x40, KEY_F }, /*full*/
|
||||
{ 0xf8, 0x1e, KEY_W }, /*tvmode*/
|
||||
{ 0xf8, 0x1b, KEY_B }, /*recall*/
|
||||
{ 0xf80a, KEY_Q }, /*power*/
|
||||
{ 0xf80c, KEY_M }, /*mute*/
|
||||
{ 0xf811, KEY_1 },
|
||||
{ 0xf812, KEY_2 },
|
||||
{ 0xf813, KEY_3 },
|
||||
{ 0xf814, KEY_4 },
|
||||
{ 0xf815, KEY_5 },
|
||||
{ 0xf816, KEY_6 },
|
||||
{ 0xf817, KEY_7 },
|
||||
{ 0xf818, KEY_8 },
|
||||
{ 0xf819, KEY_9 },
|
||||
{ 0xf810, KEY_0 },
|
||||
{ 0xf81c, KEY_PAGEUP }, /*ch+*/
|
||||
{ 0xf80f, KEY_PAGEDOWN }, /*ch-*/
|
||||
{ 0xf81a, KEY_O }, /*vol+*/
|
||||
{ 0xf80e, KEY_Z }, /*vol-*/
|
||||
{ 0xf804, KEY_R }, /*rec*/
|
||||
{ 0xf809, KEY_D }, /*fav*/
|
||||
{ 0xf808, KEY_BACKSPACE }, /*rewind*/
|
||||
{ 0xf807, KEY_A }, /*fast*/
|
||||
{ 0xf80b, KEY_P }, /*pause*/
|
||||
{ 0xf802, KEY_ESC }, /*cancel*/
|
||||
{ 0xf803, KEY_G }, /*tab*/
|
||||
{ 0xf800, KEY_UP }, /*up*/
|
||||
{ 0xf81f, KEY_ENTER }, /*ok*/
|
||||
{ 0xf801, KEY_DOWN }, /*down*/
|
||||
{ 0xf805, KEY_C }, /*cap*/
|
||||
{ 0xf806, KEY_S }, /*stop*/
|
||||
{ 0xf840, KEY_F }, /*full*/
|
||||
{ 0xf81e, KEY_W }, /*tvmode*/
|
||||
{ 0xf81b, KEY_B }, /*recall*/
|
||||
};
|
||||
|
||||
static struct dvb_usb_rc_key tevii_rc_keys[] = {
|
||||
{ 0xf8, 0x0a, KEY_POWER },
|
||||
{ 0xf8, 0x0c, KEY_MUTE },
|
||||
{ 0xf8, 0x11, KEY_1 },
|
||||
{ 0xf8, 0x12, KEY_2 },
|
||||
{ 0xf8, 0x13, KEY_3 },
|
||||
{ 0xf8, 0x14, KEY_4 },
|
||||
{ 0xf8, 0x15, KEY_5 },
|
||||
{ 0xf8, 0x16, KEY_6 },
|
||||
{ 0xf8, 0x17, KEY_7 },
|
||||
{ 0xf8, 0x18, KEY_8 },
|
||||
{ 0xf8, 0x19, KEY_9 },
|
||||
{ 0xf8, 0x10, KEY_0 },
|
||||
{ 0xf8, 0x1c, KEY_MENU },
|
||||
{ 0xf8, 0x0f, KEY_VOLUMEDOWN },
|
||||
{ 0xf8, 0x1a, KEY_LAST },
|
||||
{ 0xf8, 0x0e, KEY_OPEN },
|
||||
{ 0xf8, 0x04, KEY_RECORD },
|
||||
{ 0xf8, 0x09, KEY_VOLUMEUP },
|
||||
{ 0xf8, 0x08, KEY_CHANNELUP },
|
||||
{ 0xf8, 0x07, KEY_PVR },
|
||||
{ 0xf8, 0x0b, KEY_TIME },
|
||||
{ 0xf8, 0x02, KEY_RIGHT },
|
||||
{ 0xf8, 0x03, KEY_LEFT },
|
||||
{ 0xf8, 0x00, KEY_UP },
|
||||
{ 0xf8, 0x1f, KEY_OK },
|
||||
{ 0xf8, 0x01, KEY_DOWN },
|
||||
{ 0xf8, 0x05, KEY_TUNER },
|
||||
{ 0xf8, 0x06, KEY_CHANNELDOWN },
|
||||
{ 0xf8, 0x40, KEY_PLAYPAUSE },
|
||||
{ 0xf8, 0x1e, KEY_REWIND },
|
||||
{ 0xf8, 0x1b, KEY_FAVORITES },
|
||||
{ 0xf8, 0x1d, KEY_BACK },
|
||||
{ 0xf8, 0x4d, KEY_FASTFORWARD },
|
||||
{ 0xf8, 0x44, KEY_EPG },
|
||||
{ 0xf8, 0x4c, KEY_INFO },
|
||||
{ 0xf8, 0x41, KEY_AB },
|
||||
{ 0xf8, 0x43, KEY_AUDIO },
|
||||
{ 0xf8, 0x45, KEY_SUBTITLE },
|
||||
{ 0xf8, 0x4a, KEY_LIST },
|
||||
{ 0xf8, 0x46, KEY_F1 },
|
||||
{ 0xf8, 0x47, KEY_F2 },
|
||||
{ 0xf8, 0x5e, KEY_F3 },
|
||||
{ 0xf8, 0x5c, KEY_F4 },
|
||||
{ 0xf8, 0x52, KEY_F5 },
|
||||
{ 0xf8, 0x5a, KEY_F6 },
|
||||
{ 0xf8, 0x56, KEY_MODE },
|
||||
{ 0xf8, 0x58, KEY_SWITCHVIDEOMODE },
|
||||
{ 0xf80a, KEY_POWER },
|
||||
{ 0xf80c, KEY_MUTE },
|
||||
{ 0xf811, KEY_1 },
|
||||
{ 0xf812, KEY_2 },
|
||||
{ 0xf813, KEY_3 },
|
||||
{ 0xf814, KEY_4 },
|
||||
{ 0xf815, KEY_5 },
|
||||
{ 0xf816, KEY_6 },
|
||||
{ 0xf817, KEY_7 },
|
||||
{ 0xf818, KEY_8 },
|
||||
{ 0xf819, KEY_9 },
|
||||
{ 0xf810, KEY_0 },
|
||||
{ 0xf81c, KEY_MENU },
|
||||
{ 0xf80f, KEY_VOLUMEDOWN },
|
||||
{ 0xf81a, KEY_LAST },
|
||||
{ 0xf80e, KEY_OPEN },
|
||||
{ 0xf804, KEY_RECORD },
|
||||
{ 0xf809, KEY_VOLUMEUP },
|
||||
{ 0xf808, KEY_CHANNELUP },
|
||||
{ 0xf807, KEY_PVR },
|
||||
{ 0xf80b, KEY_TIME },
|
||||
{ 0xf802, KEY_RIGHT },
|
||||
{ 0xf803, KEY_LEFT },
|
||||
{ 0xf800, KEY_UP },
|
||||
{ 0xf81f, KEY_OK },
|
||||
{ 0xf801, KEY_DOWN },
|
||||
{ 0xf805, KEY_TUNER },
|
||||
{ 0xf806, KEY_CHANNELDOWN },
|
||||
{ 0xf840, KEY_PLAYPAUSE },
|
||||
{ 0xf81e, KEY_REWIND },
|
||||
{ 0xf81b, KEY_FAVORITES },
|
||||
{ 0xf81d, KEY_BACK },
|
||||
{ 0xf84d, KEY_FASTFORWARD },
|
||||
{ 0xf844, KEY_EPG },
|
||||
{ 0xf84c, KEY_INFO },
|
||||
{ 0xf841, KEY_AB },
|
||||
{ 0xf843, KEY_AUDIO },
|
||||
{ 0xf845, KEY_SUBTITLE },
|
||||
{ 0xf84a, KEY_LIST },
|
||||
{ 0xf846, KEY_F1 },
|
||||
{ 0xf847, KEY_F2 },
|
||||
{ 0xf85e, KEY_F3 },
|
||||
{ 0xf85c, KEY_F4 },
|
||||
{ 0xf852, KEY_F5 },
|
||||
{ 0xf85a, KEY_F6 },
|
||||
{ 0xf856, KEY_MODE },
|
||||
{ 0xf858, KEY_SWITCHVIDEOMODE },
|
||||
};
|
||||
|
||||
static struct dvb_usb_rc_key tbs_rc_keys[] = {
|
||||
{ 0xf8, 0x84, KEY_POWER },
|
||||
{ 0xf8, 0x94, KEY_MUTE },
|
||||
{ 0xf8, 0x87, KEY_1 },
|
||||
{ 0xf8, 0x86, KEY_2 },
|
||||
{ 0xf8, 0x85, KEY_3 },
|
||||
{ 0xf8, 0x8b, KEY_4 },
|
||||
{ 0xf8, 0x8a, KEY_5 },
|
||||
{ 0xf8, 0x89, KEY_6 },
|
||||
{ 0xf8, 0x8f, KEY_7 },
|
||||
{ 0xf8, 0x8e, KEY_8 },
|
||||
{ 0xf8, 0x8d, KEY_9 },
|
||||
{ 0xf8, 0x92, KEY_0 },
|
||||
{ 0xf8, 0x96, KEY_CHANNELUP },
|
||||
{ 0xf8, 0x91, KEY_CHANNELDOWN },
|
||||
{ 0xf8, 0x93, KEY_VOLUMEUP },
|
||||
{ 0xf8, 0x8c, KEY_VOLUMEDOWN },
|
||||
{ 0xf8, 0x83, KEY_RECORD },
|
||||
{ 0xf8, 0x98, KEY_PAUSE },
|
||||
{ 0xf8, 0x99, KEY_OK },
|
||||
{ 0xf8, 0x9a, KEY_SHUFFLE },
|
||||
{ 0xf8, 0x81, KEY_UP },
|
||||
{ 0xf8, 0x90, KEY_LEFT },
|
||||
{ 0xf8, 0x82, KEY_RIGHT },
|
||||
{ 0xf8, 0x88, KEY_DOWN },
|
||||
{ 0xf8, 0x95, KEY_FAVORITES },
|
||||
{ 0xf8, 0x97, KEY_SUBTITLE },
|
||||
{ 0xf8, 0x9d, KEY_ZOOM },
|
||||
{ 0xf8, 0x9f, KEY_EXIT },
|
||||
{ 0xf8, 0x9e, KEY_MENU },
|
||||
{ 0xf8, 0x9c, KEY_EPG },
|
||||
{ 0xf8, 0x80, KEY_PREVIOUS },
|
||||
{ 0xf8, 0x9b, KEY_MODE }
|
||||
{ 0xf884, KEY_POWER },
|
||||
{ 0xf894, KEY_MUTE },
|
||||
{ 0xf887, KEY_1 },
|
||||
{ 0xf886, KEY_2 },
|
||||
{ 0xf885, KEY_3 },
|
||||
{ 0xf88b, KEY_4 },
|
||||
{ 0xf88a, KEY_5 },
|
||||
{ 0xf889, KEY_6 },
|
||||
{ 0xf88f, KEY_7 },
|
||||
{ 0xf88e, KEY_8 },
|
||||
{ 0xf88d, KEY_9 },
|
||||
{ 0xf892, KEY_0 },
|
||||
{ 0xf896, KEY_CHANNELUP },
|
||||
{ 0xf891, KEY_CHANNELDOWN },
|
||||
{ 0xf893, KEY_VOLUMEUP },
|
||||
{ 0xf88c, KEY_VOLUMEDOWN },
|
||||
{ 0xf883, KEY_RECORD },
|
||||
{ 0xf898, KEY_PAUSE },
|
||||
{ 0xf899, KEY_OK },
|
||||
{ 0xf89a, KEY_SHUFFLE },
|
||||
{ 0xf881, KEY_UP },
|
||||
{ 0xf890, KEY_LEFT },
|
||||
{ 0xf882, KEY_RIGHT },
|
||||
{ 0xf888, KEY_DOWN },
|
||||
{ 0xf895, KEY_FAVORITES },
|
||||
{ 0xf897, KEY_SUBTITLE },
|
||||
{ 0xf89d, KEY_ZOOM },
|
||||
{ 0xf89f, KEY_EXIT },
|
||||
{ 0xf89e, KEY_MENU },
|
||||
{ 0xf89c, KEY_EPG },
|
||||
{ 0xf880, KEY_PREVIOUS },
|
||||
{ 0xf89b, KEY_MODE }
|
||||
};
|
||||
|
||||
static struct dvb_usb_rc_keys_table keys_tables[] = {
|
||||
|
@ -763,9 +892,9 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
}
|
||||
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) {
|
||||
if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
|
||||
for (i = 0; i < keymap_size ; i++) {
|
||||
if (keymap[i].data == msg.buf[0]) {
|
||||
if (rc5_data(&keymap[i]) == msg.buf[0]) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = keymap[i].event;
|
||||
break;
|
||||
|
@ -792,6 +921,7 @@ static struct usb_device_id dw2102_table[] = {
|
|||
{USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
|
||||
{USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
|
||||
{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
|
||||
{USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -806,6 +936,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
|
|||
u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
|
||||
const struct firmware *fw;
|
||||
const char *filename = "dvb-usb-dw2101.fw";
|
||||
|
||||
switch (dev->descriptor.idProduct) {
|
||||
case 0x2101:
|
||||
ret = request_firmware(&fw, filename, &dev->dev);
|
||||
|
@ -1053,6 +1184,48 @@ static struct dvb_usb_device_properties dw3101_properties = {
|
|||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties s630_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-s630.fw",
|
||||
.no_reconnect = 1,
|
||||
|
||||
.i2c_algo = &s630_i2c_algo,
|
||||
.rc_key_map = tevii_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(tevii_rc_keys),
|
||||
.rc_interval = 150,
|
||||
.rc_query = dw2102_rc_query,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x81,
|
||||
.num_adapters = 1,
|
||||
.download_firmware = dw2102_load_firmware,
|
||||
.read_mac_address = s630_read_mac_address,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = s630_frontend_attach,
|
||||
.streaming_ctrl = NULL,
|
||||
.tuner_attach = s630_zl10039_tuner_attach,
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 4096,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{"TeVii S630 USB",
|
||||
{&dw2102_table[6], NULL},
|
||||
{NULL},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static int dw2102_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
|
@ -1061,6 +1234,8 @@ static int dw2102_probe(struct usb_interface *intf,
|
|||
0 == dvb_usb_device_init(intf, &dw2104_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &dw3101_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &s630_properties,
|
||||
THIS_MODULE, NULL, adapter_nr)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1094,6 +1269,6 @@ module_exit(dw2102_module_exit);
|
|||
MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
|
||||
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
|
||||
" DVB-C 3101 USB2.0,"
|
||||
" TeVii S600, S650 USB2.0 devices");
|
||||
" TeVii S600, S630, S650 USB2.0 devices");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -140,7 +140,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
goto unlock;
|
||||
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++)
|
||||
if (d->props.rc_key_map[i].data == rc_state[1]) {
|
||||
if (rc5_data(&d->props.rc_key_map[i]) == rc_state[1]) {
|
||||
*event = d->props.rc_key_map[i].event;
|
||||
|
||||
switch(rc_state[0]) {
|
||||
|
@ -562,42 +562,42 @@ static struct m920x_inits tvwalkertwin_rc_init [] = {
|
|||
|
||||
/* ir keymaps */
|
||||
static struct dvb_usb_rc_key megasky_rc_keys [] = {
|
||||
{ 0x0, 0x12, KEY_POWER },
|
||||
{ 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */
|
||||
{ 0x0, 0x02, KEY_CHANNELUP },
|
||||
{ 0x0, 0x05, KEY_CHANNELDOWN },
|
||||
{ 0x0, 0x03, KEY_VOLUMEUP },
|
||||
{ 0x0, 0x06, KEY_VOLUMEDOWN },
|
||||
{ 0x0, 0x04, KEY_MUTE },
|
||||
{ 0x0, 0x07, KEY_OK }, /* TS */
|
||||
{ 0x0, 0x08, KEY_STOP },
|
||||
{ 0x0, 0x09, KEY_MENU }, /* swap */
|
||||
{ 0x0, 0x0a, KEY_REWIND },
|
||||
{ 0x0, 0x1b, KEY_PAUSE },
|
||||
{ 0x0, 0x1f, KEY_FASTFORWARD },
|
||||
{ 0x0, 0x0c, KEY_RECORD },
|
||||
{ 0x0, 0x0d, KEY_CAMERA }, /* screenshot */
|
||||
{ 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
|
||||
{ 0x0012, KEY_POWER },
|
||||
{ 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
|
||||
{ 0x0002, KEY_CHANNELUP },
|
||||
{ 0x0005, KEY_CHANNELDOWN },
|
||||
{ 0x0003, KEY_VOLUMEUP },
|
||||
{ 0x0006, KEY_VOLUMEDOWN },
|
||||
{ 0x0004, KEY_MUTE },
|
||||
{ 0x0007, KEY_OK }, /* TS */
|
||||
{ 0x0008, KEY_STOP },
|
||||
{ 0x0009, KEY_MENU }, /* swap */
|
||||
{ 0x000a, KEY_REWIND },
|
||||
{ 0x001b, KEY_PAUSE },
|
||||
{ 0x001f, KEY_FASTFORWARD },
|
||||
{ 0x000c, KEY_RECORD },
|
||||
{ 0x000d, KEY_CAMERA }, /* screenshot */
|
||||
{ 0x000e, KEY_COFFEE }, /* "MTS" */
|
||||
};
|
||||
|
||||
static struct dvb_usb_rc_key tvwalkertwin_rc_keys [] = {
|
||||
{ 0x0, 0x01, KEY_ZOOM }, /* Full Screen */
|
||||
{ 0x0, 0x02, KEY_CAMERA }, /* snapshot */
|
||||
{ 0x0, 0x03, KEY_MUTE },
|
||||
{ 0x0, 0x04, KEY_REWIND },
|
||||
{ 0x0, 0x05, KEY_PLAYPAUSE }, /* Play/Pause */
|
||||
{ 0x0, 0x06, KEY_FASTFORWARD },
|
||||
{ 0x0, 0x07, KEY_RECORD },
|
||||
{ 0x0, 0x08, KEY_STOP },
|
||||
{ 0x0, 0x09, KEY_TIME }, /* Timeshift */
|
||||
{ 0x0, 0x0c, KEY_COFFEE }, /* Recall */
|
||||
{ 0x0, 0x0e, KEY_CHANNELUP },
|
||||
{ 0x0, 0x12, KEY_POWER },
|
||||
{ 0x0, 0x15, KEY_MENU }, /* source */
|
||||
{ 0x0, 0x18, KEY_CYCLEWINDOWS }, /* TWIN PIP */
|
||||
{ 0x0, 0x1a, KEY_CHANNELDOWN },
|
||||
{ 0x0, 0x1b, KEY_VOLUMEDOWN },
|
||||
{ 0x0, 0x1e, KEY_VOLUMEUP },
|
||||
{ 0x0001, KEY_ZOOM }, /* Full Screen */
|
||||
{ 0x0002, KEY_CAMERA }, /* snapshot */
|
||||
{ 0x0003, KEY_MUTE },
|
||||
{ 0x0004, KEY_REWIND },
|
||||
{ 0x0005, KEY_PLAYPAUSE }, /* Play/Pause */
|
||||
{ 0x0006, KEY_FASTFORWARD },
|
||||
{ 0x0007, KEY_RECORD },
|
||||
{ 0x0008, KEY_STOP },
|
||||
{ 0x0009, KEY_TIME }, /* Timeshift */
|
||||
{ 0x000c, KEY_COFFEE }, /* Recall */
|
||||
{ 0x000e, KEY_CHANNELUP },
|
||||
{ 0x0012, KEY_POWER },
|
||||
{ 0x0015, KEY_MENU }, /* source */
|
||||
{ 0x0018, KEY_CYCLEWINDOWS }, /* TWIN PIP */
|
||||
{ 0x001a, KEY_CHANNELDOWN },
|
||||
{ 0x001b, KEY_VOLUMEDOWN },
|
||||
{ 0x001e, KEY_VOLUMEUP },
|
||||
};
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
|
|
|
@ -22,51 +22,51 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
|||
|
||||
/* Hauppauge NOVA-T USB2 keys */
|
||||
static struct dvb_usb_rc_key haupp_rc_keys [] = {
|
||||
{ 0x1e, 0x00, KEY_0 },
|
||||
{ 0x1e, 0x01, KEY_1 },
|
||||
{ 0x1e, 0x02, KEY_2 },
|
||||
{ 0x1e, 0x03, KEY_3 },
|
||||
{ 0x1e, 0x04, KEY_4 },
|
||||
{ 0x1e, 0x05, KEY_5 },
|
||||
{ 0x1e, 0x06, KEY_6 },
|
||||
{ 0x1e, 0x07, KEY_7 },
|
||||
{ 0x1e, 0x08, KEY_8 },
|
||||
{ 0x1e, 0x09, KEY_9 },
|
||||
{ 0x1e, 0x0a, KEY_KPASTERISK },
|
||||
{ 0x1e, 0x0b, KEY_RED },
|
||||
{ 0x1e, 0x0c, KEY_RADIO },
|
||||
{ 0x1e, 0x0d, KEY_MENU },
|
||||
{ 0x1e, 0x0e, KEY_GRAVE }, /* # */
|
||||
{ 0x1e, 0x0f, KEY_MUTE },
|
||||
{ 0x1e, 0x10, KEY_VOLUMEUP },
|
||||
{ 0x1e, 0x11, KEY_VOLUMEDOWN },
|
||||
{ 0x1e, 0x12, KEY_CHANNEL },
|
||||
{ 0x1e, 0x14, KEY_UP },
|
||||
{ 0x1e, 0x15, KEY_DOWN },
|
||||
{ 0x1e, 0x16, KEY_LEFT },
|
||||
{ 0x1e, 0x17, KEY_RIGHT },
|
||||
{ 0x1e, 0x18, KEY_VIDEO },
|
||||
{ 0x1e, 0x19, KEY_AUDIO },
|
||||
{ 0x1e, 0x1a, KEY_MEDIA },
|
||||
{ 0x1e, 0x1b, KEY_EPG },
|
||||
{ 0x1e, 0x1c, KEY_TV },
|
||||
{ 0x1e, 0x1e, KEY_NEXT },
|
||||
{ 0x1e, 0x1f, KEY_BACK },
|
||||
{ 0x1e, 0x20, KEY_CHANNELUP },
|
||||
{ 0x1e, 0x21, KEY_CHANNELDOWN },
|
||||
{ 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
|
||||
{ 0x1e, 0x25, KEY_OK },
|
||||
{ 0x1e, 0x29, KEY_BLUE},
|
||||
{ 0x1e, 0x2e, KEY_GREEN },
|
||||
{ 0x1e, 0x30, KEY_PAUSE },
|
||||
{ 0x1e, 0x32, KEY_REWIND },
|
||||
{ 0x1e, 0x34, KEY_FASTFORWARD },
|
||||
{ 0x1e, 0x35, KEY_PLAY },
|
||||
{ 0x1e, 0x36, KEY_STOP },
|
||||
{ 0x1e, 0x37, KEY_RECORD },
|
||||
{ 0x1e, 0x38, KEY_YELLOW },
|
||||
{ 0x1e, 0x3b, KEY_GOTO },
|
||||
{ 0x1e, 0x3d, KEY_POWER },
|
||||
{ 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_MEDIA },
|
||||
{ 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
|
||||
|
@ -92,10 +92,11 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(haupp_rc_keys); i++) {
|
||||
if (haupp_rc_keys[i].data == data &&
|
||||
haupp_rc_keys[i].custom == custom) {
|
||||
if (rc5_data(&haupp_rc_keys[i]) == data &&
|
||||
rc5_custom(&haupp_rc_keys[i]) == custom) {
|
||||
|
||||
deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom);
|
||||
deb_rc("c: %x, d: %x\n", rc5_data(&haupp_rc_keys[i]),
|
||||
rc5_custom(&haupp_rc_keys[i]));
|
||||
|
||||
*event = haupp_rc_keys[i].event;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
|
|
|
@ -332,32 +332,32 @@ static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
|
|||
}
|
||||
|
||||
static struct dvb_usb_rc_key opera1_rc_keys[] = {
|
||||
{0x5f, 0xa0, KEY_1},
|
||||
{0x51, 0xaf, KEY_2},
|
||||
{0x5d, 0xa2, KEY_3},
|
||||
{0x41, 0xbe, KEY_4},
|
||||
{0x0b, 0xf5, KEY_5},
|
||||
{0x43, 0xbd, KEY_6},
|
||||
{0x47, 0xb8, KEY_7},
|
||||
{0x49, 0xb6, KEY_8},
|
||||
{0x05, 0xfa, KEY_9},
|
||||
{0x45, 0xba, KEY_0},
|
||||
{0x09, 0xf6, KEY_UP}, /*chanup */
|
||||
{0x1b, 0xe5, KEY_DOWN}, /*chandown */
|
||||
{0x5d, 0xa3, KEY_LEFT}, /*voldown */
|
||||
{0x5f, 0xa1, KEY_RIGHT}, /*volup */
|
||||
{0x07, 0xf8, KEY_SPACE}, /*tab */
|
||||
{0x1f, 0xe1, KEY_ENTER}, /*play ok */
|
||||
{0x1b, 0xe4, KEY_Z}, /*zoom */
|
||||
{0x59, 0xa6, KEY_M}, /*mute */
|
||||
{0x5b, 0xa5, KEY_F}, /*tv/f */
|
||||
{0x19, 0xe7, KEY_R}, /*rec */
|
||||
{0x01, 0xfe, KEY_S}, /*Stop */
|
||||
{0x03, 0xfd, KEY_P}, /*pause */
|
||||
{0x03, 0xfc, KEY_W}, /*<- -> */
|
||||
{0x07, 0xf9, KEY_C}, /*capture */
|
||||
{0x47, 0xb9, KEY_Q}, /*exit */
|
||||
{0x43, 0xbc, KEY_O}, /*power */
|
||||
{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_UP}, /*chanup */
|
||||
{0x1be5, KEY_DOWN}, /*chandown */
|
||||
{0x5da3, KEY_LEFT}, /*voldown */
|
||||
{0x5fa1, KEY_RIGHT}, /*volup */
|
||||
{0x07f8, KEY_SPACE}, /*tab */
|
||||
{0x1fe1, KEY_ENTER}, /*play ok */
|
||||
{0x1be4, KEY_Z}, /*zoom */
|
||||
{0x59a6, KEY_M}, /*mute */
|
||||
{0x5ba5, KEY_F}, /*tv/f */
|
||||
{0x19e7, KEY_R}, /*rec */
|
||||
{0x01fe, KEY_S}, /*Stop */
|
||||
{0x03fd, KEY_P}, /*pause */
|
||||
{0x03fc, KEY_W}, /*<- -> */
|
||||
{0x07f9, KEY_C}, /*capture */
|
||||
{0x47b9, KEY_Q}, /*exit */
|
||||
{0x43bc, KEY_O}, /*power */
|
||||
|
||||
};
|
||||
|
||||
|
@ -405,8 +405,7 @@ static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
|
|||
send_key = (send_key & 0xffff) | 0x0100;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(opera1_rc_keys); i++) {
|
||||
if ((opera1_rc_keys[i].custom * 256 +
|
||||
opera1_rc_keys[i].data) == (send_key & 0xffff)) {
|
||||
if (rc5_scan(&opera1_rc_keys[i]) == (send_key & 0xffff)) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = opera1_rc_keys[i].event;
|
||||
opst->last_key_pressed =
|
||||
|
|
|
@ -175,8 +175,8 @@ static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
|||
|
||||
/* keys for the enclosed remote control */
|
||||
static struct dvb_usb_rc_key vp702x_rc_keys[] = {
|
||||
{ 0x00, 0x01, KEY_1 },
|
||||
{ 0x00, 0x02, KEY_2 },
|
||||
{ 0x0001, KEY_1 },
|
||||
{ 0x0002, KEY_2 },
|
||||
};
|
||||
|
||||
/* remote control stuff (does not work with my box) */
|
||||
|
@ -198,7 +198,7 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vp702x_rc_keys); i++)
|
||||
if (vp702x_rc_keys[i].custom == key[1]) {
|
||||
if (rc5_custom(&vp702x_rc_keys[i]) == key[1]) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = vp702x_rc_keys[i].event;
|
||||
break;
|
||||
|
|
|
@ -100,56 +100,56 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
|
|||
/* The keymapping struct. Somehow this should be loaded to the driver, but
|
||||
* currently it is hardcoded. */
|
||||
static struct dvb_usb_rc_key vp7045_rc_keys[] = {
|
||||
{ 0x00, 0x16, KEY_POWER },
|
||||
{ 0x00, 0x10, KEY_MUTE },
|
||||
{ 0x00, 0x03, KEY_1 },
|
||||
{ 0x00, 0x01, KEY_2 },
|
||||
{ 0x00, 0x06, KEY_3 },
|
||||
{ 0x00, 0x09, KEY_4 },
|
||||
{ 0x00, 0x1d, KEY_5 },
|
||||
{ 0x00, 0x1f, KEY_6 },
|
||||
{ 0x00, 0x0d, KEY_7 },
|
||||
{ 0x00, 0x19, KEY_8 },
|
||||
{ 0x00, 0x1b, KEY_9 },
|
||||
{ 0x00, 0x15, KEY_0 },
|
||||
{ 0x00, 0x05, KEY_CHANNELUP },
|
||||
{ 0x00, 0x02, KEY_CHANNELDOWN },
|
||||
{ 0x00, 0x1e, KEY_VOLUMEUP },
|
||||
{ 0x00, 0x0a, KEY_VOLUMEDOWN },
|
||||
{ 0x00, 0x11, KEY_RECORD },
|
||||
{ 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
|
||||
{ 0x00, 0x14, KEY_PLAY },
|
||||
{ 0x00, 0x1a, KEY_STOP },
|
||||
{ 0x00, 0x40, KEY_REWIND },
|
||||
{ 0x00, 0x12, KEY_FASTFORWARD },
|
||||
{ 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
|
||||
{ 0x00, 0x4c, KEY_PAUSE },
|
||||
{ 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
|
||||
{ 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
|
||||
{ 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
|
||||
{ 0x00, 0x1c, KEY_EPG }, /* EPG */
|
||||
{ 0x00, 0x00, KEY_TAB }, /* Tab */
|
||||
{ 0x00, 0x48, KEY_INFO }, /* Preview */
|
||||
{ 0x00, 0x04, KEY_LIST }, /* RecordList */
|
||||
{ 0x00, 0x0f, KEY_TEXT }, /* Teletext */
|
||||
{ 0x00, 0x41, KEY_PREVIOUSSONG },
|
||||
{ 0x00, 0x42, KEY_NEXTSONG },
|
||||
{ 0x00, 0x4b, KEY_UP },
|
||||
{ 0x00, 0x51, KEY_DOWN },
|
||||
{ 0x00, 0x4e, KEY_LEFT },
|
||||
{ 0x00, 0x52, KEY_RIGHT },
|
||||
{ 0x00, 0x4f, KEY_ENTER },
|
||||
{ 0x00, 0x13, KEY_CANCEL },
|
||||
{ 0x00, 0x4a, KEY_CLEAR },
|
||||
{ 0x00, 0x54, KEY_PRINT }, /* Capture */
|
||||
{ 0x00, 0x43, KEY_SUBTITLE }, /* Subtitle/CC */
|
||||
{ 0x00, 0x08, KEY_VIDEO }, /* A/V */
|
||||
{ 0x00, 0x07, KEY_SLEEP }, /* Hibernate */
|
||||
{ 0x00, 0x45, KEY_ZOOM }, /* Zoom+ */
|
||||
{ 0x00, 0x18, KEY_RED},
|
||||
{ 0x00, 0x53, KEY_GREEN},
|
||||
{ 0x00, 0x5e, KEY_YELLOW},
|
||||
{ 0x00, 0x5f, KEY_BLUE}
|
||||
{ 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)
|
||||
|
@ -166,7 +166,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
|||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++)
|
||||
if (vp7045_rc_keys[i].data == key) {
|
||||
if (rc5_data(&vp7045_rc_keys[i]) == key) {
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
*event = vp7045_rc_keys[i].event;
|
||||
break;
|
||||
|
|
|
@ -89,15 +89,33 @@ struct avc_response_frame {
|
|||
u8 operand[509];
|
||||
};
|
||||
|
||||
#define AVC_DEBUG_FCP_SUBACTIONS 1
|
||||
#define AVC_DEBUG_FCP_PAYLOADS 2
|
||||
#define AVC_DEBUG_READ_DESCRIPTOR 0x0001
|
||||
#define AVC_DEBUG_DSIT 0x0002
|
||||
#define AVC_DEBUG_DSD 0x0004
|
||||
#define AVC_DEBUG_REGISTER_REMOTE_CONTROL 0x0008
|
||||
#define AVC_DEBUG_LNB_CONTROL 0x0010
|
||||
#define AVC_DEBUG_TUNE_QPSK 0x0020
|
||||
#define AVC_DEBUG_TUNE_QPSK2 0x0040
|
||||
#define AVC_DEBUG_HOST2CA 0x0080
|
||||
#define AVC_DEBUG_CA2HOST 0x0100
|
||||
#define AVC_DEBUG_APPLICATION_PMT 0x4000
|
||||
#define AVC_DEBUG_FCP_PAYLOADS 0x8000
|
||||
|
||||
static int avc_debug;
|
||||
module_param_named(debug, avc_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
|
||||
", FCP subactions = " __stringify(AVC_DEBUG_FCP_SUBACTIONS)
|
||||
", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS)
|
||||
", or all = -1)");
|
||||
MODULE_PARM_DESC(debug, "Verbose logging (none = 0"
|
||||
", FCP subactions"
|
||||
": READ DESCRIPTOR = " __stringify(AVC_DEBUG_READ_DESCRIPTOR)
|
||||
", DSIT = " __stringify(AVC_DEBUG_DSIT)
|
||||
", REGISTER_REMOTE_CONTROL = " __stringify(AVC_DEBUG_REGISTER_REMOTE_CONTROL)
|
||||
", LNB CONTROL = " __stringify(AVC_DEBUG_LNB_CONTROL)
|
||||
", TUNE QPSK = " __stringify(AVC_DEBUG_TUNE_QPSK)
|
||||
", TUNE QPSK2 = " __stringify(AVC_DEBUG_TUNE_QPSK2)
|
||||
", HOST2CA = " __stringify(AVC_DEBUG_HOST2CA)
|
||||
", CA2HOST = " __stringify(AVC_DEBUG_CA2HOST)
|
||||
"; Application sent PMT = " __stringify(AVC_DEBUG_APPLICATION_PMT)
|
||||
", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS)
|
||||
", or a combination, or all = -1)");
|
||||
|
||||
static const char *debug_fcp_ctype(unsigned int ctype)
|
||||
{
|
||||
|
@ -118,48 +136,70 @@ static const char *debug_fcp_opcode(unsigned int opcode,
|
|||
const u8 *data, int length)
|
||||
{
|
||||
switch (opcode) {
|
||||
case AVC_OPCODE_VENDOR: break;
|
||||
case AVC_OPCODE_READ_DESCRIPTOR: return "ReadDescriptor";
|
||||
case AVC_OPCODE_DSIT: return "DirectSelectInfo.Type";
|
||||
case AVC_OPCODE_DSD: return "DirectSelectData";
|
||||
default: return "?";
|
||||
case AVC_OPCODE_VENDOR:
|
||||
break;
|
||||
case AVC_OPCODE_READ_DESCRIPTOR:
|
||||
return avc_debug & AVC_DEBUG_READ_DESCRIPTOR ?
|
||||
"ReadDescriptor" : NULL;
|
||||
case AVC_OPCODE_DSIT:
|
||||
return avc_debug & AVC_DEBUG_DSIT ?
|
||||
"DirectSelectInfo.Type" : NULL;
|
||||
case AVC_OPCODE_DSD:
|
||||
return avc_debug & AVC_DEBUG_DSD ? "DirectSelectData" : NULL;
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
if (length < 7 ||
|
||||
data[3] != SFE_VENDOR_DE_COMPANYID_0 ||
|
||||
data[4] != SFE_VENDOR_DE_COMPANYID_1 ||
|
||||
data[5] != SFE_VENDOR_DE_COMPANYID_2)
|
||||
return "Vendor";
|
||||
return "Vendor/Unknown";
|
||||
|
||||
switch (data[6]) {
|
||||
case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL: return "RegisterRC";
|
||||
case SFE_VENDOR_OPCODE_LNB_CONTROL: return "LNBControl";
|
||||
case SFE_VENDOR_OPCODE_TUNE_QPSK: return "TuneQPSK";
|
||||
case SFE_VENDOR_OPCODE_TUNE_QPSK2: return "TuneQPSK2";
|
||||
case SFE_VENDOR_OPCODE_HOST2CA: return "Host2CA";
|
||||
case SFE_VENDOR_OPCODE_CA2HOST: return "CA2Host";
|
||||
case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL:
|
||||
return avc_debug & AVC_DEBUG_REGISTER_REMOTE_CONTROL ?
|
||||
"RegisterRC" : NULL;
|
||||
case SFE_VENDOR_OPCODE_LNB_CONTROL:
|
||||
return avc_debug & AVC_DEBUG_LNB_CONTROL ? "LNBControl" : NULL;
|
||||
case SFE_VENDOR_OPCODE_TUNE_QPSK:
|
||||
return avc_debug & AVC_DEBUG_TUNE_QPSK ? "TuneQPSK" : NULL;
|
||||
case SFE_VENDOR_OPCODE_TUNE_QPSK2:
|
||||
return avc_debug & AVC_DEBUG_TUNE_QPSK2 ? "TuneQPSK2" : NULL;
|
||||
case SFE_VENDOR_OPCODE_HOST2CA:
|
||||
return avc_debug & AVC_DEBUG_HOST2CA ? "Host2CA" : NULL;
|
||||
case SFE_VENDOR_OPCODE_CA2HOST:
|
||||
return avc_debug & AVC_DEBUG_CA2HOST ? "CA2Host" : NULL;
|
||||
}
|
||||
return "Vendor";
|
||||
return "Vendor/Unknown";
|
||||
}
|
||||
|
||||
static void debug_fcp(const u8 *data, int length)
|
||||
{
|
||||
unsigned int subunit_type, subunit_id, op;
|
||||
const char *prefix = data[0] > 7 ? "FCP <- " : "FCP -> ";
|
||||
unsigned int subunit_type, subunit_id, opcode;
|
||||
const char *op, *prefix;
|
||||
|
||||
if (avc_debug & AVC_DEBUG_FCP_SUBACTIONS) {
|
||||
subunit_type = data[1] >> 3;
|
||||
subunit_id = data[1] & 7;
|
||||
op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
|
||||
prefix = data[0] > 7 ? "FCP <- " : "FCP -> ";
|
||||
subunit_type = data[1] >> 3;
|
||||
subunit_id = data[1] & 7;
|
||||
opcode = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
|
||||
op = debug_fcp_opcode(opcode, data, length);
|
||||
|
||||
if (op) {
|
||||
printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
|
||||
prefix, subunit_type, subunit_id, length,
|
||||
debug_fcp_ctype(data[0]),
|
||||
debug_fcp_opcode(op, data, length));
|
||||
debug_fcp_ctype(data[0]), op);
|
||||
if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
|
||||
print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE,
|
||||
16, 1, data, length, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
|
||||
print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE, 16, 1,
|
||||
data, length, false);
|
||||
static void debug_pmt(char *msg, int length)
|
||||
{
|
||||
printk(KERN_INFO "APP PMT -> l=%d\n", length);
|
||||
print_hex_dump(KERN_INFO, "APP PMT -> ", DUMP_PREFIX_NONE,
|
||||
16, 1, msg, length, false);
|
||||
}
|
||||
|
||||
static int __avc_write(struct firedtv *fdtv,
|
||||
|
@ -254,6 +294,26 @@ int avc_recv(struct firedtv *fdtv, void *data, size_t length)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
|
||||
{
|
||||
int i, n, pos = 1;
|
||||
|
||||
for (i = 0, n = 0; i < 16; i++) {
|
||||
if (test_bit(i, &fdtv->channel_active)) {
|
||||
operand[pos++] = 0x13; /* flowfunction relay */
|
||||
operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
|
||||
operand[pos++] = (fdtv->channel_pid[i] >> 8) & 0x1f;
|
||||
operand[pos++] = fdtv->channel_pid[i] & 0xff;
|
||||
operand[pos++] = 0x00; /* tableID */
|
||||
operand[pos++] = 0x00; /* filter_length */
|
||||
n++;
|
||||
}
|
||||
}
|
||||
operand[0] = n;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* tuning command for setting the relative LNB frequency
|
||||
* (not supported by the AVC standard)
|
||||
|
@ -316,7 +376,8 @@ static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
|
|||
}
|
||||
}
|
||||
|
||||
static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params,
|
||||
static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
|
||||
struct dvb_frontend_parameters *params,
|
||||
struct avc_command_frame *c)
|
||||
{
|
||||
c->opcode = AVC_OPCODE_DSD;
|
||||
|
@ -378,13 +439,13 @@ static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params,
|
|||
|
||||
c->operand[20] = 0x00;
|
||||
c->operand[21] = 0x00;
|
||||
/* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
|
||||
c->operand[22] = 0x00;
|
||||
|
||||
c->length = 28;
|
||||
/* Add PIDs to filter */
|
||||
c->length = ALIGN(22 + add_pid_filter(fdtv, &c->operand[22]) + 3, 4);
|
||||
}
|
||||
|
||||
static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params,
|
||||
static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
|
||||
struct dvb_frontend_parameters *params,
|
||||
struct avc_command_frame *c)
|
||||
{
|
||||
struct dvb_ofdm_parameters *ofdm = ¶ms->u.ofdm;
|
||||
|
@ -481,10 +542,9 @@ static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params,
|
|||
|
||||
c->operand[15] = 0x00; /* network_ID[0] */
|
||||
c->operand[16] = 0x00; /* network_ID[1] */
|
||||
/* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
|
||||
c->operand[17] = 0x00;
|
||||
|
||||
c->length = 24;
|
||||
/* Add PIDs to filter */
|
||||
c->length = ALIGN(17 + add_pid_filter(fdtv, &c->operand[17]) + 3, 4);
|
||||
}
|
||||
|
||||
int avc_tuner_dsd(struct firedtv *fdtv,
|
||||
|
@ -502,8 +562,8 @@ int avc_tuner_dsd(struct firedtv *fdtv,
|
|||
switch (fdtv->type) {
|
||||
case FIREDTV_DVB_S:
|
||||
case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break;
|
||||
case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(params, c); break;
|
||||
case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(params, c); break;
|
||||
case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(fdtv, params, c); break;
|
||||
case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(fdtv, params, c); break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
@ -963,6 +1023,9 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
|
|||
int es_info_length;
|
||||
int crc32_csum;
|
||||
|
||||
if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
|
||||
debug_pmt(msg, length);
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
|
||||
c->ctype = AVC_CTYPE_CONTROL;
|
||||
|
|
|
@ -81,6 +81,13 @@ config DVB_ZL10036
|
|||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ZL10039
|
||||
tristate "Zarlink ZL10039 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_S5H1420
|
||||
tristate "Samsung S5H1420 based"
|
||||
depends on DVB_CORE && I2C
|
||||
|
|
|
@ -31,6 +31,7 @@ obj-$(CONFIG_DVB_SP887X) += sp887x.o
|
|||
obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
|
||||
obj-$(CONFIG_DVB_MT352) += mt352.o
|
||||
obj-$(CONFIG_DVB_ZL10036) += zl10036.o
|
||||
obj-$(CONFIG_DVB_ZL10039) += zl10039.o
|
||||
obj-$(CONFIG_DVB_ZL10353) += zl10353.o
|
||||
obj-$(CONFIG_DVB_CX22702) += cx22702.o
|
||||
obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o
|
||||
|
|
|
@ -155,7 +155,7 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet
|
|||
p->hierarchy_information > HIERARCHY_4)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ)
|
||||
if (p->bandwidth < BANDWIDTH_8_MHZ || p->bandwidth > BANDWIDTH_6_MHZ)
|
||||
return -EINVAL;
|
||||
|
||||
if (p->bandwidth == BANDWIDTH_7_MHZ)
|
||||
|
|
|
@ -303,6 +303,7 @@ static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
|
|||
{
|
||||
s32 N;
|
||||
s64 F;
|
||||
u64 dividend;
|
||||
u8 R, r;
|
||||
u8 vcodiv;
|
||||
u8 factor;
|
||||
|
@ -346,7 +347,10 @@ static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
|
|||
F = freq_hz;
|
||||
F *= (u64) (R * vcodiv * 262144);
|
||||
dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
|
||||
do_div(F, state->config->xtal_khz*1000 * factor * 2);
|
||||
/* do_div needs an u64 as first argument */
|
||||
dividend = F;
|
||||
do_div(dividend, state->config->xtal_khz * 1000 * factor * 2);
|
||||
F = dividend;
|
||||
dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
|
||||
F -= (N + 32) * 262144;
|
||||
|
||||
|
|
|
@ -458,7 +458,7 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
|
|||
/* check if symbol rate is within limits */
|
||||
if ((srate > state->frontend.ops.info.symbol_rate_max) ||
|
||||
(srate < state->frontend.ops.info.symbol_rate_min))
|
||||
return -EOPNOTSUPP;;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* choose the sampling rate high enough for the required operation,
|
||||
while optimizing the power consumed by the demodulator */
|
||||
|
|
|
@ -167,7 +167,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par
|
|||
break;
|
||||
case BAND_SBAND:
|
||||
LO4_SET_VCO_HFDIV(lo4, 0, 0);
|
||||
LO4_SET_CTRIM(lo4, 1);;
|
||||
LO4_SET_CTRIM(lo4, 1);
|
||||
c = 1;
|
||||
break;
|
||||
case BAND_UHF:
|
||||
|
|
|
@ -883,7 +883,7 @@ static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32
|
|||
255, 255, 255, 255, 255, 255};
|
||||
|
||||
u32 xtal = state->cfg.bw->xtal_hz / 1000;
|
||||
int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz;
|
||||
int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
|
||||
int k;
|
||||
int coef_re[8],coef_im[8];
|
||||
int bw_khz = bw;
|
||||
|
|
|
@ -389,6 +389,77 @@ static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
|
|||
}
|
||||
};
|
||||
|
||||
/* Samsung TDTC9251DH0 DVB-T NIM, as used on AirStar 2 */
|
||||
static struct dvb_pll_desc dvb_pll_samsung_tdtc9251dh0 = {
|
||||
.name = "Samsung TDTC9251DH0",
|
||||
.min = 48000000,
|
||||
.max = 863000000,
|
||||
.iffreq = 36166667,
|
||||
.count = 3,
|
||||
.entries = {
|
||||
{ 157500000, 166667, 0xcc, 0x09 },
|
||||
{ 443000000, 166667, 0xcc, 0x0a },
|
||||
{ 863000000, 166667, 0xcc, 0x08 },
|
||||
}
|
||||
};
|
||||
|
||||
/* Samsung TBDU18132 DVB-S NIM with TSA5059 PLL, used in SkyStar2 DVB-S 2.3 */
|
||||
static struct dvb_pll_desc dvb_pll_samsung_tbdu18132 = {
|
||||
.name = "Samsung TBDU18132",
|
||||
.min = 950000,
|
||||
.max = 2150000, /* guesses */
|
||||
.iffreq = 0,
|
||||
.count = 2,
|
||||
.entries = {
|
||||
{ 1550000, 125, 0x84, 0x82 },
|
||||
{ 4095937, 125, 0x84, 0x80 },
|
||||
}
|
||||
/* TSA5059 PLL has a 17 bit divisor rather than the 15 bits supported
|
||||
* by this driver. The two extra bits are 0x60 in the third byte. 15
|
||||
* bits is enough for over 4 GHz, which is enough to cover the range
|
||||
* of this tuner. We could use the additional divisor bits by adding
|
||||
* more entries, e.g.
|
||||
{ 0x0ffff * 125 + 125/2, 125, 0x84 | 0x20, },
|
||||
{ 0x17fff * 125 + 125/2, 125, 0x84 | 0x40, },
|
||||
{ 0x1ffff * 125 + 125/2, 125, 0x84 | 0x60, }, */
|
||||
};
|
||||
|
||||
/* Samsung TBMU24112 DVB-S NIM with SL1935 zero-IF tuner */
|
||||
static struct dvb_pll_desc dvb_pll_samsung_tbmu24112 = {
|
||||
.name = "Samsung TBMU24112",
|
||||
.min = 950000,
|
||||
.max = 2150000, /* guesses */
|
||||
.iffreq = 0,
|
||||
.count = 2,
|
||||
.entries = {
|
||||
{ 1500000, 125, 0x84, 0x18 },
|
||||
{ 9999999, 125, 0x84, 0x08 },
|
||||
}
|
||||
};
|
||||
|
||||
/* Alps TDEE4 DVB-C NIM, used on Cablestar 2 */
|
||||
/* byte 4 : 1 * * AGD R3 R2 R1 R0
|
||||
* byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
|
||||
* AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95
|
||||
* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
|
||||
* 47 - 153 0 * 0 0 0 0 0 1 0x01
|
||||
* 153 - 430 0 * 0 0 0 0 1 0 0x02
|
||||
* 430 - 822 0 * 0 0 1 0 0 0 0x08
|
||||
* 822 - 862 1 * 0 0 1 0 0 0 0x88 */
|
||||
static struct dvb_pll_desc dvb_pll_alps_tdee4 = {
|
||||
.name = "ALPS TDEE4",
|
||||
.min = 47000000,
|
||||
.max = 862000000,
|
||||
.iffreq = 36125000,
|
||||
.count = 4,
|
||||
.entries = {
|
||||
{ 153000000, 62500, 0x95, 0x01 },
|
||||
{ 430000000, 62500, 0x95, 0x02 },
|
||||
{ 822000000, 62500, 0x95, 0x08 },
|
||||
{ 999999999, 62500, 0x95, 0x88 },
|
||||
}
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
static struct dvb_pll_desc *pll_list[] = {
|
||||
|
@ -402,11 +473,15 @@ static struct dvb_pll_desc *pll_list[] = {
|
|||
[DVB_PLL_TUA6034] = &dvb_pll_tua6034,
|
||||
[DVB_PLL_TDA665X] = &dvb_pll_tda665x,
|
||||
[DVB_PLL_TDED4] = &dvb_pll_tded4,
|
||||
[DVB_PLL_TDEE4] = &dvb_pll_alps_tdee4,
|
||||
[DVB_PLL_TDHU2] = &dvb_pll_tdhu2,
|
||||
[DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
|
||||
[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
|
||||
[DVB_PLL_OPERA1] = &dvb_pll_opera1,
|
||||
[DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a,
|
||||
[DVB_PLL_SAMSUNG_TDTC9251DH0] = &dvb_pll_samsung_tdtc9251dh0,
|
||||
[DVB_PLL_SAMSUNG_TBDU18132] = &dvb_pll_samsung_tbdu18132,
|
||||
[DVB_PLL_SAMSUNG_TBMU24112] = &dvb_pll_samsung_tbmu24112,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
|
|
@ -23,6 +23,10 @@
|
|||
#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
|
||||
#define DVB_PLL_OPERA1 13
|
||||
#define DVB_PLL_SAMSUNG_DTOS403IH102A 14
|
||||
#define DVB_PLL_SAMSUNG_TDTC9251DH0 15
|
||||
#define DVB_PLL_SAMSUNG_TBDU18132 16
|
||||
#define DVB_PLL_SAMSUNG_TBMU24112 17
|
||||
#define DVB_PLL_TDEE4 18
|
||||
|
||||
/**
|
||||
* Attach a dvb-pll to the supplied frontend structure.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* Support for Legend Silicon DMB-TH demodulator
|
||||
* LGS8913, LGS8GL5
|
||||
* Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
|
||||
* LGS8913, LGS8GL5, LGS8G75
|
||||
* experimental support LGS8G42, LGS8G52
|
||||
*
|
||||
* Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
|
||||
* Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
|
||||
* Copyright (C) 2008 Sirius International (Hong Kong) Limited
|
||||
* Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
|
||||
*
|
||||
|
@ -46,6 +46,42 @@ module_param(fake_signal_str, int, 0644);
|
|||
MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
|
||||
"Signal strength calculation is slow.(default:on).");
|
||||
|
||||
static const u8 lgs8g75_initdat[] = {
|
||||
0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5,
|
||||
0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50,
|
||||
0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5,
|
||||
0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01,
|
||||
0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90,
|
||||
0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23,
|
||||
0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90,
|
||||
0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D,
|
||||
0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60,
|
||||
0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12,
|
||||
0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD,
|
||||
0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60,
|
||||
0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12,
|
||||
0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B,
|
||||
0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60,
|
||||
0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74,
|
||||
0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74,
|
||||
0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2,
|
||||
0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09,
|
||||
0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00,
|
||||
0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90,
|
||||
0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08,
|
||||
0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9,
|
||||
0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80,
|
||||
0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80,
|
||||
0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22
|
||||
};
|
||||
|
||||
/* LGS8GXX internal helper functions */
|
||||
|
||||
static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
|
||||
|
@ -55,7 +91,7 @@ static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
|
|||
struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
|
||||
|
||||
msg.addr = priv->config->demod_address;
|
||||
if (reg >= 0xC0)
|
||||
if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
|
||||
msg.addr += 0x02;
|
||||
|
||||
if (debug >= 2)
|
||||
|
@ -84,7 +120,7 @@ static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
|
|||
};
|
||||
|
||||
dev_addr = priv->config->demod_address;
|
||||
if (reg >= 0xC0)
|
||||
if (priv->config->prod != LGS8GXX_PROD_LGS8G75 && reg >= 0xC0)
|
||||
dev_addr += 0x02;
|
||||
msg[1].addr = msg[0].addr = dev_addr;
|
||||
|
||||
|
@ -112,19 +148,36 @@ static int lgs8gxx_soft_reset(struct lgs8gxx_state *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wait_reg_mask(struct lgs8gxx_state *priv, u8 reg, u8 mask,
|
||||
u8 val, u8 delay, u8 tries)
|
||||
{
|
||||
u8 t;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tries; i++) {
|
||||
lgs8gxx_read_reg(priv, reg, &t);
|
||||
|
||||
if ((t & mask) == val)
|
||||
return 0;
|
||||
msleep(delay);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lgs8gxx_set_ad_mode(struct lgs8gxx_state *priv)
|
||||
{
|
||||
const struct lgs8gxx_config *config = priv->config;
|
||||
u8 if_conf;
|
||||
|
||||
if_conf = 0x10; /* AGC output on; */
|
||||
if_conf = 0x10; /* AGC output on, RF_AGC output off; */
|
||||
|
||||
if_conf |=
|
||||
((config->ext_adc) ? 0x80 : 0x00) |
|
||||
((config->if_neg_center) ? 0x04 : 0x00) |
|
||||
((config->if_freq == 0) ? 0x08 : 0x00) | /* Baseband */
|
||||
((config->ext_adc && config->adc_signed) ? 0x02 : 0x00) |
|
||||
((config->ext_adc && config->if_neg_edge) ? 0x01 : 0x00);
|
||||
((config->adc_signed) ? 0x02 : 0x00) |
|
||||
((config->if_neg_edge) ? 0x01 : 0x00);
|
||||
|
||||
if (config->ext_adc &&
|
||||
(config->prod == LGS8GXX_PROD_LGS8G52)) {
|
||||
|
@ -157,39 +210,82 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/)
|
|||
}
|
||||
dprintk("AFC_INIT_FREQ = 0x%08X\n", v32);
|
||||
|
||||
lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
|
||||
lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
|
||||
lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
|
||||
lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
lgs8gxx_write_reg(priv, 0x08, 0xFF & (v32));
|
||||
lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32 >> 8));
|
||||
lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 16));
|
||||
lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 24));
|
||||
} else {
|
||||
lgs8gxx_write_reg(priv, 0x09, 0xFF & (v32));
|
||||
lgs8gxx_write_reg(priv, 0x0A, 0xFF & (v32 >> 8));
|
||||
lgs8gxx_write_reg(priv, 0x0B, 0xFF & (v32 >> 16));
|
||||
lgs8gxx_write_reg(priv, 0x0C, 0xFF & (v32 >> 24));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv)
|
||||
{
|
||||
u64 val;
|
||||
u32 v32 = 0;
|
||||
u8 reg_addr, t;
|
||||
int i;
|
||||
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
|
||||
reg_addr = 0x23;
|
||||
else
|
||||
reg_addr = 0x48;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
lgs8gxx_read_reg(priv, reg_addr, &t);
|
||||
v32 <<= 8;
|
||||
v32 |= t;
|
||||
reg_addr--;
|
||||
}
|
||||
|
||||
val = v32;
|
||||
val *= priv->config->if_clk_freq;
|
||||
val /= (u64)1 << 32;
|
||||
dprintk("AFC = %u kHz\n", (u32)val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
|
||||
{
|
||||
u8 t;
|
||||
u8 prod = priv->config->prod;
|
||||
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
|
||||
if (prod == LGS8GXX_PROD_LGS8913)
|
||||
lgs8gxx_write_reg(priv, 0xC6, 0x01);
|
||||
|
||||
lgs8gxx_read_reg(priv, 0x7E, &t);
|
||||
lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
|
||||
if (prod == LGS8GXX_PROD_LGS8G75) {
|
||||
lgs8gxx_read_reg(priv, 0x0C, &t);
|
||||
t &= (~0x04);
|
||||
lgs8gxx_write_reg(priv, 0x0C, t | 0x80);
|
||||
lgs8gxx_write_reg(priv, 0x39, 0x00);
|
||||
lgs8gxx_write_reg(priv, 0x3D, 0x04);
|
||||
} else if (prod == LGS8GXX_PROD_LGS8913 ||
|
||||
prod == LGS8GXX_PROD_LGS8GL5 ||
|
||||
prod == LGS8GXX_PROD_LGS8G42 ||
|
||||
prod == LGS8GXX_PROD_LGS8G52 ||
|
||||
prod == LGS8GXX_PROD_LGS8G54) {
|
||||
lgs8gxx_read_reg(priv, 0x7E, &t);
|
||||
lgs8gxx_write_reg(priv, 0x7E, t | 0x01);
|
||||
|
||||
/* clear FEC self reset */
|
||||
lgs8gxx_read_reg(priv, 0xC5, &t);
|
||||
lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
|
||||
/* clear FEC self reset */
|
||||
lgs8gxx_read_reg(priv, 0xC5, &t);
|
||||
lgs8gxx_write_reg(priv, 0xC5, t & 0xE0);
|
||||
}
|
||||
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
|
||||
if (prod == LGS8GXX_PROD_LGS8913) {
|
||||
/* FEC auto detect */
|
||||
lgs8gxx_write_reg(priv, 0xC1, 0x03);
|
||||
|
||||
lgs8gxx_read_reg(priv, 0x7C, &t);
|
||||
t = (t & 0x8C) | 0x03;
|
||||
lgs8gxx_write_reg(priv, 0x7C, t);
|
||||
}
|
||||
|
||||
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
|
||||
/* BER test mode */
|
||||
lgs8gxx_read_reg(priv, 0xC3, &t);
|
||||
t = (t & 0xEF) | 0x10;
|
||||
|
@ -207,6 +303,32 @@ static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
|
|||
int ret = 0;
|
||||
u8 t;
|
||||
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
u8 t2;
|
||||
lgs8gxx_read_reg(priv, 0x0C, &t);
|
||||
t &= (~0x80);
|
||||
lgs8gxx_write_reg(priv, 0x0C, t);
|
||||
|
||||
lgs8gxx_read_reg(priv, 0x0C, &t);
|
||||
lgs8gxx_read_reg(priv, 0x19, &t2);
|
||||
|
||||
if (((t&0x03) == 0x01) && (t2&0x01)) {
|
||||
lgs8gxx_write_reg(priv, 0x6E, 0x05);
|
||||
lgs8gxx_write_reg(priv, 0x39, 0x02);
|
||||
lgs8gxx_write_reg(priv, 0x39, 0x03);
|
||||
lgs8gxx_write_reg(priv, 0x3D, 0x05);
|
||||
lgs8gxx_write_reg(priv, 0x3E, 0x28);
|
||||
lgs8gxx_write_reg(priv, 0x53, 0x80);
|
||||
} else {
|
||||
lgs8gxx_write_reg(priv, 0x6E, 0x3F);
|
||||
lgs8gxx_write_reg(priv, 0x39, 0x00);
|
||||
lgs8gxx_write_reg(priv, 0x3D, 0x04);
|
||||
}
|
||||
|
||||
lgs8gxx_soft_reset(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* turn off auto-detect; manual settings */
|
||||
lgs8gxx_write_reg(priv, 0x7E, 0);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
|
||||
|
@ -226,11 +348,39 @@ static int lgs8gxx_is_locked(struct lgs8gxx_state *priv, u8 *locked)
|
|||
int ret = 0;
|
||||
u8 t;
|
||||
|
||||
ret = lgs8gxx_read_reg(priv, 0x4B, &t);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
|
||||
ret = lgs8gxx_read_reg(priv, 0x13, &t);
|
||||
else
|
||||
ret = lgs8gxx_read_reg(priv, 0x4B, &t);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
*locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
|
||||
*locked = ((t & 0x80) == 0x80) ? 1 : 0;
|
||||
else
|
||||
*locked = ((t & 0xC0) == 0xC0) ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait for Code Acquisition Lock */
|
||||
static int lgs8gxx_wait_ca_lock(struct lgs8gxx_state *priv, u8 *locked)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 reg, mask, val;
|
||||
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
reg = 0x13;
|
||||
mask = 0x80;
|
||||
val = 0x80;
|
||||
} else {
|
||||
reg = 0x4B;
|
||||
mask = 0xC0;
|
||||
val = 0xC0;
|
||||
}
|
||||
|
||||
ret = wait_reg_mask(priv, reg, mask, val, 50, 40);
|
||||
*locked = (ret == 0) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -238,21 +388,30 @@ static int lgs8gxx_is_autodetect_finished(struct lgs8gxx_state *priv,
|
|||
u8 *finished)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 t;
|
||||
u8 reg, mask, val;
|
||||
|
||||
ret = lgs8gxx_read_reg(priv, 0xA4, &t);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
reg = 0x1f;
|
||||
mask = 0xC0;
|
||||
val = 0x80;
|
||||
} else {
|
||||
reg = 0xA4;
|
||||
mask = 0x03;
|
||||
val = 0x01;
|
||||
}
|
||||
|
||||
*finished = ((t & 0x3) == 0x1) ? 1 : 0;
|
||||
ret = wait_reg_mask(priv, reg, mask, val, 10, 20);
|
||||
*finished = (ret == 0) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked)
|
||||
static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 cpn,
|
||||
u8 *locked)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
u8 ad_fini = 0;
|
||||
u8 t1, t2;
|
||||
|
||||
if (gi == GI_945)
|
||||
dprintk("try GI 945\n");
|
||||
|
@ -260,17 +419,29 @@ static int lgs8gxx_autolock_gi(struct lgs8gxx_state *priv, u8 gi, u8 *locked)
|
|||
dprintk("try GI 595\n");
|
||||
else if (gi == GI_420)
|
||||
dprintk("try GI 420\n");
|
||||
lgs8gxx_write_reg(priv, 0x04, gi);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
lgs8gxx_read_reg(priv, 0x0C, &t1);
|
||||
lgs8gxx_read_reg(priv, 0x18, &t2);
|
||||
t1 &= ~(GI_MASK);
|
||||
t1 |= gi;
|
||||
t2 &= 0xFE;
|
||||
t2 |= cpn ? 0x01 : 0x00;
|
||||
lgs8gxx_write_reg(priv, 0x0C, t1);
|
||||
lgs8gxx_write_reg(priv, 0x18, t2);
|
||||
} else {
|
||||
lgs8gxx_write_reg(priv, 0x04, gi);
|
||||
}
|
||||
lgs8gxx_soft_reset(priv);
|
||||
msleep(50);
|
||||
err = lgs8gxx_wait_ca_lock(priv, locked);
|
||||
if (err || !(*locked))
|
||||
return err;
|
||||
err = lgs8gxx_is_autodetect_finished(priv, &ad_fini);
|
||||
if (err != 0)
|
||||
return err;
|
||||
if (ad_fini) {
|
||||
err = lgs8gxx_is_locked(priv, locked);
|
||||
if (err != 0)
|
||||
return err;
|
||||
}
|
||||
dprintk("auto detect finished\n");
|
||||
} else
|
||||
*locked = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -285,13 +456,18 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
|
|||
dprintk("%s\n", __func__);
|
||||
|
||||
lgs8gxx_set_mode_auto(priv);
|
||||
/* Guard Interval */
|
||||
lgs8gxx_write_reg(priv, 0x03, 00);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
lgs8gxx_write_reg(priv, 0x67, 0xAA);
|
||||
lgs8gxx_write_reg(priv, 0x6E, 0x3F);
|
||||
} else {
|
||||
/* Guard Interval */
|
||||
lgs8gxx_write_reg(priv, 0x03, 00);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
tmp_gi = GI_945;
|
||||
err = lgs8gxx_autolock_gi(priv, GI_945, &locked);
|
||||
err = lgs8gxx_autolock_gi(priv, GI_945, j, &locked);
|
||||
if (err)
|
||||
goto out;
|
||||
if (locked)
|
||||
|
@ -299,14 +475,14 @@ static int lgs8gxx_auto_detect(struct lgs8gxx_state *priv,
|
|||
}
|
||||
for (j = 0; j < 2; j++) {
|
||||
tmp_gi = GI_420;
|
||||
err = lgs8gxx_autolock_gi(priv, GI_420, &locked);
|
||||
err = lgs8gxx_autolock_gi(priv, GI_420, j, &locked);
|
||||
if (err)
|
||||
goto out;
|
||||
if (locked)
|
||||
goto locked;
|
||||
}
|
||||
tmp_gi = GI_595;
|
||||
err = lgs8gxx_autolock_gi(priv, GI_595, &locked);
|
||||
err = lgs8gxx_autolock_gi(priv, GI_595, 1, &locked);
|
||||
if (err)
|
||||
goto out;
|
||||
if (locked)
|
||||
|
@ -317,8 +493,13 @@ locked:
|
|||
if ((err == 0) && (locked == 1)) {
|
||||
u8 t;
|
||||
|
||||
lgs8gxx_read_reg(priv, 0xA2, &t);
|
||||
*detected_param = t;
|
||||
if (priv->config->prod != LGS8GXX_PROD_LGS8G75) {
|
||||
lgs8gxx_read_reg(priv, 0xA2, &t);
|
||||
*detected_param = t;
|
||||
} else {
|
||||
lgs8gxx_read_reg(priv, 0x1F, &t);
|
||||
*detected_param = t & 0x3F;
|
||||
}
|
||||
|
||||
if (tmp_gi == GI_945)
|
||||
dprintk("GI 945 locked\n");
|
||||
|
@ -345,18 +526,28 @@ static void lgs8gxx_auto_lock(struct lgs8gxx_state *priv)
|
|||
|
||||
if (err != 0) {
|
||||
dprintk("lgs8gxx_auto_detect failed\n");
|
||||
}
|
||||
} else
|
||||
dprintk("detected param = 0x%02X\n", detected_param);
|
||||
|
||||
/* Apply detected parameters */
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8913) {
|
||||
u8 inter_leave_len = detected_param & TIM_MASK ;
|
||||
inter_leave_len = (inter_leave_len == TIM_LONG) ? 0x60 : 0x40;
|
||||
/* Fix 8913 time interleaver detection bug */
|
||||
inter_leave_len = (inter_leave_len == TIM_MIDDLE) ? 0x60 : 0x40;
|
||||
detected_param &= CF_MASK | SC_MASK | LGS_FEC_MASK;
|
||||
detected_param |= inter_leave_len;
|
||||
}
|
||||
lgs8gxx_write_reg(priv, 0x7D, detected_param);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
|
||||
lgs8gxx_write_reg(priv, 0xC0, detected_param);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
u8 t;
|
||||
lgs8gxx_read_reg(priv, 0x19, &t);
|
||||
t &= 0x81;
|
||||
t |= detected_param << 1;
|
||||
lgs8gxx_write_reg(priv, 0x19, t);
|
||||
} else {
|
||||
lgs8gxx_write_reg(priv, 0x7D, detected_param);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
|
||||
lgs8gxx_write_reg(priv, 0xC0, detected_param);
|
||||
}
|
||||
/* lgs8gxx_soft_reset(priv); */
|
||||
|
||||
/* Enter manual mode */
|
||||
|
@ -378,9 +569,10 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
|
|||
u8 serial, u8 clk_pol, u8 clk_gated)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 t;
|
||||
u8 t, reg_addr;
|
||||
|
||||
ret = lgs8gxx_read_reg(priv, 0xC2, &t);
|
||||
reg_addr = (priv->config->prod == LGS8GXX_PROD_LGS8G75) ? 0x30 : 0xC2;
|
||||
ret = lgs8gxx_read_reg(priv, reg_addr, &t);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
|
@ -389,13 +581,29 @@ static int lgs8gxx_set_mpeg_mode(struct lgs8gxx_state *priv,
|
|||
t |= clk_pol ? TS_CLK_INVERTED : TS_CLK_NORMAL;
|
||||
t |= clk_gated ? TS_CLK_GATED : TS_CLK_FREERUN;
|
||||
|
||||
ret = lgs8gxx_write_reg(priv, 0xC2, t);
|
||||
ret = lgs8gxx_write_reg(priv, reg_addr, t);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A/D input peak-to-peak voltage range */
|
||||
static int lgs8g75_set_adc_vpp(struct lgs8gxx_state *priv,
|
||||
u8 sel)
|
||||
{
|
||||
u8 r26 = 0x73, r27 = 0x90;
|
||||
|
||||
if (priv->config->prod != LGS8GXX_PROD_LGS8G75)
|
||||
return 0;
|
||||
|
||||
r26 |= (sel & 0x01) << 7;
|
||||
r27 |= (sel & 0x02) >> 1;
|
||||
lgs8gxx_write_reg(priv, 0x26, r26);
|
||||
lgs8gxx_write_reg(priv, 0x27, r27);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LGS8913 demod frontend functions */
|
||||
|
||||
|
@ -417,6 +625,34 @@ static int lgs8913_init(struct lgs8gxx_state *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lgs8g75_init_data(struct lgs8gxx_state *priv)
|
||||
{
|
||||
const u8 *p = lgs8g75_initdat;
|
||||
int i;
|
||||
|
||||
lgs8gxx_write_reg(priv, 0xC6, 0x40);
|
||||
|
||||
lgs8gxx_write_reg(priv, 0x3D, 0x04);
|
||||
lgs8gxx_write_reg(priv, 0x39, 0x00);
|
||||
|
||||
lgs8gxx_write_reg(priv, 0x3A, 0x00);
|
||||
lgs8gxx_write_reg(priv, 0x38, 0x00);
|
||||
lgs8gxx_write_reg(priv, 0x3B, 0x00);
|
||||
lgs8gxx_write_reg(priv, 0x38, 0x00);
|
||||
|
||||
for (i = 0; i < sizeof(lgs8g75_initdat); i++) {
|
||||
lgs8gxx_write_reg(priv, 0x38, 0x00);
|
||||
lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
|
||||
lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
|
||||
lgs8gxx_write_reg(priv, 0x3C, *p);
|
||||
p++;
|
||||
}
|
||||
|
||||
lgs8gxx_write_reg(priv, 0x38, 0x00);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgs8gxx_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct lgs8gxx_state *priv =
|
||||
|
@ -429,6 +665,9 @@ static int lgs8gxx_init(struct dvb_frontend *fe)
|
|||
lgs8gxx_read_reg(priv, 0, &data);
|
||||
dprintk("reg 0 = 0x%02X\n", data);
|
||||
|
||||
if (config->prod == LGS8GXX_PROD_LGS8G75)
|
||||
lgs8g75_set_adc_vpp(priv, config->adc_vpp);
|
||||
|
||||
/* Setup MPEG output format */
|
||||
err = lgs8gxx_set_mpeg_mode(priv, config->serial_ts,
|
||||
config->ts_clk_pol,
|
||||
|
@ -439,8 +678,7 @@ static int lgs8gxx_init(struct dvb_frontend *fe)
|
|||
if (config->prod == LGS8GXX_PROD_LGS8913)
|
||||
lgs8913_init(priv);
|
||||
lgs8gxx_set_if_freq(priv, priv->config->if_freq);
|
||||
if (config->prod != LGS8GXX_PROD_LGS8913)
|
||||
lgs8gxx_set_ad_mode(priv);
|
||||
lgs8gxx_set_ad_mode(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -489,9 +727,6 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe,
|
|||
static int lgs8gxx_get_fe(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fe_params)
|
||||
{
|
||||
struct lgs8gxx_state *priv = fe->demodulator_priv;
|
||||
u8 t;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* TODO: get real readings from device */
|
||||
|
@ -501,29 +736,10 @@ static int lgs8gxx_get_fe(struct dvb_frontend *fe,
|
|||
/* bandwidth */
|
||||
fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
|
||||
|
||||
|
||||
lgs8gxx_read_reg(priv, 0x7D, &t);
|
||||
fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
|
||||
fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
|
||||
|
||||
/* constellation */
|
||||
switch (t & SC_MASK) {
|
||||
case SC_QAM64:
|
||||
fe_params->u.ofdm.constellation = QAM_64;
|
||||
break;
|
||||
case SC_QAM32:
|
||||
fe_params->u.ofdm.constellation = QAM_32;
|
||||
break;
|
||||
case SC_QAM16:
|
||||
fe_params->u.ofdm.constellation = QAM_16;
|
||||
break;
|
||||
case SC_QAM4:
|
||||
case SC_QAM4NR:
|
||||
fe_params->u.ofdm.constellation = QPSK;
|
||||
break;
|
||||
default:
|
||||
fe_params->u.ofdm.constellation = QAM_64;
|
||||
}
|
||||
fe_params->u.ofdm.constellation = QAM_AUTO;
|
||||
|
||||
/* transmission mode */
|
||||
fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
|
||||
|
@ -552,9 +768,19 @@ static int lgs8gxx_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
|
|||
{
|
||||
struct lgs8gxx_state *priv = fe->demodulator_priv;
|
||||
s8 ret;
|
||||
u8 t;
|
||||
u8 t, locked = 0;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
*fe_status = 0;
|
||||
|
||||
lgs8gxx_get_afc_phase(priv);
|
||||
lgs8gxx_is_locked(priv, &locked);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
if (locked)
|
||||
*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
|
||||
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = lgs8gxx_read_reg(priv, 0x4B, &t);
|
||||
if (ret != 0)
|
||||
|
@ -658,12 +884,33 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lgs8g75_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
|
||||
{
|
||||
u8 t;
|
||||
s16 v = 0;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
lgs8gxx_read_reg(priv, 0xB1, &t);
|
||||
v |= t;
|
||||
v <<= 8;
|
||||
lgs8gxx_read_reg(priv, 0xB0, &t);
|
||||
v |= t;
|
||||
|
||||
*signal = v;
|
||||
dprintk("%s: signal=0x%02X\n", __func__, *signal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lgs8gxx_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
|
||||
{
|
||||
struct lgs8gxx_state *priv = fe->demodulator_priv;
|
||||
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
|
||||
return lgs8913_read_signal_strength(priv, signal);
|
||||
else if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
|
||||
return lgs8g75_read_signal_strength(priv, signal);
|
||||
else
|
||||
return lgs8gxx_read_signal_agc(priv, signal);
|
||||
}
|
||||
|
@ -674,7 +921,10 @@ static int lgs8gxx_read_snr(struct dvb_frontend *fe, u16 *snr)
|
|||
u8 t;
|
||||
*snr = 0;
|
||||
|
||||
lgs8gxx_read_reg(priv, 0x95, &t);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75)
|
||||
lgs8gxx_read_reg(priv, 0x34, &t);
|
||||
else
|
||||
lgs8gxx_read_reg(priv, 0x95, &t);
|
||||
dprintk("AVG Noise=0x%02X\n", t);
|
||||
*snr = 256 - t;
|
||||
*snr <<= 8;
|
||||
|
@ -690,31 +940,68 @@ static int lgs8gxx_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void packet_counter_start(struct lgs8gxx_state *priv)
|
||||
{
|
||||
u8 orig, t;
|
||||
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
lgs8gxx_read_reg(priv, 0x30, &orig);
|
||||
orig &= 0xE7;
|
||||
t = orig | 0x10;
|
||||
lgs8gxx_write_reg(priv, 0x30, t);
|
||||
t = orig | 0x18;
|
||||
lgs8gxx_write_reg(priv, 0x30, t);
|
||||
t = orig | 0x10;
|
||||
lgs8gxx_write_reg(priv, 0x30, t);
|
||||
} else {
|
||||
lgs8gxx_write_reg(priv, 0xC6, 0x01);
|
||||
lgs8gxx_write_reg(priv, 0xC6, 0x41);
|
||||
lgs8gxx_write_reg(priv, 0xC6, 0x01);
|
||||
}
|
||||
}
|
||||
|
||||
static void packet_counter_stop(struct lgs8gxx_state *priv)
|
||||
{
|
||||
u8 t;
|
||||
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
lgs8gxx_read_reg(priv, 0x30, &t);
|
||||
t &= 0xE7;
|
||||
lgs8gxx_write_reg(priv, 0x30, t);
|
||||
} else {
|
||||
lgs8gxx_write_reg(priv, 0xC6, 0x81);
|
||||
}
|
||||
}
|
||||
|
||||
static int lgs8gxx_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct lgs8gxx_state *priv = fe->demodulator_priv;
|
||||
u8 r0, r1, r2, r3;
|
||||
u32 total_cnt, err_cnt;
|
||||
u8 reg_err, reg_total, t;
|
||||
u32 total_cnt = 0, err_cnt = 0;
|
||||
int i;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
lgs8gxx_write_reg(priv, 0xc6, 0x01);
|
||||
lgs8gxx_write_reg(priv, 0xc6, 0x41);
|
||||
lgs8gxx_write_reg(priv, 0xc6, 0x01);
|
||||
|
||||
packet_counter_start(priv);
|
||||
msleep(200);
|
||||
packet_counter_stop(priv);
|
||||
|
||||
lgs8gxx_write_reg(priv, 0xc6, 0x81);
|
||||
lgs8gxx_read_reg(priv, 0xd0, &r0);
|
||||
lgs8gxx_read_reg(priv, 0xd1, &r1);
|
||||
lgs8gxx_read_reg(priv, 0xd2, &r2);
|
||||
lgs8gxx_read_reg(priv, 0xd3, &r3);
|
||||
total_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
|
||||
lgs8gxx_read_reg(priv, 0xd4, &r0);
|
||||
lgs8gxx_read_reg(priv, 0xd5, &r1);
|
||||
lgs8gxx_read_reg(priv, 0xd6, &r2);
|
||||
lgs8gxx_read_reg(priv, 0xd7, &r3);
|
||||
err_cnt = (r3 << 24) | (r2 << 16) | (r1 << 8) | (r0);
|
||||
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
|
||||
reg_total = 0x28; reg_err = 0x2C;
|
||||
} else {
|
||||
reg_total = 0xD0; reg_err = 0xD4;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
total_cnt <<= 8;
|
||||
lgs8gxx_read_reg(priv, reg_total+3-i, &t);
|
||||
total_cnt |= t;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
err_cnt <<= 8;
|
||||
lgs8gxx_read_reg(priv, reg_err+3-i, &t);
|
||||
err_cnt |= t;
|
||||
}
|
||||
dprintk("error=%d total=%d\n", err_cnt, total_cnt);
|
||||
|
||||
if (total_cnt == 0)
|
||||
|
@ -801,6 +1088,9 @@ struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
|
|||
sizeof(struct dvb_frontend_ops));
|
||||
priv->frontend.demodulator_priv = priv;
|
||||
|
||||
if (config->prod == LGS8GXX_PROD_LGS8G75)
|
||||
lgs8g75_init_data(priv);
|
||||
|
||||
return &priv->frontend;
|
||||
|
||||
error_out:
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* Support for Legend Silicon DMB-TH demodulator
|
||||
* LGS8913, LGS8GL5
|
||||
* Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
|
||||
* LGS8913, LGS8GL5, LGS8G75
|
||||
* experimental support LGS8G42, LGS8G52
|
||||
*
|
||||
* Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
|
||||
* Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
|
||||
* Copyright (C) 2008 Sirius International (Hong Kong) Limited
|
||||
* Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
|
||||
*
|
||||
|
@ -34,6 +34,7 @@
|
|||
#define LGS8GXX_PROD_LGS8G42 3
|
||||
#define LGS8GXX_PROD_LGS8G52 4
|
||||
#define LGS8GXX_PROD_LGS8G54 5
|
||||
#define LGS8GXX_PROD_LGS8G75 6
|
||||
|
||||
struct lgs8gxx_config {
|
||||
|
||||
|
@ -70,6 +71,10 @@ struct lgs8gxx_config {
|
|||
/*IF use Negative center frequency*/
|
||||
u8 if_neg_center;
|
||||
|
||||
/*8G75 internal ADC input range selection*/
|
||||
/*0: 0.8Vpp, 1: 1.0Vpp, 2: 1.6Vpp, 3: 2.0Vpp*/
|
||||
u8 adc_vpp;
|
||||
|
||||
/* slave address and configuration of the tuner */
|
||||
u8 tuner_address;
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* Support for Legend Silicon DMB-TH demodulator
|
||||
* LGS8913, LGS8GL5
|
||||
* Support for Legend Silicon GB20600 (a.k.a DMB-TH) demodulator
|
||||
* LGS8913, LGS8GL5, LGS8G75
|
||||
* experimental support LGS8G42, LGS8G52
|
||||
*
|
||||
* Copyright (C) 2007,2008 David T.L. Wong <davidtlwong@gmail.com>
|
||||
* Copyright (C) 2007-2009 David T.L. Wong <davidtlwong@gmail.com>
|
||||
* Copyright (C) 2008 Sirius International (Hong Kong) Limited
|
||||
* Timothy Lee <timothy.lee@siriushk.com> (for initial work on LGS8GL5)
|
||||
*
|
||||
|
@ -38,7 +38,7 @@ struct lgs8gxx_state {
|
|||
#define SC_QAM64 0x10 /* 64QAM modulation */
|
||||
#define SC_QAM32 0x0C /* 32QAM modulation */
|
||||
#define SC_QAM16 0x08 /* 16QAM modulation */
|
||||
#define SC_QAM4NR 0x04 /* 4QAM modulation */
|
||||
#define SC_QAM4NR 0x04 /* 4QAM-NR modulation */
|
||||
#define SC_QAM4 0x00 /* 4QAM modulation */
|
||||
|
||||
#define LGS_FEC_MASK 0x03 /* FEC Rate Mask */
|
||||
|
@ -47,8 +47,8 @@ struct lgs8gxx_state {
|
|||
#define LGS_FEC_0_8 0x02 /* FEC Rate 0.8 */
|
||||
|
||||
#define TIM_MASK 0x20 /* Time Interleave Length Mask */
|
||||
#define TIM_LONG 0x00 /* Time Interleave Length = 720 */
|
||||
#define TIM_MIDDLE 0x20 /* Time Interleave Length = 240 */
|
||||
#define TIM_LONG 0x20 /* Time Interleave Length = 720 */
|
||||
#define TIM_MIDDLE 0x00 /* Time Interleave Length = 240 */
|
||||
|
||||
#define CF_MASK 0x80 /* Control Frame Mask */
|
||||
#define CF_EN 0x80 /* Control Frame On */
|
||||
|
|
|
@ -85,7 +85,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
|
|||
int i;
|
||||
dprintk("R(%d):", reg & 0x7f);
|
||||
for (i = 0; i < count; i++)
|
||||
printk(" %02x", buf[i]);
|
||||
printk(KERN_CONT " %02x", buf[i]);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
|
|||
int i;
|
||||
dprintk("W(%d):", reg & 0x7f);
|
||||
for (i = 0; i < count; i++)
|
||||
printk(" %02x", src[i]);
|
||||
printk(KERN_CONT " %02x", src[i]);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
|
@ -744,7 +744,8 @@ static struct dvb_frontend_ops mt312_ops = {
|
|||
.type = FE_QPSK,
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, /* FIXME: adjust freq to real used xtal */
|
||||
/* FIXME: adjust freq to real used xtal */
|
||||
.frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
|
||||
.symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */
|
||||
.symbol_rate_max = MT312_SYS_CLK / 2,
|
||||
.caps =
|
||||
|
|
|
@ -367,7 +367,9 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
|||
/* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */
|
||||
nint = fvco / (state->reference << psd2);
|
||||
/* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */
|
||||
nfrac = (((fvco - (nint * state->reference << psd2)) << (9 - psd2)) + state->reference / 2) / state->reference;
|
||||
nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2))
|
||||
<< (9 - psd2),
|
||||
state->reference);
|
||||
dprintk(verbose, FE_DEBUG, 1,
|
||||
"frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
|
||||
frequency, srate, (unsigned int)g, (unsigned int)odiv,
|
||||
|
|
|
@ -230,8 +230,8 @@ enum fe_stv0900_error stv0900_initialize(struct stv0900_internal *i_params)
|
|||
stv0900_write_reg(i_params, R0900_P2_DMDISTATE, 0x5c);
|
||||
stv0900_write_reg(i_params, R0900_P1_TNRCFG, 0x6c);
|
||||
stv0900_write_reg(i_params, R0900_P2_TNRCFG, 0x6f);
|
||||
stv0900_write_reg(i_params, R0900_P1_I2CRPT, 0x24);
|
||||
stv0900_write_reg(i_params, R0900_P2_I2CRPT, 0x24);
|
||||
stv0900_write_reg(i_params, R0900_P1_I2CRPT, 0x20);
|
||||
stv0900_write_reg(i_params, R0900_P2_I2CRPT, 0x20);
|
||||
stv0900_write_reg(i_params, R0900_NCOARSE, 0x13);
|
||||
msleep(3);
|
||||
stv0900_write_reg(i_params, R0900_I2CCFG, 0x08);
|
||||
|
@ -370,8 +370,8 @@ static int stv0900_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
|||
u32 fi2c;
|
||||
|
||||
dmd_reg(fi2c, F0900_P1_I2CT_ON, F0900_P2_I2CT_ON);
|
||||
if (enable)
|
||||
stv0900_write_bits(i_params, fi2c, 1);
|
||||
|
||||
stv0900_write_bits(i_params, fi2c, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1721,7 +1721,7 @@ static enum fe_stv0900_signal_type stv0900_dvbs1_acq_workaround(struct dvb_front
|
|||
|
||||
s32 srate, demod_timeout,
|
||||
fec_timeout, freq1, freq0;
|
||||
enum fe_stv0900_signal_type signal_type = STV0900_NODATA;;
|
||||
enum fe_stv0900_signal_type signal_type = STV0900_NODATA;
|
||||
|
||||
switch (demod) {
|
||||
case STV0900_DEMOD_1:
|
||||
|
|
|
@ -36,6 +36,7 @@ struct stv6110_priv {
|
|||
struct i2c_adapter *i2c;
|
||||
|
||||
u32 mclk;
|
||||
u8 clk_div;
|
||||
u8 regs[8];
|
||||
};
|
||||
|
||||
|
@ -100,35 +101,25 @@ static int stv6110_read_regs(struct dvb_frontend *fe, u8 regs[],
|
|||
struct stv6110_priv *priv = fe->tuner_priv;
|
||||
int rc;
|
||||
u8 reg[] = { start };
|
||||
struct i2c_msg msg_wr = {
|
||||
.addr = priv->i2c_address,
|
||||
.flags = 0,
|
||||
.buf = reg,
|
||||
.len = 1,
|
||||
struct i2c_msg msg[] = {
|
||||
{
|
||||
.addr = priv->i2c_address,
|
||||
.flags = 0,
|
||||
.buf = reg,
|
||||
.len = 1,
|
||||
}, {
|
||||
.addr = priv->i2c_address,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = regs,
|
||||
.len = len,
|
||||
},
|
||||
};
|
||||
|
||||
struct i2c_msg msg_rd = {
|
||||
.addr = priv->i2c_address,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = regs,
|
||||
.len = len,
|
||||
};
|
||||
/* write subaddr */
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
rc = i2c_transfer(priv->i2c, &msg_wr, 1);
|
||||
if (rc != 1)
|
||||
dprintk("%s: i2c error\n", __func__);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
/* read registers */
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
rc = i2c_transfer(priv->i2c, &msg_rd, 1);
|
||||
if (rc != 1)
|
||||
rc = i2c_transfer(priv->i2c, msg, 2);
|
||||
if (rc != 2)
|
||||
dprintk("%s: i2c error\n", __func__);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
|
@ -221,6 +212,10 @@ static int stv6110_init(struct dvb_frontend *fe)
|
|||
priv->regs[RSTV6110_CTRL1] |=
|
||||
((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
|
||||
|
||||
/* divisor value for the output clock */
|
||||
priv->regs[RSTV6110_CTRL2] &= ~0xc0;
|
||||
priv->regs[RSTV6110_CTRL2] |= (priv->clk_div << 6);
|
||||
|
||||
stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL1], RSTV6110_CTRL1, 8);
|
||||
msleep(1);
|
||||
stv6110_set_bandwidth(fe, 72000000);
|
||||
|
@ -418,6 +413,10 @@ struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
|
|||
};
|
||||
int ret;
|
||||
|
||||
/* divisor value for the output clock */
|
||||
reg0[2] &= ~0xc0;
|
||||
reg0[2] |= (config->clk_div << 6);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
|
@ -436,6 +435,7 @@ struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
|
|||
priv->i2c_address = config->i2c_address;
|
||||
priv->i2c = i2c;
|
||||
priv->mclk = config->mclk;
|
||||
priv->clk_div = config->clk_div;
|
||||
|
||||
memcpy(&priv->regs, ®0[1], 8);
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
struct stv6110_config {
|
||||
u8 i2c_address;
|
||||
u32 mclk;
|
||||
int iq_wiring;
|
||||
u8 clk_div; /* divisor value for the output clock */
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \
|
||||
|
|
|
@ -176,7 +176,7 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate
|
|||
tmp = ((symbolrate << 4) % FIN) << 8;
|
||||
ratio = (ratio << 8) + tmp / FIN;
|
||||
tmp = (tmp % FIN) << 8;
|
||||
ratio = (ratio << 8) + (tmp + FIN/2) / FIN;
|
||||
ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN);
|
||||
|
||||
BDR = ratio;
|
||||
BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
|
||||
|
|
|
@ -136,9 +136,9 @@ static int tda8261_set_state(struct dvb_frontend *fe,
|
|||
|
||||
if (frequency < 1450000)
|
||||
buf[3] = 0x00;
|
||||
if (frequency < 2000000)
|
||||
else if (frequency < 2000000)
|
||||
buf[3] = 0x40;
|
||||
if (frequency < 2150000)
|
||||
else if (frequency < 2150000)
|
||||
buf[3] = 0x80;
|
||||
|
||||
/* Set params */
|
||||
|
|
|
@ -165,7 +165,7 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate)
|
|||
tmp = ((symbolrate << 4) % fin) << 8;
|
||||
ratio = (ratio << 8) + tmp / fin;
|
||||
tmp = (tmp % fin) << 8;
|
||||
ratio = (ratio << 8) + (tmp + fin / 2) / fin;
|
||||
ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, fin);
|
||||
|
||||
BDR = ratio;
|
||||
BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <asm/types.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "zl10036.h"
|
||||
|
||||
|
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* Driver for Zarlink ZL10039 DVB-S tuner
|
||||
*
|
||||
* Copyright 2007 Jan D. Louw <jd.louw@mweb.co.za>
|
||||
*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "zl10039.h"
|
||||
|
||||
static int debug;
|
||||
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG args); \
|
||||
} while (0)
|
||||
|
||||
enum zl10039_model_id {
|
||||
ID_ZL10039 = 1
|
||||
};
|
||||
|
||||
struct zl10039_state {
|
||||
struct i2c_adapter *i2c;
|
||||
u8 i2c_addr;
|
||||
u8 id;
|
||||
};
|
||||
|
||||
enum zl10039_reg_addr {
|
||||
PLL0 = 0,
|
||||
PLL1,
|
||||
PLL2,
|
||||
PLL3,
|
||||
RFFE,
|
||||
BASE0,
|
||||
BASE1,
|
||||
BASE2,
|
||||
LO0,
|
||||
LO1,
|
||||
LO2,
|
||||
LO3,
|
||||
LO4,
|
||||
LO5,
|
||||
LO6,
|
||||
GENERAL
|
||||
};
|
||||
|
||||
static int zl10039_read(const struct zl10039_state *state,
|
||||
const enum zl10039_reg_addr reg, u8 *buf,
|
||||
const size_t count)
|
||||
{
|
||||
u8 regbuf[] = { reg };
|
||||
struct i2c_msg msg[] = {
|
||||
{/* Write register address */
|
||||
.addr = state->i2c_addr,
|
||||
.flags = 0,
|
||||
.buf = regbuf,
|
||||
.len = 1,
|
||||
}, {/* Read count bytes */
|
||||
.addr = state->i2c_addr,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = buf,
|
||||
.len = count,
|
||||
},
|
||||
};
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (i2c_transfer(state->i2c, msg, 2) != 2) {
|
||||
dprintk("%s: i2c read error\n", __func__);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0; /* Success */
|
||||
}
|
||||
|
||||
static int zl10039_write(struct zl10039_state *state,
|
||||
const enum zl10039_reg_addr reg, const u8 *src,
|
||||
const size_t count)
|
||||
{
|
||||
u8 buf[count + 1];
|
||||
struct i2c_msg msg = {
|
||||
.addr = state->i2c_addr,
|
||||
.flags = 0,
|
||||
.buf = buf,
|
||||
.len = count + 1,
|
||||
};
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
/* Write register address and data in one go */
|
||||
buf[0] = reg;
|
||||
memcpy(&buf[1], src, count);
|
||||
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
|
||||
dprintk("%s: i2c write error\n", __func__);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
return 0; /* Success */
|
||||
}
|
||||
|
||||
static inline int zl10039_readreg(struct zl10039_state *state,
|
||||
const enum zl10039_reg_addr reg, u8 *val)
|
||||
{
|
||||
return zl10039_read(state, reg, val, 1);
|
||||
}
|
||||
|
||||
static inline int zl10039_writereg(struct zl10039_state *state,
|
||||
const enum zl10039_reg_addr reg,
|
||||
const u8 val)
|
||||
{
|
||||
return zl10039_write(state, reg, &val, 1);
|
||||
}
|
||||
|
||||
static int zl10039_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct zl10039_state *state = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
/* Reset logic */
|
||||
ret = zl10039_writereg(state, GENERAL, 0x40);
|
||||
if (ret < 0) {
|
||||
dprintk("Note: i2c write error normal when resetting the "
|
||||
"tuner\n");
|
||||
}
|
||||
/* Wake up */
|
||||
ret = zl10039_writereg(state, GENERAL, 0x01);
|
||||
if (ret < 0) {
|
||||
dprintk("Tuner power up failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zl10039_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
struct zl10039_state *state = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
ret = zl10039_writereg(state, GENERAL, 0x80);
|
||||
if (ret < 0) {
|
||||
dprintk("Tuner sleep failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zl10039_set_params(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct zl10039_state *state = fe->tuner_priv;
|
||||
u8 buf[6];
|
||||
u8 bf;
|
||||
u32 fbw;
|
||||
u32 div;
|
||||
int ret;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
dprintk("Set frequency = %d, symbol rate = %d\n",
|
||||
params->frequency, params->u.qpsk.symbol_rate);
|
||||
|
||||
/* Assumed 10.111 MHz crystal oscillator */
|
||||
/* Cancelled num/den 80 to prevent overflow */
|
||||
div = (params->frequency * 1000) / 126387;
|
||||
fbw = (params->u.qpsk.symbol_rate * 27) / 32000;
|
||||
/* Cancelled num/den 10 to prevent overflow */
|
||||
bf = ((fbw * 5088) / 1011100) - 1;
|
||||
|
||||
/*PLL divider*/
|
||||
buf[0] = (div >> 8) & 0x7f;
|
||||
buf[1] = (div >> 0) & 0xff;
|
||||
/*Reference divider*/
|
||||
/* Select reference ratio of 80 */
|
||||
buf[2] = 0x1D;
|
||||
/*PLL test modes*/
|
||||
buf[3] = 0x40;
|
||||
/*RF Control register*/
|
||||
buf[4] = 0x6E; /* Bypass enable */
|
||||
/*Baseband filter cutoff */
|
||||
buf[5] = bf;
|
||||
|
||||
/* Open i2c gate */
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
/* BR = 10, Enable filter adjustment */
|
||||
ret = zl10039_writereg(state, BASE1, 0x0A);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
/* Write new config values */
|
||||
ret = zl10039_write(state, PLL0, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
/* BR = 10, Disable filter adjustment */
|
||||
ret = zl10039_writereg(state, BASE1, 0x6A);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
/* Close i2c gate */
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
return 0;
|
||||
error:
|
||||
dprintk("Error setting tuner\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int zl10039_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct zl10039_state *state = fe->tuner_priv;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
kfree(state);
|
||||
fe->tuner_priv = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_tuner_ops zl10039_ops = {
|
||||
.release = zl10039_release,
|
||||
.init = zl10039_init,
|
||||
.sleep = zl10039_sleep,
|
||||
.set_params = zl10039_set_params,
|
||||
};
|
||||
|
||||
struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
|
||||
u8 i2c_addr, struct i2c_adapter *i2c)
|
||||
{
|
||||
struct zl10039_state *state = NULL;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
state->i2c = i2c;
|
||||
state->i2c_addr = i2c_addr;
|
||||
|
||||
/* Open i2c gate */
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
/* check if this is a valid tuner */
|
||||
if (zl10039_readreg(state, GENERAL, &state->id) < 0) {
|
||||
/* Close i2c gate */
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
goto error;
|
||||
}
|
||||
/* Close i2c gate */
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
state->id = state->id & 0x0f;
|
||||
switch (state->id) {
|
||||
case ID_ZL10039:
|
||||
strcpy(fe->ops.tuner_ops.info.name,
|
||||
"Zarlink ZL10039 DVB-S tuner");
|
||||
break;
|
||||
default:
|
||||
dprintk("Chip ID=%x does not match a known type\n", state->id);
|
||||
break;
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops));
|
||||
fe->tuner_priv = state;
|
||||
dprintk("Tuner attached @ i2c address 0x%02x\n", i2c_addr);
|
||||
return fe;
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(zl10039_attach);
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver");
|
||||
MODULE_AUTHOR("Jan D. Louw <jd.louw@mweb.co.za>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Driver for Zarlink ZL10039 DVB-S tuner
|
||||
|
||||
Copyright (C) 2007 Jan D. Louw <jd.louw@mweb.co.za>
|
||||
|
||||
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 ZL10039_H
|
||||
#define ZL10039_H
|
||||
|
||||
#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \
|
||||
&& defined(MODULE))
|
||||
struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
|
||||
u8 i2c_addr,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
|
||||
u8 i2c_addr,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_ZL10039 */
|
||||
|
||||
#endif /* ZL10039_H */
|
|
@ -38,6 +38,8 @@ struct zl10353_state {
|
|||
struct zl10353_config config;
|
||||
|
||||
enum fe_bandwidth bandwidth;
|
||||
u32 ucblocks;
|
||||
u32 frequency;
|
||||
};
|
||||
|
||||
static int debug;
|
||||
|
@ -199,6 +201,8 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
|
|||
u16 tps = 0;
|
||||
struct dvb_ofdm_parameters *op = ¶m->u.ofdm;
|
||||
|
||||
state->frequency = param->frequency;
|
||||
|
||||
zl10353_single_write(fe, RESET, 0x80);
|
||||
udelay(200);
|
||||
zl10353_single_write(fe, 0xEA, 0x01);
|
||||
|
@ -464,7 +468,7 @@ static int zl10353_get_parameters(struct dvb_frontend *fe,
|
|||
break;
|
||||
}
|
||||
|
||||
param->frequency = 0;
|
||||
param->frequency = state->frequency;
|
||||
op->bandwidth = state->bandwidth;
|
||||
param->inversion = INVERSION_AUTO;
|
||||
|
||||
|
@ -542,9 +546,13 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
|
|||
static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
struct zl10353_state *state = fe->demodulator_priv;
|
||||
u32 ubl = 0;
|
||||
|
||||
*ucblocks = zl10353_read_register(state, RS_UBC_1) << 8 |
|
||||
zl10353_read_register(state, RS_UBC_0);
|
||||
ubl = zl10353_read_register(state, RS_UBC_1) << 8 |
|
||||
zl10353_read_register(state, RS_UBC_0);
|
||||
|
||||
state->ucblocks += ubl;
|
||||
*ucblocks = state->ucblocks;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -439,7 +439,7 @@ static inline u32 divide(u32 numerator, u32 denominator)
|
|||
if (denominator == 0)
|
||||
return ~0;
|
||||
|
||||
return (numerator + denominator / 2) / denominator;
|
||||
return DIV_ROUND_CLOSEST(numerator, denominator);
|
||||
}
|
||||
|
||||
/* LG Innotek TDTE-E001P (Infineon TUA6034) */
|
||||
|
|
|
@ -490,7 +490,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
|
|||
if (!av7110->analog_tuner_flags)
|
||||
return 0;
|
||||
|
||||
if (input < 0 || input >= 4)
|
||||
if (input >= 4)
|
||||
return -EINVAL;
|
||||
|
||||
av7110->current_input = input;
|
||||
|
|
|
@ -225,7 +225,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
|||
case 0x1012:
|
||||
/* The hauppauge keymap is a superset of these remotes */
|
||||
ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
IR_TYPE_RC5, ir_codes_hauppauge_new);
|
||||
IR_TYPE_RC5, &ir_codes_hauppauge_new_table);
|
||||
|
||||
if (rc5_device < 0)
|
||||
budget_ci->ir.rc5_device = 0x1f;
|
||||
|
@ -237,7 +237,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
|||
case 0x101a:
|
||||
/* for the Technotrend 1500 bundled remote */
|
||||
ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
IR_TYPE_RC5, ir_codes_tt_1500);
|
||||
IR_TYPE_RC5, &ir_codes_tt_1500_table);
|
||||
|
||||
if (rc5_device < 0)
|
||||
budget_ci->ir.rc5_device = IR_DEVICE_ANY;
|
||||
|
@ -247,7 +247,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
|||
default:
|
||||
/* unknown remote */
|
||||
ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
IR_TYPE_RC5, ir_codes_budget_ci_old);
|
||||
IR_TYPE_RC5, &ir_codes_budget_ci_old_table);
|
||||
|
||||
if (rc5_device < 0)
|
||||
budget_ci->ir.rc5_device = IR_DEVICE_ANY;
|
||||
|
|
|
@ -288,16 +288,6 @@ config RADIO_TYPHOON
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-typhoon.
|
||||
|
||||
config RADIO_TYPHOON_PROC_FS
|
||||
bool "Support for /proc/radio-typhoon"
|
||||
depends on PROC_FS && RADIO_TYPHOON
|
||||
help
|
||||
Say Y here if you want the typhoon radio card driver to write
|
||||
status information (frequency, volume, muted, mute frequency,
|
||||
base address) to /proc/radio-typhoon. The file can be viewed with
|
||||
your favorite pager (i.e. use "more /proc/radio-typhoon" or "less
|
||||
/proc/radio-typhoon" or simply "cat /proc/radio-typhoon").
|
||||
|
||||
config RADIO_TYPHOON_PORT
|
||||
hex "Typhoon I/O port (0x316 or 0x336)"
|
||||
depends on RADIO_TYPHOON=y
|
||||
|
@ -339,6 +329,29 @@ config RADIO_ZOLTRIX_PORT
|
|||
help
|
||||
Enter the I/O port of your Zoltrix radio card.
|
||||
|
||||
config I2C_SI4713
|
||||
tristate "I2C driver for Silicon Labs Si4713 device"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
---help---
|
||||
Say Y here if you want support to Si4713 I2C device.
|
||||
This device driver supports only i2c bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called si4713.
|
||||
|
||||
config RADIO_SI4713
|
||||
tristate "Silicon Labs Si4713 FM Radio Transmitter support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
select I2C_SI4713
|
||||
---help---
|
||||
Say Y here if you want support to Si4713 FM Radio Transmitter.
|
||||
This device can transmit audio through FM. It can transmit
|
||||
EDS and EBDS signals as well. This module is the v4l2 radio
|
||||
interface for the i2c driver of this device.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-si4713.
|
||||
|
||||
config USB_DSBR
|
||||
tristate "D-Link/GemTek USB FM radio support"
|
||||
depends on USB && VIDEO_V4L2
|
||||
|
@ -351,29 +364,11 @@ config USB_DSBR
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called dsbr100.
|
||||
|
||||
config USB_SI470X
|
||||
tristate "Silicon Labs Si470x FM Radio Receiver support"
|
||||
depends on USB && VIDEO_V4L2
|
||||
---help---
|
||||
This is a driver for USB devices with the Silicon Labs SI470x
|
||||
chip. Currently these devices are known to work:
|
||||
- 10c4:818a: Silicon Labs USB FM Radio Reference Design
|
||||
- 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music)
|
||||
- 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
|
||||
config RADIO_SI470X
|
||||
bool "Silicon Labs Si470x FM Radio Receiver support"
|
||||
depends on VIDEO_V4L2
|
||||
|
||||
Sound is provided by the ALSA USB Audio/MIDI driver. Therefore
|
||||
if you don't want to use the device solely for RDS receiving,
|
||||
it is recommended to also select SND_USB_AUDIO.
|
||||
|
||||
Please have a look at the documentation, especially on how
|
||||
to redirect the audio stream from the radio to your sound device:
|
||||
Documentation/video4linux/si470x.txt
|
||||
|
||||
Say Y here if you want to connect this type of radio to your
|
||||
computer's USB port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-si470x.
|
||||
source "drivers/media/radio/si470x/Kconfig"
|
||||
|
||||
config USB_MR800
|
||||
tristate "AverMedia MR 800 USB FM radio support"
|
||||
|
|
|
@ -15,9 +15,11 @@ obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
|
|||
obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
|
||||
obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
|
||||
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
|
||||
obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
|
||||
obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
|
||||
obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
|
||||
obj-$(CONFIG_USB_DSBR) += dsbr100.o
|
||||
obj-$(CONFIG_USB_SI470X) += radio-si470x.o
|
||||
obj-$(CONFIG_RADIO_SI470X) += si470x/
|
||||
obj-$(CONFIG_USB_MR800) += radio-mr800.o
|
||||
obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
|
||||
|
||||
|
|
|
@ -359,7 +359,8 @@ static int vidioc_querycap(struct file *file, void *priv,
|
|||
strlcpy(v->card, "ADS Cadet", sizeof(v->card));
|
||||
strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
|
||||
v->version = CADET_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_READWRITE;
|
||||
v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
|
||||
V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -372,7 +373,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
|
|||
switch (v->index) {
|
||||
case 0:
|
||||
strlcpy(v->name, "FM", sizeof(v->name));
|
||||
v->capability = V4L2_TUNER_CAP_STEREO;
|
||||
v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS;
|
||||
v->rangelow = 1400; /* 87.5 MHz */
|
||||
v->rangehigh = 1728; /* 108.0 MHz */
|
||||
v->rxsubchans = cadet_getstereo(dev);
|
||||
|
@ -386,6 +387,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
v->rxsubchans |= V4L2_TUNER_SUB_RDS;
|
||||
break;
|
||||
case 1:
|
||||
strlcpy(v->name, "AM", sizeof(v->name));
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,367 @@
|
|||
/*
|
||||
* drivers/media/radio/radio-si4713.c
|
||||
*
|
||||
* Platform Driver for Silicon Labs Si4713 FM Radio Transmitter:
|
||||
*
|
||||
* Copyright (c) 2008 Instituto Nokia de Tecnologia - INdT
|
||||
* Contact: Eduardo Valentin <eduardo.valentin@nokia.com>
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/radio-si4713.h>
|
||||
|
||||
/* module parameters */
|
||||
static int radio_nr = -1; /* radio device minor (-1 ==> auto assign) */
|
||||
module_param(radio_nr, int, 0);
|
||||
MODULE_PARM_DESC(radio_nr,
|
||||
"Minor number for radio device (-1 ==> auto assign)");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Eduardo Valentin <eduardo.valentin@nokia.com>");
|
||||
MODULE_DESCRIPTION("Platform driver for Si4713 FM Radio Transmitter");
|
||||
MODULE_VERSION("0.0.1");
|
||||
|
||||
/* Driver state struct */
|
||||
struct radio_si4713_device {
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct video_device *radio_dev;
|
||||
};
|
||||
|
||||
/* radio_si4713_fops - file operations interface */
|
||||
static const struct v4l2_file_operations radio_si4713_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = video_ioctl2,
|
||||
};
|
||||
|
||||
/* Video4Linux Interface */
|
||||
static int radio_si4713_fill_audout(struct v4l2_audioout *vao)
|
||||
{
|
||||
/* TODO: check presence of audio output */
|
||||
strlcpy(vao->name, "FM Modulator Audio Out", 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int radio_si4713_enumaudout(struct file *file, void *priv,
|
||||
struct v4l2_audioout *vao)
|
||||
{
|
||||
return radio_si4713_fill_audout(vao);
|
||||
}
|
||||
|
||||
static int radio_si4713_g_audout(struct file *file, void *priv,
|
||||
struct v4l2_audioout *vao)
|
||||
{
|
||||
int rval = radio_si4713_fill_audout(vao);
|
||||
|
||||
vao->index = 0;
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int radio_si4713_s_audout(struct file *file, void *priv,
|
||||
struct v4l2_audioout *vao)
|
||||
{
|
||||
return vao->index ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
/* radio_si4713_querycap - query device capabilities */
|
||||
static int radio_si4713_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *capability)
|
||||
{
|
||||
struct radio_si4713_device *rsdev;
|
||||
|
||||
rsdev = video_get_drvdata(video_devdata(file));
|
||||
|
||||
strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver));
|
||||
strlcpy(capability->card, "Silicon Labs Si4713 Modulator",
|
||||
sizeof(capability->card));
|
||||
capability->capabilities = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* radio_si4713_queryctrl - enumerate control items */
|
||||
static int radio_si4713_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
/* Must be sorted from low to high control ID! */
|
||||
static const u32 user_ctrls[] = {
|
||||
V4L2_CID_USER_CLASS,
|
||||
V4L2_CID_AUDIO_MUTE,
|
||||
0
|
||||
};
|
||||
|
||||
/* Must be sorted from low to high control ID! */
|
||||
static const u32 fmtx_ctrls[] = {
|
||||
V4L2_CID_FM_TX_CLASS,
|
||||
V4L2_CID_RDS_TX_DEVIATION,
|
||||
V4L2_CID_RDS_TX_PI,
|
||||
V4L2_CID_RDS_TX_PTY,
|
||||
V4L2_CID_RDS_TX_PS_NAME,
|
||||
V4L2_CID_RDS_TX_RADIO_TEXT,
|
||||
V4L2_CID_AUDIO_LIMITER_ENABLED,
|
||||
V4L2_CID_AUDIO_LIMITER_RELEASE_TIME,
|
||||
V4L2_CID_AUDIO_LIMITER_DEVIATION,
|
||||
V4L2_CID_AUDIO_COMPRESSION_ENABLED,
|
||||
V4L2_CID_AUDIO_COMPRESSION_GAIN,
|
||||
V4L2_CID_AUDIO_COMPRESSION_THRESHOLD,
|
||||
V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME,
|
||||
V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME,
|
||||
V4L2_CID_PILOT_TONE_ENABLED,
|
||||
V4L2_CID_PILOT_TONE_DEVIATION,
|
||||
V4L2_CID_PILOT_TONE_FREQUENCY,
|
||||
V4L2_CID_TUNE_PREEMPHASIS,
|
||||
V4L2_CID_TUNE_POWER_LEVEL,
|
||||
V4L2_CID_TUNE_ANTENNA_CAPACITOR,
|
||||
0
|
||||
};
|
||||
static const u32 *ctrl_classes[] = {
|
||||
user_ctrls,
|
||||
fmtx_ctrls,
|
||||
NULL
|
||||
};
|
||||
struct radio_si4713_device *rsdev;
|
||||
|
||||
rsdev = video_get_drvdata(video_devdata(file));
|
||||
|
||||
qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
|
||||
if (qc->id == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (qc->id == V4L2_CID_USER_CLASS || qc->id == V4L2_CID_FM_TX_CLASS)
|
||||
return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0);
|
||||
|
||||
return v4l2_device_call_until_err(&rsdev->v4l2_dev, 0, core,
|
||||
queryctrl, qc);
|
||||
}
|
||||
|
||||
/*
|
||||
* v4l2 ioctl call backs.
|
||||
* we are just a wrapper for v4l2_sub_devs.
|
||||
*/
|
||||
static inline struct v4l2_device *get_v4l2_dev(struct file *file)
|
||||
{
|
||||
return &((struct radio_si4713_device *)video_drvdata(file))->v4l2_dev;
|
||||
}
|
||||
|
||||
static int radio_si4713_g_ext_ctrls(struct file *file, void *p,
|
||||
struct v4l2_ext_controls *vecs)
|
||||
{
|
||||
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
|
||||
g_ext_ctrls, vecs);
|
||||
}
|
||||
|
||||
static int radio_si4713_s_ext_ctrls(struct file *file, void *p,
|
||||
struct v4l2_ext_controls *vecs)
|
||||
{
|
||||
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
|
||||
s_ext_ctrls, vecs);
|
||||
}
|
||||
|
||||
static int radio_si4713_g_ctrl(struct file *file, void *p,
|
||||
struct v4l2_control *vc)
|
||||
{
|
||||
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
|
||||
g_ctrl, vc);
|
||||
}
|
||||
|
||||
static int radio_si4713_s_ctrl(struct file *file, void *p,
|
||||
struct v4l2_control *vc)
|
||||
{
|
||||
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
|
||||
s_ctrl, vc);
|
||||
}
|
||||
|
||||
static int radio_si4713_g_modulator(struct file *file, void *p,
|
||||
struct v4l2_modulator *vm)
|
||||
{
|
||||
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
|
||||
g_modulator, vm);
|
||||
}
|
||||
|
||||
static int radio_si4713_s_modulator(struct file *file, void *p,
|
||||
struct v4l2_modulator *vm)
|
||||
{
|
||||
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
|
||||
s_modulator, vm);
|
||||
}
|
||||
|
||||
static int radio_si4713_g_frequency(struct file *file, void *p,
|
||||
struct v4l2_frequency *vf)
|
||||
{
|
||||
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
|
||||
g_frequency, vf);
|
||||
}
|
||||
|
||||
static int radio_si4713_s_frequency(struct file *file, void *p,
|
||||
struct v4l2_frequency *vf)
|
||||
{
|
||||
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
|
||||
s_frequency, vf);
|
||||
}
|
||||
|
||||
static long radio_si4713_default(struct file *file, void *p, int cmd, void *arg)
|
||||
{
|
||||
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
|
||||
ioctl, cmd, arg);
|
||||
}
|
||||
|
||||
static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = {
|
||||
.vidioc_enumaudout = radio_si4713_enumaudout,
|
||||
.vidioc_g_audout = radio_si4713_g_audout,
|
||||
.vidioc_s_audout = radio_si4713_s_audout,
|
||||
.vidioc_querycap = radio_si4713_querycap,
|
||||
.vidioc_queryctrl = radio_si4713_queryctrl,
|
||||
.vidioc_g_ext_ctrls = radio_si4713_g_ext_ctrls,
|
||||
.vidioc_s_ext_ctrls = radio_si4713_s_ext_ctrls,
|
||||
.vidioc_g_ctrl = radio_si4713_g_ctrl,
|
||||
.vidioc_s_ctrl = radio_si4713_s_ctrl,
|
||||
.vidioc_g_modulator = radio_si4713_g_modulator,
|
||||
.vidioc_s_modulator = radio_si4713_s_modulator,
|
||||
.vidioc_g_frequency = radio_si4713_g_frequency,
|
||||
.vidioc_s_frequency = radio_si4713_s_frequency,
|
||||
.vidioc_default = radio_si4713_default,
|
||||
};
|
||||
|
||||
/* radio_si4713_vdev_template - video device interface */
|
||||
static struct video_device radio_si4713_vdev_template = {
|
||||
.fops = &radio_si4713_fops,
|
||||
.name = "radio-si4713",
|
||||
.release = video_device_release,
|
||||
.ioctl_ops = &radio_si4713_ioctl_ops,
|
||||
};
|
||||
|
||||
/* Platform driver interface */
|
||||
/* radio_si4713_pdriver_probe - probe for the device */
|
||||
static int radio_si4713_pdriver_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct radio_si4713_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct radio_si4713_device *rsdev;
|
||||
struct i2c_adapter *adapter;
|
||||
struct v4l2_subdev *sd;
|
||||
int rval = 0;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "Cannot proceed without platform data.\n");
|
||||
rval = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rsdev = kzalloc(sizeof *rsdev, GFP_KERNEL);
|
||||
if (!rsdev) {
|
||||
dev_err(&pdev->dev, "Failed to alloc video device.\n");
|
||||
rval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rval = v4l2_device_register(&pdev->dev, &rsdev->v4l2_dev);
|
||||
if (rval) {
|
||||
dev_err(&pdev->dev, "Failed to register v4l2 device.\n");
|
||||
goto free_rsdev;
|
||||
}
|
||||
|
||||
adapter = i2c_get_adapter(pdata->i2c_bus);
|
||||
if (!adapter) {
|
||||
dev_err(&pdev->dev, "Cannot get i2c adapter %d\n",
|
||||
pdata->i2c_bus);
|
||||
rval = -ENODEV;
|
||||
goto unregister_v4l2_dev;
|
||||
}
|
||||
|
||||
sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, "si4713_i2c",
|
||||
pdata->subdev_board_info, NULL);
|
||||
if (!sd) {
|
||||
dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
|
||||
rval = -ENODEV;
|
||||
goto unregister_v4l2_dev;
|
||||
}
|
||||
|
||||
rsdev->radio_dev = video_device_alloc();
|
||||
if (!rsdev->radio_dev) {
|
||||
dev_err(&pdev->dev, "Failed to alloc video device.\n");
|
||||
rval = -ENOMEM;
|
||||
goto unregister_v4l2_dev;
|
||||
}
|
||||
|
||||
memcpy(rsdev->radio_dev, &radio_si4713_vdev_template,
|
||||
sizeof(radio_si4713_vdev_template));
|
||||
video_set_drvdata(rsdev->radio_dev, rsdev);
|
||||
if (video_register_device(rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) {
|
||||
dev_err(&pdev->dev, "Could not register video device.\n");
|
||||
rval = -EIO;
|
||||
goto free_vdev;
|
||||
}
|
||||
dev_info(&pdev->dev, "New device successfully probed\n");
|
||||
|
||||
goto exit;
|
||||
|
||||
free_vdev:
|
||||
video_device_release(rsdev->radio_dev);
|
||||
unregister_v4l2_dev:
|
||||
v4l2_device_unregister(&rsdev->v4l2_dev);
|
||||
free_rsdev:
|
||||
kfree(rsdev);
|
||||
exit:
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* radio_si4713_pdriver_remove - remove the device */
|
||||
static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
|
||||
struct radio_si4713_device *rsdev = container_of(v4l2_dev,
|
||||
struct radio_si4713_device,
|
||||
v4l2_dev);
|
||||
|
||||
video_unregister_device(rsdev->radio_dev);
|
||||
v4l2_device_unregister(&rsdev->v4l2_dev);
|
||||
kfree(rsdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver radio_si4713_pdriver = {
|
||||
.driver = {
|
||||
.name = "radio-si4713",
|
||||
},
|
||||
.probe = radio_si4713_pdriver_probe,
|
||||
.remove = __exit_p(radio_si4713_pdriver_remove),
|
||||
};
|
||||
|
||||
/* Module Interface */
|
||||
static int __init radio_si4713_module_init(void)
|
||||
{
|
||||
return platform_driver_register(&radio_si4713_pdriver);
|
||||
}
|
||||
|
||||
static void __exit radio_si4713_module_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&radio_si4713_pdriver);
|
||||
}
|
||||
|
||||
module_init(radio_si4713_module_init);
|
||||
module_exit(radio_si4713_module_exit);
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
config USB_SI470X
|
||||
tristate "Silicon Labs Si470x FM Radio Receiver support with USB"
|
||||
depends on USB && RADIO_SI470X
|
||||
---help---
|
||||
This is a driver for USB devices with the Silicon Labs SI470x
|
||||
chip. Currently these devices are known to work:
|
||||
- 10c4:818a: Silicon Labs USB FM Radio Reference Design
|
||||
- 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music)
|
||||
- 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700)
|
||||
- 10c5:819a: Sanei Electric FM USB Radio (aka DealExtreme.com PCear)
|
||||
|
||||
Sound is provided by the ALSA USB Audio/MIDI driver. Therefore
|
||||
if you don't want to use the device solely for RDS receiving,
|
||||
it is recommended to also select SND_USB_AUDIO.
|
||||
|
||||
Please have a look at the documentation, especially on how
|
||||
to redirect the audio stream from the radio to your sound device:
|
||||
Documentation/video4linux/si470x.txt
|
||||
|
||||
Say Y here if you want to connect this type of radio to your
|
||||
computer's USB port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-usb-si470x.
|
||||
|
||||
config I2C_SI470X
|
||||
tristate "Silicon Labs Si470x FM Radio Receiver support with I2C"
|
||||
depends on I2C && RADIO_SI470X && !USB_SI470X
|
||||
---help---
|
||||
This is a driver for I2C devices with the Silicon Labs SI470x
|
||||
chip.
|
||||
|
||||
Say Y here if you want to connect this type of radio to your
|
||||
computer's I2C port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called radio-i2c-si470x.
|
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Makefile for radios with Silicon Labs Si470x FM Radio Receivers
|
||||
#
|
||||
|
||||
radio-usb-si470x-objs := radio-si470x-usb.o radio-si470x-common.o
|
||||
radio-i2c-si470x-objs := radio-si470x-i2c.o radio-si470x-common.o
|
||||
|
||||
obj-$(CONFIG_USB_SI470X) += radio-usb-si470x.o
|
||||
obj-$(CONFIG_I2C_SI470X) += radio-i2c-si470x.o
|
|
@ -0,0 +1,798 @@
|
|||
/*
|
||||
* drivers/media/radio/si470x/radio-si470x-common.c
|
||||
*
|
||||
* Driver for radios with Silicon Labs Si470x FM Radio Receivers
|
||||
*
|
||||
* Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* History:
|
||||
* 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Version 1.0.0
|
||||
* - First working version
|
||||
* 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Version 1.0.1
|
||||
* - Improved error handling, every function now returns errno
|
||||
* - Improved multi user access (start/mute/stop)
|
||||
* - Channel doesn't get lost anymore after start/mute/stop
|
||||
* - RDS support added (polling mode via interrupt EP 1)
|
||||
* - marked default module parameters with *value*
|
||||
* - switched from bit structs to bit masks
|
||||
* - header file cleaned and integrated
|
||||
* 2008-01-14 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Version 1.0.2
|
||||
* - hex values are now lower case
|
||||
* - commented USB ID for ADS/Tech moved on todo list
|
||||
* - blacklisted si470x in hid-quirks.c
|
||||
* - rds buffer handling functions integrated into *_work, *_read
|
||||
* - rds_command in si470x_poll exchanged against simple retval
|
||||
* - check for firmware version 15
|
||||
* - code order and prototypes still remain the same
|
||||
* - spacing and bottom of band codes remain the same
|
||||
* 2008-01-16 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Version 1.0.3
|
||||
* - code reordered to avoid function prototypes
|
||||
* - switch/case defaults are now more user-friendly
|
||||
* - unified comment style
|
||||
* - applied all checkpatch.pl v1.12 suggestions
|
||||
* except the warning about the too long lines with bit comments
|
||||
* - renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
|
||||
* 2008-01-22 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Version 1.0.4
|
||||
* - avoid poss. locking when doing copy_to_user which may sleep
|
||||
* - RDS is automatically activated on read now
|
||||
* - code cleaned of unnecessary rds_commands
|
||||
* - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
|
||||
* (thanks to Guillaume RAMOUSSE)
|
||||
* 2008-01-27 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Version 1.0.5
|
||||
* - number of seek_retries changed to tune_timeout
|
||||
* - fixed problem with incomplete tune operations by own buffers
|
||||
* - optimization of variables and printf types
|
||||
* - improved error logging
|
||||
* 2008-01-31 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Oliver Neukum <oliver@neukum.org>
|
||||
* Version 1.0.6
|
||||
* - fixed coverity checker warnings in *_usb_driver_disconnect
|
||||
* - probe()/open() race by correct ordering in probe()
|
||||
* - DMA coherency rules by separate allocation of all buffers
|
||||
* - use of endianness macros
|
||||
* - abuse of spinlock, replaced by mutex
|
||||
* - racy handling of timer in disconnect,
|
||||
* replaced by delayed_work
|
||||
* - racy interruptible_sleep_on(),
|
||||
* replaced with wait_event_interruptible()
|
||||
* - handle signals in read()
|
||||
* 2008-02-08 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Oliver Neukum <oliver@neukum.org>
|
||||
* Version 1.0.7
|
||||
* - usb autosuspend support
|
||||
* - unplugging fixed
|
||||
* 2008-05-07 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* Version 1.0.8
|
||||
* - hardware frequency seek support
|
||||
* - afc indication
|
||||
* - more safety checks, let si470x_get_freq return errno
|
||||
* - vidioc behavior corrected according to v4l2 spec
|
||||
* 2008-10-20 Alexey Klimov <klimov.linux@gmail.com>
|
||||
* - add support for KWorld USB FM Radio FM700
|
||||
* - blacklisted KWorld radio in hid-core.c and hid-ids.h
|
||||
* 2008-12-03 Mark Lord <mlord@pobox.com>
|
||||
* - add support for DealExtreme USB Radio
|
||||
* 2009-01-31 Bob Ross <pigiron@gmx.com>
|
||||
* - correction of stereo detection/setting
|
||||
* - correction of signal strength indicator scaling
|
||||
* 2009-01-31 Rick Bronson <rick@efn.org>
|
||||
* Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
* - add LED status output
|
||||
* - get HW/SW version from scratchpad
|
||||
* 2009-06-16 Edouard Lafargue <edouard@lafargue.name>
|
||||
* Version 1.0.10
|
||||
* - add support for interrupt mode for RDS endpoint,
|
||||
* instead of polling.
|
||||
* Improves RDS reception significantly
|
||||
*/
|
||||
|
||||
|
||||
/* kernel includes */
|
||||
#include "radio-si470x.h"
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Module Parameters
|
||||
**************************************************************************/
|
||||
|
||||
/* Spacing (kHz) */
|
||||
/* 0: 200 kHz (USA, Australia) */
|
||||
/* 1: 100 kHz (Europe, Japan) */
|
||||
/* 2: 50 kHz */
|
||||
static unsigned short space = 2;
|
||||
module_param(space, ushort, 0444);
|
||||
MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
|
||||
|
||||
/* Bottom of Band (MHz) */
|
||||
/* 0: 87.5 - 108 MHz (USA, Europe)*/
|
||||
/* 1: 76 - 108 MHz (Japan wide band) */
|
||||
/* 2: 76 - 90 MHz (Japan) */
|
||||
static unsigned short band = 1;
|
||||
module_param(band, ushort, 0444);
|
||||
MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
|
||||
|
||||
/* De-emphasis */
|
||||
/* 0: 75 us (USA) */
|
||||
/* 1: 50 us (Europe, Australia, Japan) */
|
||||
static unsigned short de = 1;
|
||||
module_param(de, ushort, 0444);
|
||||
MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
|
||||
|
||||
/* Tune timeout */
|
||||
static unsigned int tune_timeout = 3000;
|
||||
module_param(tune_timeout, uint, 0644);
|
||||
MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
|
||||
|
||||
/* Seek timeout */
|
||||
static unsigned int seek_timeout = 5000;
|
||||
module_param(seek_timeout, uint, 0644);
|
||||
MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Generic Functions
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_set_chan - set the channel
|
||||
*/
|
||||
static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
|
||||
{
|
||||
int retval;
|
||||
unsigned long timeout;
|
||||
bool timed_out = 0;
|
||||
|
||||
/* start tuning */
|
||||
radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
|
||||
radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
|
||||
retval = si470x_set_register(radio, CHANNEL);
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
|
||||
/* wait till tune operation has completed */
|
||||
timeout = jiffies + msecs_to_jiffies(tune_timeout);
|
||||
do {
|
||||
retval = si470x_get_register(radio, STATUSRSSI);
|
||||
if (retval < 0)
|
||||
goto stop;
|
||||
timed_out = time_after(jiffies, timeout);
|
||||
} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
|
||||
(!timed_out));
|
||||
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
|
||||
dev_warn(&radio->videodev->dev, "tune does not complete\n");
|
||||
if (timed_out)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"tune timed out after %u ms\n", tune_timeout);
|
||||
|
||||
stop:
|
||||
/* stop tuning */
|
||||
radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
|
||||
retval = si470x_set_register(radio, CHANNEL);
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_get_freq - get the frequency
|
||||
*/
|
||||
static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
|
||||
{
|
||||
unsigned int spacing, band_bottom;
|
||||
unsigned short chan;
|
||||
int retval;
|
||||
|
||||
/* Spacing (kHz) */
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
|
||||
/* 0: 200 kHz (USA, Australia) */
|
||||
case 0:
|
||||
spacing = 0.200 * FREQ_MUL; break;
|
||||
/* 1: 100 kHz (Europe, Japan) */
|
||||
case 1:
|
||||
spacing = 0.100 * FREQ_MUL; break;
|
||||
/* 2: 50 kHz */
|
||||
default:
|
||||
spacing = 0.050 * FREQ_MUL; break;
|
||||
};
|
||||
|
||||
/* Bottom of Band (MHz) */
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
|
||||
/* 0: 87.5 - 108 MHz (USA, Europe) */
|
||||
case 0:
|
||||
band_bottom = 87.5 * FREQ_MUL; break;
|
||||
/* 1: 76 - 108 MHz (Japan wide band) */
|
||||
default:
|
||||
band_bottom = 76 * FREQ_MUL; break;
|
||||
/* 2: 76 - 90 MHz (Japan) */
|
||||
case 2:
|
||||
band_bottom = 76 * FREQ_MUL; break;
|
||||
};
|
||||
|
||||
/* read channel */
|
||||
retval = si470x_get_register(radio, READCHAN);
|
||||
chan = radio->registers[READCHAN] & READCHAN_READCHAN;
|
||||
|
||||
/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
|
||||
*freq = chan * spacing + band_bottom;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_set_freq - set the frequency
|
||||
*/
|
||||
int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
|
||||
{
|
||||
unsigned int spacing, band_bottom;
|
||||
unsigned short chan;
|
||||
|
||||
/* Spacing (kHz) */
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
|
||||
/* 0: 200 kHz (USA, Australia) */
|
||||
case 0:
|
||||
spacing = 0.200 * FREQ_MUL; break;
|
||||
/* 1: 100 kHz (Europe, Japan) */
|
||||
case 1:
|
||||
spacing = 0.100 * FREQ_MUL; break;
|
||||
/* 2: 50 kHz */
|
||||
default:
|
||||
spacing = 0.050 * FREQ_MUL; break;
|
||||
};
|
||||
|
||||
/* Bottom of Band (MHz) */
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
|
||||
/* 0: 87.5 - 108 MHz (USA, Europe) */
|
||||
case 0:
|
||||
band_bottom = 87.5 * FREQ_MUL; break;
|
||||
/* 1: 76 - 108 MHz (Japan wide band) */
|
||||
default:
|
||||
band_bottom = 76 * FREQ_MUL; break;
|
||||
/* 2: 76 - 90 MHz (Japan) */
|
||||
case 2:
|
||||
band_bottom = 76 * FREQ_MUL; break;
|
||||
};
|
||||
|
||||
/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
|
||||
chan = (freq - band_bottom) / spacing;
|
||||
|
||||
return si470x_set_chan(radio, chan);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_set_seek - set seek
|
||||
*/
|
||||
static int si470x_set_seek(struct si470x_device *radio,
|
||||
unsigned int wrap_around, unsigned int seek_upward)
|
||||
{
|
||||
int retval = 0;
|
||||
unsigned long timeout;
|
||||
bool timed_out = 0;
|
||||
|
||||
/* start seeking */
|
||||
radio->registers[POWERCFG] |= POWERCFG_SEEK;
|
||||
if (wrap_around == 1)
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
|
||||
else
|
||||
radio->registers[POWERCFG] |= POWERCFG_SKMODE;
|
||||
if (seek_upward == 1)
|
||||
radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
|
||||
else
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
|
||||
/* wait till seek operation has completed */
|
||||
timeout = jiffies + msecs_to_jiffies(seek_timeout);
|
||||
do {
|
||||
retval = si470x_get_register(radio, STATUSRSSI);
|
||||
if (retval < 0)
|
||||
goto stop;
|
||||
timed_out = time_after(jiffies, timeout);
|
||||
} while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
|
||||
(!timed_out));
|
||||
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
|
||||
dev_warn(&radio->videodev->dev, "seek does not complete\n");
|
||||
if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"seek failed / band limit reached\n");
|
||||
if (timed_out)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"seek timed out after %u ms\n", seek_timeout);
|
||||
|
||||
stop:
|
||||
/* stop seeking */
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
|
||||
done:
|
||||
/* try again, if timed out */
|
||||
if ((retval == 0) && timed_out)
|
||||
retval = -EAGAIN;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_start - switch on radio
|
||||
*/
|
||||
int si470x_start(struct si470x_device *radio)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* powercfg */
|
||||
radio->registers[POWERCFG] =
|
||||
POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
|
||||
/* sysconfig 1 */
|
||||
radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
|
||||
retval = si470x_set_register(radio, SYSCONFIG1);
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
|
||||
/* sysconfig 2 */
|
||||
radio->registers[SYSCONFIG2] =
|
||||
(0x3f << 8) | /* SEEKTH */
|
||||
((band << 6) & SYSCONFIG2_BAND) | /* BAND */
|
||||
((space << 4) & SYSCONFIG2_SPACE) | /* SPACE */
|
||||
15; /* VOLUME (max) */
|
||||
retval = si470x_set_register(radio, SYSCONFIG2);
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
|
||||
/* reset last channel */
|
||||
retval = si470x_set_chan(radio,
|
||||
radio->registers[CHANNEL] & CHANNEL_CHAN);
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_stop - switch off radio
|
||||
*/
|
||||
int si470x_stop(struct si470x_device *radio)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* sysconfig 1 */
|
||||
radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
|
||||
retval = si470x_set_register(radio, SYSCONFIG1);
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
|
||||
/* powercfg */
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
|
||||
/* POWERCFG_ENABLE has to automatically go low */
|
||||
radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_rds_on - switch on rds reception
|
||||
*/
|
||||
int si470x_rds_on(struct si470x_device *radio)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* sysconfig 1 */
|
||||
mutex_lock(&radio->lock);
|
||||
radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
|
||||
retval = si470x_set_register(radio, SYSCONFIG1);
|
||||
if (retval < 0)
|
||||
radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Video4Linux Interface
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_vidioc_queryctrl - enumerate control items
|
||||
*/
|
||||
static int si470x_vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = -EINVAL;
|
||||
|
||||
/* abort if qc->id is below V4L2_CID_BASE */
|
||||
if (qc->id < V4L2_CID_BASE)
|
||||
goto done;
|
||||
|
||||
/* search video control */
|
||||
switch (qc->id) {
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15);
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
|
||||
}
|
||||
|
||||
/* disable unsupported base controls */
|
||||
/* to satisfy kradio and such apps */
|
||||
if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
|
||||
qc->flags = V4L2_CTRL_FLAG_DISABLED;
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"query controls failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_g_ctrl - get the value of a control
|
||||
*/
|
||||
static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
retval = si470x_disconnect_check(radio);
|
||||
if (retval)
|
||||
goto done;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value = radio->registers[SYSCONFIG2] &
|
||||
SYSCONFIG2_VOLUME;
|
||||
break;
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = ((radio->registers[POWERCFG] &
|
||||
POWERCFG_DMUTE) == 0) ? 1 : 0;
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
}
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"get control failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_s_ctrl - set the value of a control
|
||||
*/
|
||||
static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
retval = si470x_disconnect_check(radio);
|
||||
if (retval)
|
||||
goto done;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
|
||||
radio->registers[SYSCONFIG2] |= ctrl->value;
|
||||
retval = si470x_set_register(radio, SYSCONFIG2);
|
||||
break;
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value == 1)
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
|
||||
else
|
||||
radio->registers[POWERCFG] |= POWERCFG_DMUTE;
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
}
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"set control failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_g_audio - get audio attributes
|
||||
*/
|
||||
static int si470x_vidioc_g_audio(struct file *file, void *priv,
|
||||
struct v4l2_audio *audio)
|
||||
{
|
||||
/* driver constants */
|
||||
audio->index = 0;
|
||||
strcpy(audio->name, "Radio");
|
||||
audio->capability = V4L2_AUDCAP_STEREO;
|
||||
audio->mode = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_g_tuner - get tuner attributes
|
||||
*/
|
||||
static int si470x_vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *tuner)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
retval = si470x_disconnect_check(radio);
|
||||
if (retval)
|
||||
goto done;
|
||||
|
||||
if (tuner->index != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
retval = si470x_get_register(radio, STATUSRSSI);
|
||||
if (retval < 0)
|
||||
goto done;
|
||||
|
||||
/* driver constants */
|
||||
strcpy(tuner->name, "FM");
|
||||
tuner->type = V4L2_TUNER_RADIO;
|
||||
#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
|
||||
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
|
||||
V4L2_TUNER_CAP_RDS;
|
||||
#else
|
||||
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
|
||||
#endif
|
||||
|
||||
/* range limits */
|
||||
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
|
||||
/* 0: 87.5 - 108 MHz (USA, Europe, default) */
|
||||
default:
|
||||
tuner->rangelow = 87.5 * FREQ_MUL;
|
||||
tuner->rangehigh = 108 * FREQ_MUL;
|
||||
break;
|
||||
/* 1: 76 - 108 MHz (Japan wide band) */
|
||||
case 1:
|
||||
tuner->rangelow = 76 * FREQ_MUL;
|
||||
tuner->rangehigh = 108 * FREQ_MUL;
|
||||
break;
|
||||
/* 2: 76 - 90 MHz (Japan) */
|
||||
case 2:
|
||||
tuner->rangelow = 76 * FREQ_MUL;
|
||||
tuner->rangehigh = 90 * FREQ_MUL;
|
||||
break;
|
||||
};
|
||||
|
||||
/* stereo indicator == stereo (instead of mono) */
|
||||
if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
|
||||
tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
else
|
||||
tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
|
||||
#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
|
||||
/* If there is a reliable method of detecting an RDS channel,
|
||||
then this code should check for that before setting this
|
||||
RDS subchannel. */
|
||||
tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
|
||||
#endif
|
||||
|
||||
/* mono/stereo selector */
|
||||
if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
|
||||
tuner->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
tuner->audmode = V4L2_TUNER_MODE_MONO;
|
||||
|
||||
/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
|
||||
/* measured in units of db쨉V in 1 db increments (max at ~75 db쨉V) */
|
||||
tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
|
||||
/* the ideal factor is 0xffff/75 = 873,8 */
|
||||
tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
|
||||
|
||||
/* automatic frequency control: -1: freq to low, 1 freq to high */
|
||||
/* AFCRL does only indicate that freq. differs, not if too low/high */
|
||||
tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"get tuner failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_s_tuner - set tuner attributes
|
||||
*/
|
||||
static int si470x_vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *tuner)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = -EINVAL;
|
||||
|
||||
/* safety checks */
|
||||
retval = si470x_disconnect_check(radio);
|
||||
if (retval)
|
||||
goto done;
|
||||
|
||||
if (tuner->index != 0)
|
||||
goto done;
|
||||
|
||||
/* mono/stereo selector */
|
||||
switch (tuner->audmode) {
|
||||
case V4L2_TUNER_MODE_MONO:
|
||||
radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */
|
||||
break;
|
||||
case V4L2_TUNER_MODE_STEREO:
|
||||
radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
|
||||
break;
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
|
||||
retval = si470x_set_register(radio, POWERCFG);
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"set tuner failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_g_frequency - get tuner or modulator radio frequency
|
||||
*/
|
||||
static int si470x_vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *freq)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
retval = si470x_disconnect_check(radio);
|
||||
if (retval)
|
||||
goto done;
|
||||
|
||||
if (freq->tuner != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
freq->type = V4L2_TUNER_RADIO;
|
||||
retval = si470x_get_freq(radio, &freq->frequency);
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"get frequency failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_s_frequency - set tuner or modulator radio frequency
|
||||
*/
|
||||
static int si470x_vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *freq)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
retval = si470x_disconnect_check(radio);
|
||||
if (retval)
|
||||
goto done;
|
||||
|
||||
if (freq->tuner != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
retval = si470x_set_freq(radio, freq->frequency);
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"set frequency failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
|
||||
*/
|
||||
static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
|
||||
struct v4l2_hw_freq_seek *seek)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
/* safety checks */
|
||||
retval = si470x_disconnect_check(radio);
|
||||
if (retval)
|
||||
goto done;
|
||||
|
||||
if (seek->tuner != 0) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
|
||||
|
||||
done:
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->videodev->dev,
|
||||
"set hardware frequency seek failed with %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_ioctl_ops - video device ioctl operations
|
||||
*/
|
||||
static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
|
||||
.vidioc_querycap = si470x_vidioc_querycap,
|
||||
.vidioc_queryctrl = si470x_vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = si470x_vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = si470x_vidioc_s_ctrl,
|
||||
.vidioc_g_audio = si470x_vidioc_g_audio,
|
||||
.vidioc_g_tuner = si470x_vidioc_g_tuner,
|
||||
.vidioc_s_tuner = si470x_vidioc_s_tuner,
|
||||
.vidioc_g_frequency = si470x_vidioc_g_frequency,
|
||||
.vidioc_s_frequency = si470x_vidioc_s_frequency,
|
||||
.vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* si470x_viddev_template - video device interface
|
||||
*/
|
||||
struct video_device si470x_viddev_template = {
|
||||
.fops = &si470x_fops,
|
||||
.name = DRIVER_NAME,
|
||||
.release = video_device_release,
|
||||
.ioctl_ops = &si470x_ioctl_ops,
|
||||
};
|
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
* drivers/media/radio/si470x/radio-si470x-i2c.c
|
||||
*
|
||||
* I2C driver for radios with Silicon Labs Si470x FM Radio Receivers
|
||||
*
|
||||
* Copyright (c) 2009 Samsung Electronics Co.Ltd
|
||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* ToDo:
|
||||
* - RDS support
|
||||
*/
|
||||
|
||||
|
||||
/* driver definitions */
|
||||
#define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>";
|
||||
#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 0)
|
||||
#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
|
||||
#define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers"
|
||||
#define DRIVER_VERSION "1.0.0"
|
||||
|
||||
/* kernel includes */
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "radio-si470x.h"
|
||||
|
||||
|
||||
/* I2C Device ID List */
|
||||
static const struct i2c_device_id si470x_i2c_id[] = {
|
||||
/* Generic Entry */
|
||||
{ "si470x", 0 },
|
||||
/* Terminating entry */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, si470x_i2c_id);
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Module Parameters
|
||||
**************************************************************************/
|
||||
|
||||
/* Radio Nr */
|
||||
static int radio_nr = -1;
|
||||
module_param(radio_nr, int, 0444);
|
||||
MODULE_PARM_DESC(radio_nr, "Radio Nr");
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* I2C Definitions
|
||||
**************************************************************************/
|
||||
|
||||
/* Write starts with the upper byte of register 0x02 */
|
||||
#define WRITE_REG_NUM 8
|
||||
#define WRITE_INDEX(i) (i + 0x02)
|
||||
|
||||
/* Read starts with the upper byte of register 0x0a */
|
||||
#define READ_REG_NUM RADIO_REGISTER_NUM
|
||||
#define READ_INDEX(i) ((i + RADIO_REGISTER_NUM - 0x0a) % READ_REG_NUM)
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Functions - REGISTERs
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_get_register - read register
|
||||
*/
|
||||
int si470x_get_register(struct si470x_device *radio, int regnr)
|
||||
{
|
||||
u16 buf[READ_REG_NUM];
|
||||
struct i2c_msg msgs[1] = {
|
||||
{ radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM,
|
||||
(void *)buf },
|
||||
};
|
||||
|
||||
if (i2c_transfer(radio->client->adapter, msgs, 1) != 1)
|
||||
return -EIO;
|
||||
|
||||
radio->registers[regnr] = __be16_to_cpu(buf[READ_INDEX(regnr)]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_set_register - write register
|
||||
*/
|
||||
int si470x_set_register(struct si470x_device *radio, int regnr)
|
||||
{
|
||||
int i;
|
||||
u16 buf[WRITE_REG_NUM];
|
||||
struct i2c_msg msgs[1] = {
|
||||
{ radio->client->addr, 0, sizeof(u16) * WRITE_REG_NUM,
|
||||
(void *)buf },
|
||||
};
|
||||
|
||||
for (i = 0; i < WRITE_REG_NUM; i++)
|
||||
buf[i] = __cpu_to_be16(radio->registers[WRITE_INDEX(i)]);
|
||||
|
||||
if (i2c_transfer(radio->client->adapter, msgs, 1) != 1)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Functions - ENTIRE REGISTERS
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_get_all_registers - read entire registers
|
||||
*/
|
||||
static int si470x_get_all_registers(struct si470x_device *radio)
|
||||
{
|
||||
int i;
|
||||
u16 buf[READ_REG_NUM];
|
||||
struct i2c_msg msgs[1] = {
|
||||
{ radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM,
|
||||
(void *)buf },
|
||||
};
|
||||
|
||||
if (i2c_transfer(radio->client->adapter, msgs, 1) != 1)
|
||||
return -EIO;
|
||||
|
||||
for (i = 0; i < READ_REG_NUM; i++)
|
||||
radio->registers[i] = __be16_to_cpu(buf[READ_INDEX(i)]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Functions - DISCONNECT_CHECK
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_disconnect_check - check whether radio disconnects
|
||||
*/
|
||||
int si470x_disconnect_check(struct si470x_device *radio)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* File Operations Interface
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_fops_open - file open
|
||||
*/
|
||||
static int si470x_fops_open(struct file *file)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
radio->users++;
|
||||
|
||||
if (radio->users == 1)
|
||||
/* start radio */
|
||||
retval = si470x_start(radio);
|
||||
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_fops_release - file release
|
||||
*/
|
||||
static int si470x_fops_release(struct file *file)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
/* safety check */
|
||||
if (!radio)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
radio->users--;
|
||||
if (radio->users == 0)
|
||||
/* stop radio */
|
||||
retval = si470x_stop(radio);
|
||||
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_fops - file operations interface
|
||||
*/
|
||||
const struct v4l2_file_operations si470x_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = video_ioctl2,
|
||||
.open = si470x_fops_open,
|
||||
.release = si470x_fops_release,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Video4Linux Interface
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_vidioc_querycap - query device capabilities
|
||||
*/
|
||||
int si470x_vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *capability)
|
||||
{
|
||||
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
|
||||
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
|
||||
capability->version = DRIVER_KERNEL_VERSION;
|
||||
capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
|
||||
V4L2_CAP_TUNER | V4L2_CAP_RADIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* I2C Interface
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_i2c_probe - probe for the device
|
||||
*/
|
||||
static int __devinit si470x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct si470x_device *radio;
|
||||
int retval = 0;
|
||||
unsigned char version_warning = 0;
|
||||
|
||||
/* private data allocation and initialization */
|
||||
radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
|
||||
if (!radio) {
|
||||
retval = -ENOMEM;
|
||||
goto err_initial;
|
||||
}
|
||||
radio->users = 0;
|
||||
radio->client = client;
|
||||
mutex_init(&radio->lock);
|
||||
|
||||
/* video device allocation and initialization */
|
||||
radio->videodev = video_device_alloc();
|
||||
if (!radio->videodev) {
|
||||
retval = -ENOMEM;
|
||||
goto err_radio;
|
||||
}
|
||||
memcpy(radio->videodev, &si470x_viddev_template,
|
||||
sizeof(si470x_viddev_template));
|
||||
video_set_drvdata(radio->videodev, radio);
|
||||
|
||||
/* power up : need 110ms */
|
||||
radio->registers[POWERCFG] = POWERCFG_ENABLE;
|
||||
if (si470x_set_register(radio, POWERCFG) < 0) {
|
||||
retval = -EIO;
|
||||
goto err_all;
|
||||
}
|
||||
msleep(110);
|
||||
|
||||
/* get device and chip versions */
|
||||
if (si470x_get_all_registers(radio) < 0) {
|
||||
retval = -EIO;
|
||||
goto err_video;
|
||||
}
|
||||
dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
|
||||
radio->registers[DEVICEID], radio->registers[CHIPID]);
|
||||
if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) {
|
||||
dev_warn(&client->dev,
|
||||
"This driver is known to work with "
|
||||
"firmware version %hu,\n", RADIO_FW_VERSION);
|
||||
dev_warn(&client->dev,
|
||||
"but the device has firmware version %hu.\n",
|
||||
radio->registers[CHIPID] & CHIPID_FIRMWARE);
|
||||
version_warning = 1;
|
||||
}
|
||||
|
||||
/* give out version warning */
|
||||
if (version_warning == 1) {
|
||||
dev_warn(&client->dev,
|
||||
"If you have some trouble using this driver,\n");
|
||||
dev_warn(&client->dev,
|
||||
"please report to V4L ML at "
|
||||
"linux-media@vger.kernel.org\n");
|
||||
}
|
||||
|
||||
/* set initial frequency */
|
||||
si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
|
||||
|
||||
/* register video device */
|
||||
retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
|
||||
radio_nr);
|
||||
if (retval) {
|
||||
dev_warn(&client->dev, "Could not register video device\n");
|
||||
goto err_all;
|
||||
}
|
||||
i2c_set_clientdata(client, radio);
|
||||
|
||||
return 0;
|
||||
err_all:
|
||||
err_video:
|
||||
video_device_release(radio->videodev);
|
||||
err_radio:
|
||||
kfree(radio);
|
||||
err_initial:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_i2c_remove - remove the device
|
||||
*/
|
||||
static __devexit int si470x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct si470x_device *radio = i2c_get_clientdata(client);
|
||||
|
||||
video_unregister_device(radio->videodev);
|
||||
kfree(radio);
|
||||
i2c_set_clientdata(client, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_i2c_driver - i2c driver interface
|
||||
*/
|
||||
static struct i2c_driver si470x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "si470x",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = si470x_i2c_probe,
|
||||
.remove = __devexit_p(si470x_i2c_remove),
|
||||
.id_table = si470x_i2c_id,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Module Interface
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_i2c_init - module init
|
||||
*/
|
||||
static int __init si470x_i2c_init(void)
|
||||
{
|
||||
printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
|
||||
return i2c_add_driver(&si470x_i2c_driver);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_i2c_exit - module exit
|
||||
*/
|
||||
static void __exit si470x_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&si470x_i2c_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init(si470x_i2c_init);
|
||||
module_exit(si470x_i2c_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
|
@ -0,0 +1,988 @@
|
|||
/*
|
||||
* drivers/media/radio/si470x/radio-si470x-usb.c
|
||||
*
|
||||
* USB driver for radios with Silicon Labs Si470x FM Radio Receivers
|
||||
*
|
||||
* Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* ToDo:
|
||||
* - add firmware download/update support
|
||||
*/
|
||||
|
||||
|
||||
/* driver definitions */
|
||||
#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
|
||||
#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 10)
|
||||
#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
|
||||
#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
|
||||
#define DRIVER_VERSION "1.0.10"
|
||||
|
||||
/* kernel includes */
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
#include "radio-si470x.h"
|
||||
|
||||
|
||||
/* USB Device ID List */
|
||||
static struct usb_device_id si470x_usb_driver_id_table[] = {
|
||||
/* Silicon Labs USB FM Radio Reference Design */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
|
||||
/* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) },
|
||||
/* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) },
|
||||
/* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) },
|
||||
/* Terminating entry */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Module Parameters
|
||||
**************************************************************************/
|
||||
|
||||
/* Radio Nr */
|
||||
static int radio_nr = -1;
|
||||
module_param(radio_nr, int, 0444);
|
||||
MODULE_PARM_DESC(radio_nr, "Radio Nr");
|
||||
|
||||
/* USB timeout */
|
||||
static unsigned int usb_timeout = 500;
|
||||
module_param(usb_timeout, uint, 0644);
|
||||
MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
|
||||
|
||||
/* RDS buffer blocks */
|
||||
static unsigned int rds_buf = 100;
|
||||
module_param(rds_buf, uint, 0444);
|
||||
MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
|
||||
|
||||
/* RDS maximum block errors */
|
||||
static unsigned short max_rds_errors = 1;
|
||||
/* 0 means 0 errors requiring correction */
|
||||
/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */
|
||||
/* 2 means 3-5 errors requiring correction */
|
||||
/* 3 means 6+ errors or errors in checkword, correction not possible */
|
||||
module_param(max_rds_errors, ushort, 0644);
|
||||
MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* USB HID Reports
|
||||
**************************************************************************/
|
||||
|
||||
/* Reports 1-16 give direct read/write access to the 16 Si470x registers */
|
||||
/* with the (REPORT_ID - 1) corresponding to the register address across USB */
|
||||
/* endpoint 0 using GET_REPORT and SET_REPORT */
|
||||
#define REGISTER_REPORT_SIZE (RADIO_REGISTER_SIZE + 1)
|
||||
#define REGISTER_REPORT(reg) ((reg) + 1)
|
||||
|
||||
/* Report 17 gives direct read/write access to the entire Si470x register */
|
||||
/* map across endpoint 0 using GET_REPORT and SET_REPORT */
|
||||
#define ENTIRE_REPORT_SIZE (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
|
||||
#define ENTIRE_REPORT 17
|
||||
|
||||
/* Report 18 is used to send the lowest 6 Si470x registers up the HID */
|
||||
/* interrupt endpoint 1 to Windows every 20 milliseconds for status */
|
||||
#define RDS_REPORT_SIZE (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
|
||||
#define RDS_REPORT 18
|
||||
|
||||
/* Report 19: LED state */
|
||||
#define LED_REPORT_SIZE 3
|
||||
#define LED_REPORT 19
|
||||
|
||||
/* Report 19: stream */
|
||||
#define STREAM_REPORT_SIZE 3
|
||||
#define STREAM_REPORT 19
|
||||
|
||||
/* Report 20: scratch */
|
||||
#define SCRATCH_PAGE_SIZE 63
|
||||
#define SCRATCH_REPORT_SIZE (SCRATCH_PAGE_SIZE + 1)
|
||||
#define SCRATCH_REPORT 20
|
||||
|
||||
/* Reports 19-22: flash upgrade of the C8051F321 */
|
||||
#define WRITE_REPORT_SIZE 4
|
||||
#define WRITE_REPORT 19
|
||||
#define FLASH_REPORT_SIZE 64
|
||||
#define FLASH_REPORT 20
|
||||
#define CRC_REPORT_SIZE 3
|
||||
#define CRC_REPORT 21
|
||||
#define RESPONSE_REPORT_SIZE 2
|
||||
#define RESPONSE_REPORT 22
|
||||
|
||||
/* Report 23: currently unused, but can accept 60 byte reports on the HID */
|
||||
/* interrupt out endpoint 2 every 1 millisecond */
|
||||
#define UNUSED_REPORT 23
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Software/Hardware Versions from Scratch Page
|
||||
**************************************************************************/
|
||||
#define RADIO_SW_VERSION_NOT_BOOTLOADABLE 6
|
||||
#define RADIO_SW_VERSION 7
|
||||
#define RADIO_HW_VERSION 1
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* LED State Definitions
|
||||
**************************************************************************/
|
||||
#define LED_COMMAND 0x35
|
||||
|
||||
#define NO_CHANGE_LED 0x00
|
||||
#define ALL_COLOR_LED 0x01 /* streaming state */
|
||||
#define BLINK_GREEN_LED 0x02 /* connect state */
|
||||
#define BLINK_RED_LED 0x04
|
||||
#define BLINK_ORANGE_LED 0x10 /* disconnect state */
|
||||
#define SOLID_GREEN_LED 0x20 /* tuning/seeking state */
|
||||
#define SOLID_RED_LED 0x40 /* bootload state */
|
||||
#define SOLID_ORANGE_LED 0x80
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Stream State Definitions
|
||||
**************************************************************************/
|
||||
#define STREAM_COMMAND 0x36
|
||||
#define STREAM_VIDPID 0x00
|
||||
#define STREAM_AUDIO 0xff
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Bootloader / Flash Commands
|
||||
**************************************************************************/
|
||||
|
||||
/* unique id sent to bootloader and required to put into a bootload state */
|
||||
#define UNIQUE_BL_ID 0x34
|
||||
|
||||
/* mask for the flash data */
|
||||
#define FLASH_DATA_MASK 0x55
|
||||
|
||||
/* bootloader commands */
|
||||
#define GET_SW_VERSION_COMMAND 0x00
|
||||
#define SET_PAGE_COMMAND 0x01
|
||||
#define ERASE_PAGE_COMMAND 0x02
|
||||
#define WRITE_PAGE_COMMAND 0x03
|
||||
#define CRC_ON_PAGE_COMMAND 0x04
|
||||
#define READ_FLASH_BYTE_COMMAND 0x05
|
||||
#define RESET_DEVICE_COMMAND 0x06
|
||||
#define GET_HW_VERSION_COMMAND 0x07
|
||||
#define BLANK 0xff
|
||||
|
||||
/* bootloader command responses */
|
||||
#define COMMAND_OK 0x01
|
||||
#define COMMAND_FAILED 0x02
|
||||
#define COMMAND_PENDING 0x03
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Functions - REGISTER_REPORTs
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_get_report - receive a HID report
|
||||
*/
|
||||
static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
|
||||
{
|
||||
unsigned char *report = (unsigned char *) buf;
|
||||
int retval;
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_rcvctrlpipe(radio->usbdev, 0),
|
||||
HID_REQ_GET_REPORT,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
|
||||
report[0], 2,
|
||||
buf, size, usb_timeout);
|
||||
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->intf->dev,
|
||||
"si470x_get_report: usb_control_msg returned %d\n",
|
||||
retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_set_report - send a HID report
|
||||
*/
|
||||
static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
|
||||
{
|
||||
unsigned char *report = (unsigned char *) buf;
|
||||
int retval;
|
||||
|
||||
retval = usb_control_msg(radio->usbdev,
|
||||
usb_sndctrlpipe(radio->usbdev, 0),
|
||||
HID_REQ_SET_REPORT,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
|
||||
report[0], 2,
|
||||
buf, size, usb_timeout);
|
||||
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->intf->dev,
|
||||
"si470x_set_report: usb_control_msg returned %d\n",
|
||||
retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_get_register - read register
|
||||
*/
|
||||
int si470x_get_register(struct si470x_device *radio, int regnr)
|
||||
{
|
||||
unsigned char buf[REGISTER_REPORT_SIZE];
|
||||
int retval;
|
||||
|
||||
buf[0] = REGISTER_REPORT(regnr);
|
||||
|
||||
retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
|
||||
|
||||
if (retval >= 0)
|
||||
radio->registers[regnr] = get_unaligned_be16(&buf[1]);
|
||||
|
||||
return (retval < 0) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_set_register - write register
|
||||
*/
|
||||
int si470x_set_register(struct si470x_device *radio, int regnr)
|
||||
{
|
||||
unsigned char buf[REGISTER_REPORT_SIZE];
|
||||
int retval;
|
||||
|
||||
buf[0] = REGISTER_REPORT(regnr);
|
||||
put_unaligned_be16(radio->registers[regnr], &buf[1]);
|
||||
|
||||
retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
|
||||
|
||||
return (retval < 0) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Functions - ENTIRE_REPORT
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_get_all_registers - read entire registers
|
||||
*/
|
||||
static int si470x_get_all_registers(struct si470x_device *radio)
|
||||
{
|
||||
unsigned char buf[ENTIRE_REPORT_SIZE];
|
||||
int retval;
|
||||
unsigned char regnr;
|
||||
|
||||
buf[0] = ENTIRE_REPORT;
|
||||
|
||||
retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
|
||||
|
||||
if (retval >= 0)
|
||||
for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
|
||||
radio->registers[regnr] = get_unaligned_be16(
|
||||
&buf[regnr * RADIO_REGISTER_SIZE + 1]);
|
||||
|
||||
return (retval < 0) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Functions - LED_REPORT
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_set_led_state - sets the led state
|
||||
*/
|
||||
static int si470x_set_led_state(struct si470x_device *radio,
|
||||
unsigned char led_state)
|
||||
{
|
||||
unsigned char buf[LED_REPORT_SIZE];
|
||||
int retval;
|
||||
|
||||
buf[0] = LED_REPORT;
|
||||
buf[1] = LED_COMMAND;
|
||||
buf[2] = led_state;
|
||||
|
||||
retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
|
||||
|
||||
return (retval < 0) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Functions - SCRATCH_REPORT
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_get_scratch_versions - gets the scratch page and version infos
|
||||
*/
|
||||
static int si470x_get_scratch_page_versions(struct si470x_device *radio)
|
||||
{
|
||||
unsigned char buf[SCRATCH_REPORT_SIZE];
|
||||
int retval;
|
||||
|
||||
buf[0] = SCRATCH_REPORT;
|
||||
|
||||
retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
|
||||
|
||||
if (retval < 0)
|
||||
dev_warn(&radio->intf->dev, "si470x_get_scratch: "
|
||||
"si470x_get_report returned %d\n", retval);
|
||||
else {
|
||||
radio->software_version = buf[1];
|
||||
radio->hardware_version = buf[2];
|
||||
}
|
||||
|
||||
return (retval < 0) ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Functions - DISCONNECT_CHECK
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_disconnect_check - check whether radio disconnects
|
||||
*/
|
||||
int si470x_disconnect_check(struct si470x_device *radio)
|
||||
{
|
||||
if (radio->disconnected)
|
||||
return -EIO;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* RDS Driver Functions
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_int_in_callback - rds callback and processing function
|
||||
*
|
||||
* TODO: do we need to use mutex locks in some sections?
|
||||
*/
|
||||
static void si470x_int_in_callback(struct urb *urb)
|
||||
{
|
||||
struct si470x_device *radio = urb->context;
|
||||
unsigned char buf[RDS_REPORT_SIZE];
|
||||
int retval;
|
||||
unsigned char regnr;
|
||||
unsigned char blocknum;
|
||||
unsigned short bler; /* rds block errors */
|
||||
unsigned short rds;
|
||||
unsigned char tmpbuf[3];
|
||||
|
||||
if (urb->status) {
|
||||
if (urb->status == -ENOENT ||
|
||||
urb->status == -ECONNRESET ||
|
||||
urb->status == -ESHUTDOWN) {
|
||||
return;
|
||||
} else {
|
||||
dev_warn(&radio->intf->dev,
|
||||
"non-zero urb status (%d)\n", urb->status);
|
||||
goto resubmit; /* Maybe we can recover. */
|
||||
}
|
||||
}
|
||||
|
||||
/* safety checks */
|
||||
if (radio->disconnected)
|
||||
return;
|
||||
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
|
||||
goto resubmit;
|
||||
|
||||
if (urb->actual_length > 0) {
|
||||
/* Update RDS registers with URB data */
|
||||
buf[0] = RDS_REPORT;
|
||||
for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
|
||||
radio->registers[STATUSRSSI + regnr] =
|
||||
get_unaligned_be16(&radio->int_in_buffer[
|
||||
regnr * RADIO_REGISTER_SIZE + 1]);
|
||||
/* get rds blocks */
|
||||
if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
|
||||
/* No RDS group ready, better luck next time */
|
||||
goto resubmit;
|
||||
}
|
||||
if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
|
||||
/* RDS decoder not synchronized */
|
||||
goto resubmit;
|
||||
}
|
||||
for (blocknum = 0; blocknum < 4; blocknum++) {
|
||||
switch (blocknum) {
|
||||
default:
|
||||
bler = (radio->registers[STATUSRSSI] &
|
||||
STATUSRSSI_BLERA) >> 9;
|
||||
rds = radio->registers[RDSA];
|
||||
break;
|
||||
case 1:
|
||||
bler = (radio->registers[READCHAN] &
|
||||
READCHAN_BLERB) >> 14;
|
||||
rds = radio->registers[RDSB];
|
||||
break;
|
||||
case 2:
|
||||
bler = (radio->registers[READCHAN] &
|
||||
READCHAN_BLERC) >> 12;
|
||||
rds = radio->registers[RDSC];
|
||||
break;
|
||||
case 3:
|
||||
bler = (radio->registers[READCHAN] &
|
||||
READCHAN_BLERD) >> 10;
|
||||
rds = radio->registers[RDSD];
|
||||
break;
|
||||
};
|
||||
|
||||
/* Fill the V4L2 RDS buffer */
|
||||
put_unaligned_le16(rds, &tmpbuf);
|
||||
tmpbuf[2] = blocknum; /* offset name */
|
||||
tmpbuf[2] |= blocknum << 3; /* received offset */
|
||||
if (bler > max_rds_errors)
|
||||
tmpbuf[2] |= 0x80; /* uncorrectable errors */
|
||||
else if (bler > 0)
|
||||
tmpbuf[2] |= 0x40; /* corrected error(s) */
|
||||
|
||||
/* copy RDS block to internal buffer */
|
||||
memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
|
||||
radio->wr_index += 3;
|
||||
|
||||
/* wrap write pointer */
|
||||
if (radio->wr_index >= radio->buf_size)
|
||||
radio->wr_index = 0;
|
||||
|
||||
/* check for overflow */
|
||||
if (radio->wr_index == radio->rd_index) {
|
||||
/* increment and wrap read pointer */
|
||||
radio->rd_index += 3;
|
||||
if (radio->rd_index >= radio->buf_size)
|
||||
radio->rd_index = 0;
|
||||
}
|
||||
}
|
||||
if (radio->wr_index != radio->rd_index)
|
||||
wake_up_interruptible(&radio->read_queue);
|
||||
}
|
||||
|
||||
resubmit:
|
||||
/* Resubmit if we're still running. */
|
||||
if (radio->int_in_running && radio->usbdev) {
|
||||
retval = usb_submit_urb(radio->int_in_urb, GFP_ATOMIC);
|
||||
if (retval) {
|
||||
dev_warn(&radio->intf->dev,
|
||||
"resubmitting urb failed (%d)", retval);
|
||||
radio->int_in_running = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* File Operations Interface
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_fops_read - read RDS data
|
||||
*/
|
||||
static ssize_t si470x_fops_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
unsigned int block_count = 0;
|
||||
|
||||
/* switch on rds reception */
|
||||
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
|
||||
si470x_rds_on(radio);
|
||||
|
||||
/* block if no new data available */
|
||||
while (radio->wr_index == radio->rd_index) {
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
retval = -EWOULDBLOCK;
|
||||
goto done;
|
||||
}
|
||||
if (wait_event_interruptible(radio->read_queue,
|
||||
radio->wr_index != radio->rd_index) < 0) {
|
||||
retval = -EINTR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate block count from byte count */
|
||||
count /= 3;
|
||||
|
||||
/* copy RDS block out of internal buffer and to user buffer */
|
||||
mutex_lock(&radio->lock);
|
||||
while (block_count < count) {
|
||||
if (radio->rd_index == radio->wr_index)
|
||||
break;
|
||||
|
||||
/* always transfer rds complete blocks */
|
||||
if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
|
||||
/* retval = -EFAULT; */
|
||||
break;
|
||||
|
||||
/* increment and wrap read pointer */
|
||||
radio->rd_index += 3;
|
||||
if (radio->rd_index >= radio->buf_size)
|
||||
radio->rd_index = 0;
|
||||
|
||||
/* increment counters */
|
||||
block_count++;
|
||||
buf += 3;
|
||||
retval += 3;
|
||||
}
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_fops_poll - poll RDS data
|
||||
*/
|
||||
static unsigned int si470x_fops_poll(struct file *file,
|
||||
struct poll_table_struct *pts)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
/* switch on rds reception */
|
||||
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
|
||||
si470x_rds_on(radio);
|
||||
|
||||
poll_wait(file, &radio->read_queue, pts);
|
||||
|
||||
if (radio->rd_index != radio->wr_index)
|
||||
retval = POLLIN | POLLRDNORM;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_fops_open - file open
|
||||
*/
|
||||
static int si470x_fops_open(struct file *file)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval;
|
||||
|
||||
lock_kernel();
|
||||
radio->users++;
|
||||
|
||||
retval = usb_autopm_get_interface(radio->intf);
|
||||
if (retval < 0) {
|
||||
radio->users--;
|
||||
retval = -EIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (radio->users == 1) {
|
||||
/* start radio */
|
||||
retval = si470x_start(radio);
|
||||
if (retval < 0) {
|
||||
usb_autopm_put_interface(radio->intf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* initialize interrupt urb */
|
||||
usb_fill_int_urb(radio->int_in_urb, radio->usbdev,
|
||||
usb_rcvintpipe(radio->usbdev,
|
||||
radio->int_in_endpoint->bEndpointAddress),
|
||||
radio->int_in_buffer,
|
||||
le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize),
|
||||
si470x_int_in_callback,
|
||||
radio,
|
||||
radio->int_in_endpoint->bInterval);
|
||||
|
||||
radio->int_in_running = 1;
|
||||
mb();
|
||||
|
||||
retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL);
|
||||
if (retval) {
|
||||
dev_info(&radio->intf->dev,
|
||||
"submitting int urb failed (%d)\n", retval);
|
||||
radio->int_in_running = 0;
|
||||
usb_autopm_put_interface(radio->intf);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
unlock_kernel();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_fops_release - file release
|
||||
*/
|
||||
static int si470x_fops_release(struct file *file)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
int retval = 0;
|
||||
|
||||
/* safety check */
|
||||
if (!radio) {
|
||||
retval = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
|
||||
mutex_lock(&radio->disconnect_lock);
|
||||
radio->users--;
|
||||
if (radio->users == 0) {
|
||||
/* shutdown interrupt handler */
|
||||
if (radio->int_in_running) {
|
||||
radio->int_in_running = 0;
|
||||
if (radio->int_in_urb)
|
||||
usb_kill_urb(radio->int_in_urb);
|
||||
}
|
||||
|
||||
if (radio->disconnected) {
|
||||
video_unregister_device(radio->videodev);
|
||||
kfree(radio->int_in_buffer);
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* cancel read processes */
|
||||
wake_up_interruptible(&radio->read_queue);
|
||||
|
||||
/* stop radio */
|
||||
retval = si470x_stop(radio);
|
||||
usb_autopm_put_interface(radio->intf);
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&radio->disconnect_lock);
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_fops - file operations interface
|
||||
*/
|
||||
const struct v4l2_file_operations si470x_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = si470x_fops_read,
|
||||
.poll = si470x_fops_poll,
|
||||
.ioctl = video_ioctl2,
|
||||
.open = si470x_fops_open,
|
||||
.release = si470x_fops_release,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Video4Linux Interface
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_vidioc_querycap - query device capabilities
|
||||
*/
|
||||
int si470x_vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *capability)
|
||||
{
|
||||
struct si470x_device *radio = video_drvdata(file);
|
||||
|
||||
strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
|
||||
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
|
||||
usb_make_path(radio->usbdev, capability->bus_info,
|
||||
sizeof(capability->bus_info));
|
||||
capability->version = DRIVER_KERNEL_VERSION;
|
||||
capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
|
||||
V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* USB Interface
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_usb_driver_probe - probe for the device
|
||||
*/
|
||||
static int si470x_usb_driver_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct si470x_device *radio;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
int i, int_end_size, retval = 0;
|
||||
unsigned char version_warning = 0;
|
||||
|
||||
/* private data allocation and initialization */
|
||||
radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL);
|
||||
if (!radio) {
|
||||
retval = -ENOMEM;
|
||||
goto err_initial;
|
||||
}
|
||||
radio->users = 0;
|
||||
radio->disconnected = 0;
|
||||
radio->usbdev = interface_to_usbdev(intf);
|
||||
radio->intf = intf;
|
||||
mutex_init(&radio->disconnect_lock);
|
||||
mutex_init(&radio->lock);
|
||||
|
||||
iface_desc = intf->cur_altsetting;
|
||||
|
||||
/* Set up interrupt endpoint information. */
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
|
||||
USB_DIR_IN) && ((endpoint->bmAttributes &
|
||||
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT))
|
||||
radio->int_in_endpoint = endpoint;
|
||||
}
|
||||
if (!radio->int_in_endpoint) {
|
||||
dev_info(&intf->dev, "could not find interrupt in endpoint\n");
|
||||
retval = -EIO;
|
||||
goto err_radio;
|
||||
}
|
||||
|
||||
int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize);
|
||||
|
||||
radio->int_in_buffer = kmalloc(int_end_size, GFP_KERNEL);
|
||||
if (!radio->int_in_buffer) {
|
||||
dev_info(&intf->dev, "could not allocate int_in_buffer");
|
||||
retval = -ENOMEM;
|
||||
goto err_radio;
|
||||
}
|
||||
|
||||
radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!radio->int_in_urb) {
|
||||
dev_info(&intf->dev, "could not allocate int_in_urb");
|
||||
retval = -ENOMEM;
|
||||
goto err_intbuffer;
|
||||
}
|
||||
|
||||
/* video device allocation and initialization */
|
||||
radio->videodev = video_device_alloc();
|
||||
if (!radio->videodev) {
|
||||
retval = -ENOMEM;
|
||||
goto err_intbuffer;
|
||||
}
|
||||
memcpy(radio->videodev, &si470x_viddev_template,
|
||||
sizeof(si470x_viddev_template));
|
||||
video_set_drvdata(radio->videodev, radio);
|
||||
|
||||
/* get device and chip versions */
|
||||
if (si470x_get_all_registers(radio) < 0) {
|
||||
retval = -EIO;
|
||||
goto err_video;
|
||||
}
|
||||
dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
|
||||
radio->registers[DEVICEID], radio->registers[CHIPID]);
|
||||
if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_FW_VERSION) {
|
||||
dev_warn(&intf->dev,
|
||||
"This driver is known to work with "
|
||||
"firmware version %hu,\n", RADIO_FW_VERSION);
|
||||
dev_warn(&intf->dev,
|
||||
"but the device has firmware version %hu.\n",
|
||||
radio->registers[CHIPID] & CHIPID_FIRMWARE);
|
||||
version_warning = 1;
|
||||
}
|
||||
|
||||
/* get software and hardware versions */
|
||||
if (si470x_get_scratch_page_versions(radio) < 0) {
|
||||
retval = -EIO;
|
||||
goto err_video;
|
||||
}
|
||||
dev_info(&intf->dev, "software version %d, hardware version %d\n",
|
||||
radio->software_version, radio->hardware_version);
|
||||
if (radio->software_version < RADIO_SW_VERSION) {
|
||||
dev_warn(&intf->dev,
|
||||
"This driver is known to work with "
|
||||
"software version %hu,\n", RADIO_SW_VERSION);
|
||||
dev_warn(&intf->dev,
|
||||
"but the device has software version %hu.\n",
|
||||
radio->software_version);
|
||||
version_warning = 1;
|
||||
}
|
||||
if (radio->hardware_version < RADIO_HW_VERSION) {
|
||||
dev_warn(&intf->dev,
|
||||
"This driver is known to work with "
|
||||
"hardware version %hu,\n", RADIO_HW_VERSION);
|
||||
dev_warn(&intf->dev,
|
||||
"but the device has hardware version %hu.\n",
|
||||
radio->hardware_version);
|
||||
version_warning = 1;
|
||||
}
|
||||
|
||||
/* give out version warning */
|
||||
if (version_warning == 1) {
|
||||
dev_warn(&intf->dev,
|
||||
"If you have some trouble using this driver,\n");
|
||||
dev_warn(&intf->dev,
|
||||
"please report to V4L ML at "
|
||||
"linux-media@vger.kernel.org\n");
|
||||
}
|
||||
|
||||
/* set initial frequency */
|
||||
si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
|
||||
|
||||
/* set led to connect state */
|
||||
si470x_set_led_state(radio, BLINK_GREEN_LED);
|
||||
|
||||
/* rds buffer allocation */
|
||||
radio->buf_size = rds_buf * 3;
|
||||
radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
|
||||
if (!radio->buffer) {
|
||||
retval = -EIO;
|
||||
goto err_video;
|
||||
}
|
||||
|
||||
/* rds buffer configuration */
|
||||
radio->wr_index = 0;
|
||||
radio->rd_index = 0;
|
||||
init_waitqueue_head(&radio->read_queue);
|
||||
|
||||
/* register video device */
|
||||
retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
|
||||
radio_nr);
|
||||
if (retval) {
|
||||
dev_warn(&intf->dev, "Could not register video device\n");
|
||||
goto err_all;
|
||||
}
|
||||
usb_set_intfdata(intf, radio);
|
||||
|
||||
return 0;
|
||||
err_all:
|
||||
kfree(radio->buffer);
|
||||
err_video:
|
||||
video_device_release(radio->videodev);
|
||||
err_intbuffer:
|
||||
kfree(radio->int_in_buffer);
|
||||
err_radio:
|
||||
kfree(radio);
|
||||
err_initial:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_usb_driver_suspend - suspend the device
|
||||
*/
|
||||
static int si470x_usb_driver_suspend(struct usb_interface *intf,
|
||||
pm_message_t message)
|
||||
{
|
||||
dev_info(&intf->dev, "suspending now...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_usb_driver_resume - resume the device
|
||||
*/
|
||||
static int si470x_usb_driver_resume(struct usb_interface *intf)
|
||||
{
|
||||
dev_info(&intf->dev, "resuming now...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_usb_driver_disconnect - disconnect the device
|
||||
*/
|
||||
static void si470x_usb_driver_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct si470x_device *radio = usb_get_intfdata(intf);
|
||||
|
||||
mutex_lock(&radio->disconnect_lock);
|
||||
radio->disconnected = 1;
|
||||
usb_set_intfdata(intf, NULL);
|
||||
if (radio->users == 0) {
|
||||
/* set led to disconnect state */
|
||||
si470x_set_led_state(radio, BLINK_ORANGE_LED);
|
||||
|
||||
/* Free data structures. */
|
||||
usb_free_urb(radio->int_in_urb);
|
||||
|
||||
kfree(radio->int_in_buffer);
|
||||
video_unregister_device(radio->videodev);
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
}
|
||||
mutex_unlock(&radio->disconnect_lock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_usb_driver - usb driver interface
|
||||
*/
|
||||
static struct usb_driver si470x_usb_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe = si470x_usb_driver_probe,
|
||||
.disconnect = si470x_usb_driver_disconnect,
|
||||
.suspend = si470x_usb_driver_suspend,
|
||||
.resume = si470x_usb_driver_resume,
|
||||
.id_table = si470x_usb_driver_id_table,
|
||||
.supports_autosuspend = 1,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Module Interface
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_module_init - module init
|
||||
*/
|
||||
static int __init si470x_module_init(void)
|
||||
{
|
||||
printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n");
|
||||
return usb_register(&si470x_usb_driver);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* si470x_module_exit - module exit
|
||||
*/
|
||||
static void __exit si470x_module_exit(void)
|
||||
{
|
||||
usb_deregister(&si470x_usb_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init(si470x_module_init);
|
||||
module_exit(si470x_module_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* drivers/media/radio/si470x/radio-si470x.h
|
||||
*
|
||||
* Driver for radios with Silicon Labs Si470x FM Radio Receivers
|
||||
*
|
||||
* Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
/* driver definitions */
|
||||
#define DRIVER_NAME "radio-si470x"
|
||||
|
||||
|
||||
/* kernel includes */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/rds.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Register Definitions
|
||||
**************************************************************************/
|
||||
#define RADIO_REGISTER_SIZE 2 /* 16 register bit width */
|
||||
#define RADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */
|
||||
#define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */
|
||||
|
||||
#define DEVICEID 0 /* Device ID */
|
||||
#define DEVICEID_PN 0xf000 /* bits 15..12: Part Number */
|
||||
#define DEVICEID_MFGID 0x0fff /* bits 11..00: Manufacturer ID */
|
||||
|
||||
#define CHIPID 1 /* Chip ID */
|
||||
#define CHIPID_REV 0xfc00 /* bits 15..10: Chip Version */
|
||||
#define CHIPID_DEV 0x0200 /* bits 09..09: Device */
|
||||
#define CHIPID_FIRMWARE 0x01ff /* bits 08..00: Firmware Version */
|
||||
|
||||
#define POWERCFG 2 /* Power Configuration */
|
||||
#define POWERCFG_DSMUTE 0x8000 /* bits 15..15: Softmute Disable */
|
||||
#define POWERCFG_DMUTE 0x4000 /* bits 14..14: Mute Disable */
|
||||
#define POWERCFG_MONO 0x2000 /* bits 13..13: Mono Select */
|
||||
#define POWERCFG_RDSM 0x0800 /* bits 11..11: RDS Mode (Si4701 only) */
|
||||
#define POWERCFG_SKMODE 0x0400 /* bits 10..10: Seek Mode */
|
||||
#define POWERCFG_SEEKUP 0x0200 /* bits 09..09: Seek Direction */
|
||||
#define POWERCFG_SEEK 0x0100 /* bits 08..08: Seek */
|
||||
#define POWERCFG_DISABLE 0x0040 /* bits 06..06: Powerup Disable */
|
||||
#define POWERCFG_ENABLE 0x0001 /* bits 00..00: Powerup Enable */
|
||||
|
||||
#define CHANNEL 3 /* Channel */
|
||||
#define CHANNEL_TUNE 0x8000 /* bits 15..15: Tune */
|
||||
#define CHANNEL_CHAN 0x03ff /* bits 09..00: Channel Select */
|
||||
|
||||
#define SYSCONFIG1 4 /* System Configuration 1 */
|
||||
#define SYSCONFIG1_RDSIEN 0x8000 /* bits 15..15: RDS Interrupt Enable (Si4701 only) */
|
||||
#define SYSCONFIG1_STCIEN 0x4000 /* bits 14..14: Seek/Tune Complete Interrupt Enable */
|
||||
#define SYSCONFIG1_RDS 0x1000 /* bits 12..12: RDS Enable (Si4701 only) */
|
||||
#define SYSCONFIG1_DE 0x0800 /* bits 11..11: De-emphasis (0=75us 1=50us) */
|
||||
#define SYSCONFIG1_AGCD 0x0400 /* bits 10..10: AGC Disable */
|
||||
#define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */
|
||||
#define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */
|
||||
#define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */
|
||||
#define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */
|
||||
|
||||
#define SYSCONFIG2 5 /* System Configuration 2 */
|
||||
#define SYSCONFIG2_SEEKTH 0xff00 /* bits 15..08: RSSI Seek Threshold */
|
||||
#define SYSCONFIG2_BAND 0x0080 /* bits 07..06: Band Select */
|
||||
#define SYSCONFIG2_SPACE 0x0030 /* bits 05..04: Channel Spacing */
|
||||
#define SYSCONFIG2_VOLUME 0x000f /* bits 03..00: Volume */
|
||||
|
||||
#define SYSCONFIG3 6 /* System Configuration 3 */
|
||||
#define SYSCONFIG3_SMUTER 0xc000 /* bits 15..14: Softmute Attack/Recover Rate */
|
||||
#define SYSCONFIG3_SMUTEA 0x3000 /* bits 13..12: Softmute Attenuation */
|
||||
#define SYSCONFIG3_SKSNR 0x00f0 /* bits 07..04: Seek SNR Threshold */
|
||||
#define SYSCONFIG3_SKCNT 0x000f /* bits 03..00: Seek FM Impulse Detection Threshold */
|
||||
|
||||
#define TEST1 7 /* Test 1 */
|
||||
#define TEST1_AHIZEN 0x4000 /* bits 14..14: Audio High-Z Enable */
|
||||
|
||||
#define TEST2 8 /* Test 2 */
|
||||
/* TEST2 only contains reserved bits */
|
||||
|
||||
#define BOOTCONFIG 9 /* Boot Configuration */
|
||||
/* BOOTCONFIG only contains reserved bits */
|
||||
|
||||
#define STATUSRSSI 10 /* Status RSSI */
|
||||
#define STATUSRSSI_RDSR 0x8000 /* bits 15..15: RDS Ready (Si4701 only) */
|
||||
#define STATUSRSSI_STC 0x4000 /* bits 14..14: Seek/Tune Complete */
|
||||
#define STATUSRSSI_SF 0x2000 /* bits 13..13: Seek Fail/Band Limit */
|
||||
#define STATUSRSSI_AFCRL 0x1000 /* bits 12..12: AFC Rail */
|
||||
#define STATUSRSSI_RDSS 0x0800 /* bits 11..11: RDS Synchronized (Si4701 only) */
|
||||
#define STATUSRSSI_BLERA 0x0600 /* bits 10..09: RDS Block A Errors (Si4701 only) */
|
||||
#define STATUSRSSI_ST 0x0100 /* bits 08..08: Stereo Indicator */
|
||||
#define STATUSRSSI_RSSI 0x00ff /* bits 07..00: RSSI (Received Signal Strength Indicator) */
|
||||
|
||||
#define READCHAN 11 /* Read Channel */
|
||||
#define READCHAN_BLERB 0xc000 /* bits 15..14: RDS Block D Errors (Si4701 only) */
|
||||
#define READCHAN_BLERC 0x3000 /* bits 13..12: RDS Block C Errors (Si4701 only) */
|
||||
#define READCHAN_BLERD 0x0c00 /* bits 11..10: RDS Block B Errors (Si4701 only) */
|
||||
#define READCHAN_READCHAN 0x03ff /* bits 09..00: Read Channel */
|
||||
|
||||
#define RDSA 12 /* RDSA */
|
||||
#define RDSA_RDSA 0xffff /* bits 15..00: RDS Block A Data (Si4701 only) */
|
||||
|
||||
#define RDSB 13 /* RDSB */
|
||||
#define RDSB_RDSB 0xffff /* bits 15..00: RDS Block B Data (Si4701 only) */
|
||||
|
||||
#define RDSC 14 /* RDSC */
|
||||
#define RDSC_RDSC 0xffff /* bits 15..00: RDS Block C Data (Si4701 only) */
|
||||
|
||||
#define RDSD 15 /* RDSD */
|
||||
#define RDSD_RDSD 0xffff /* bits 15..00: RDS Block D Data (Si4701 only) */
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* General Driver Definitions
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* si470x_device - private data
|
||||
*/
|
||||
struct si470x_device {
|
||||
struct video_device *videodev;
|
||||
|
||||
/* driver management */
|
||||
unsigned int users;
|
||||
|
||||
/* Silabs internal registers (0..15) */
|
||||
unsigned short registers[RADIO_REGISTER_NUM];
|
||||
|
||||
/* RDS receive buffer */
|
||||
wait_queue_head_t read_queue;
|
||||
struct mutex lock; /* buffer locking */
|
||||
unsigned char *buffer; /* size is always multiple of three */
|
||||
unsigned int buf_size;
|
||||
unsigned int rd_index;
|
||||
unsigned int wr_index;
|
||||
|
||||
#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
|
||||
/* reference to USB and video device */
|
||||
struct usb_device *usbdev;
|
||||
struct usb_interface *intf;
|
||||
|
||||
/* Interrupt endpoint handling */
|
||||
char *int_in_buffer;
|
||||
struct usb_endpoint_descriptor *int_in_endpoint;
|
||||
struct urb *int_in_urb;
|
||||
int int_in_running;
|
||||
|
||||
/* scratch page */
|
||||
unsigned char software_version;
|
||||
unsigned char hardware_version;
|
||||
|
||||
/* driver management */
|
||||
unsigned char disconnected;
|
||||
struct mutex disconnect_lock;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
|
||||
struct i2c_client *client;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Firmware Versions
|
||||
**************************************************************************/
|
||||
|
||||
#define RADIO_FW_VERSION 15
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Frequency Multiplicator
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
|
||||
* 62.5 kHz otherwise.
|
||||
* The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
|
||||
* tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
|
||||
* The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
|
||||
*/
|
||||
#define FREQ_MUL (1000000 / 62.5)
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Common Functions
|
||||
**************************************************************************/
|
||||
extern const struct v4l2_file_operations si470x_fops;
|
||||
extern struct video_device si470x_viddev_template;
|
||||
int si470x_get_register(struct si470x_device *radio, int regnr);
|
||||
int si470x_set_register(struct si470x_device *radio, int regnr);
|
||||
int si470x_disconnect_check(struct si470x_device *radio);
|
||||
int si470x_set_freq(struct si470x_device *radio, unsigned int freq);
|
||||
int si470x_start(struct si470x_device *radio);
|
||||
int si470x_stop(struct si470x_device *radio);
|
||||
int si470x_rds_on(struct si470x_device *radio);
|
||||
int si470x_vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *capability);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* drivers/media/radio/si4713-i2c.h
|
||||
*
|
||||
* Property and commands definitions for Si4713 radio transmitter chip.
|
||||
*
|
||||
* Copyright (c) 2008 Instituto Nokia de Tecnologia - INdT
|
||||
* Contact: Eduardo Valentin <eduardo.valentin@nokia.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SI4713_I2C_H
|
||||
#define SI4713_I2C_H
|
||||
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/si4713.h>
|
||||
|
||||
#define SI4713_PRODUCT_NUMBER 0x0D
|
||||
|
||||
/* Command Timeouts */
|
||||
#define DEFAULT_TIMEOUT 500
|
||||
#define TIMEOUT_SET_PROPERTY 20
|
||||
#define TIMEOUT_TX_TUNE_POWER 30000
|
||||
#define TIMEOUT_TX_TUNE 110000
|
||||
#define TIMEOUT_POWER_UP 200000
|
||||
|
||||
/*
|
||||
* Command and its arguments definitions
|
||||
*/
|
||||
#define SI4713_PWUP_CTSIEN (1<<7)
|
||||
#define SI4713_PWUP_GPO2OEN (1<<6)
|
||||
#define SI4713_PWUP_PATCH (1<<5)
|
||||
#define SI4713_PWUP_XOSCEN (1<<4)
|
||||
#define SI4713_PWUP_FUNC_TX 0x02
|
||||
#define SI4713_PWUP_FUNC_PATCH 0x0F
|
||||
#define SI4713_PWUP_OPMOD_ANALOG 0x50
|
||||
#define SI4713_PWUP_OPMOD_DIGITAL 0x0F
|
||||
#define SI4713_PWUP_NARGS 2
|
||||
#define SI4713_PWUP_NRESP 1
|
||||
#define SI4713_CMD_POWER_UP 0x01
|
||||
|
||||
#define SI4713_GETREV_NRESP 9
|
||||
#define SI4713_CMD_GET_REV 0x10
|
||||
|
||||
#define SI4713_PWDN_NRESP 1
|
||||
#define SI4713_CMD_POWER_DOWN 0x11
|
||||
|
||||
#define SI4713_SET_PROP_NARGS 5
|
||||
#define SI4713_SET_PROP_NRESP 1
|
||||
#define SI4713_CMD_SET_PROPERTY 0x12
|
||||
|
||||
#define SI4713_GET_PROP_NARGS 3
|
||||
#define SI4713_GET_PROP_NRESP 4
|
||||
#define SI4713_CMD_GET_PROPERTY 0x13
|
||||
|
||||
#define SI4713_GET_STATUS_NRESP 1
|
||||
#define SI4713_CMD_GET_INT_STATUS 0x14
|
||||
|
||||
#define SI4713_CMD_PATCH_ARGS 0x15
|
||||
#define SI4713_CMD_PATCH_DATA 0x16
|
||||
|
||||
#define SI4713_MAX_FREQ 10800
|
||||
#define SI4713_MIN_FREQ 7600
|
||||
#define SI4713_TXFREQ_NARGS 3
|
||||
#define SI4713_TXFREQ_NRESP 1
|
||||
#define SI4713_CMD_TX_TUNE_FREQ 0x30
|
||||
|
||||
#define SI4713_MAX_POWER 120
|
||||
#define SI4713_MIN_POWER 88
|
||||
#define SI4713_MAX_ANTCAP 191
|
||||
#define SI4713_MIN_ANTCAP 0
|
||||
#define SI4713_TXPWR_NARGS 4
|
||||
#define SI4713_TXPWR_NRESP 1
|
||||
#define SI4713_CMD_TX_TUNE_POWER 0x31
|
||||
|
||||
#define SI4713_TXMEA_NARGS 4
|
||||
#define SI4713_TXMEA_NRESP 1
|
||||
#define SI4713_CMD_TX_TUNE_MEASURE 0x32
|
||||
|
||||
#define SI4713_INTACK_MASK 0x01
|
||||
#define SI4713_TXSTATUS_NARGS 1
|
||||
#define SI4713_TXSTATUS_NRESP 8
|
||||
#define SI4713_CMD_TX_TUNE_STATUS 0x33
|
||||
|
||||
#define SI4713_OVERMOD_BIT (1 << 2)
|
||||
#define SI4713_IALH_BIT (1 << 1)
|
||||
#define SI4713_IALL_BIT (1 << 0)
|
||||
#define SI4713_ASQSTATUS_NARGS 1
|
||||
#define SI4713_ASQSTATUS_NRESP 5
|
||||
#define SI4713_CMD_TX_ASQ_STATUS 0x34
|
||||
|
||||
#define SI4713_RDSBUFF_MODE_MASK 0x87
|
||||
#define SI4713_RDSBUFF_NARGS 7
|
||||
#define SI4713_RDSBUFF_NRESP 6
|
||||
#define SI4713_CMD_TX_RDS_BUFF 0x35
|
||||
|
||||
#define SI4713_RDSPS_PSID_MASK 0x1F
|
||||
#define SI4713_RDSPS_NARGS 5
|
||||
#define SI4713_RDSPS_NRESP 1
|
||||
#define SI4713_CMD_TX_RDS_PS 0x36
|
||||
|
||||
#define SI4713_CMD_GPO_CTL 0x80
|
||||
#define SI4713_CMD_GPO_SET 0x81
|
||||
|
||||
/*
|
||||
* Bits from status response
|
||||
*/
|
||||
#define SI4713_CTS (1<<7)
|
||||
#define SI4713_ERR (1<<6)
|
||||
#define SI4713_RDS_INT (1<<2)
|
||||
#define SI4713_ASQ_INT (1<<1)
|
||||
#define SI4713_STC_INT (1<<0)
|
||||
|
||||
/*
|
||||
* Property definitions
|
||||
*/
|
||||
#define SI4713_GPO_IEN 0x0001
|
||||
#define SI4713_DIG_INPUT_FORMAT 0x0101
|
||||
#define SI4713_DIG_INPUT_SAMPLE_RATE 0x0103
|
||||
#define SI4713_REFCLK_FREQ 0x0201
|
||||
#define SI4713_REFCLK_PRESCALE 0x0202
|
||||
#define SI4713_TX_COMPONENT_ENABLE 0x2100
|
||||
#define SI4713_TX_AUDIO_DEVIATION 0x2101
|
||||
#define SI4713_TX_PILOT_DEVIATION 0x2102
|
||||
#define SI4713_TX_RDS_DEVIATION 0x2103
|
||||
#define SI4713_TX_LINE_INPUT_LEVEL 0x2104
|
||||
#define SI4713_TX_LINE_INPUT_MUTE 0x2105
|
||||
#define SI4713_TX_PREEMPHASIS 0x2106
|
||||
#define SI4713_TX_PILOT_FREQUENCY 0x2107
|
||||
#define SI4713_TX_ACOMP_ENABLE 0x2200
|
||||
#define SI4713_TX_ACOMP_THRESHOLD 0x2201
|
||||
#define SI4713_TX_ACOMP_ATTACK_TIME 0x2202
|
||||
#define SI4713_TX_ACOMP_RELEASE_TIME 0x2203
|
||||
#define SI4713_TX_ACOMP_GAIN 0x2204
|
||||
#define SI4713_TX_LIMITER_RELEASE_TIME 0x2205
|
||||
#define SI4713_TX_ASQ_INTERRUPT_SOURCE 0x2300
|
||||
#define SI4713_TX_ASQ_LEVEL_LOW 0x2301
|
||||
#define SI4713_TX_ASQ_DURATION_LOW 0x2302
|
||||
#define SI4713_TX_ASQ_LEVEL_HIGH 0x2303
|
||||
#define SI4713_TX_ASQ_DURATION_HIGH 0x2304
|
||||
#define SI4713_TX_RDS_INTERRUPT_SOURCE 0x2C00
|
||||
#define SI4713_TX_RDS_PI 0x2C01
|
||||
#define SI4713_TX_RDS_PS_MIX 0x2C02
|
||||
#define SI4713_TX_RDS_PS_MISC 0x2C03
|
||||
#define SI4713_TX_RDS_PS_REPEAT_COUNT 0x2C04
|
||||
#define SI4713_TX_RDS_PS_MESSAGE_COUNT 0x2C05
|
||||
#define SI4713_TX_RDS_PS_AF 0x2C06
|
||||
#define SI4713_TX_RDS_FIFO_SIZE 0x2C07
|
||||
|
||||
#define PREEMPHASIS_USA 75
|
||||
#define PREEMPHASIS_EU 50
|
||||
#define PREEMPHASIS_DISABLED 0
|
||||
#define FMPE_USA 0x00
|
||||
#define FMPE_EU 0x01
|
||||
#define FMPE_DISABLED 0x02
|
||||
|
||||
#define POWER_UP 0x01
|
||||
#define POWER_DOWN 0x00
|
||||
|
||||
struct rds_info {
|
||||
u32 pi;
|
||||
#define MAX_RDS_PTY 31
|
||||
u32 pty;
|
||||
#define MAX_RDS_DEVIATION 90000
|
||||
u32 deviation;
|
||||
/*
|
||||
* PSNAME is known to be defined as 8 character sized (RDS Spec).
|
||||
* However, there is receivers which scroll PSNAME 8xN sized.
|
||||
*/
|
||||
#define MAX_RDS_PS_NAME 96
|
||||
u8 ps_name[MAX_RDS_PS_NAME + 1];
|
||||
/*
|
||||
* MAX_RDS_RADIO_TEXT is known to be defined as 32 (2A group) or 64 (2B group)
|
||||
* character sized (RDS Spec).
|
||||
* However, there is receivers which scroll them as well.
|
||||
*/
|
||||
#define MAX_RDS_RADIO_TEXT 384
|
||||
u8 radio_text[MAX_RDS_RADIO_TEXT + 1];
|
||||
u32 enabled;
|
||||
};
|
||||
|
||||
struct limiter_info {
|
||||
#define MAX_LIMITER_RELEASE_TIME 102390
|
||||
u32 release_time;
|
||||
#define MAX_LIMITER_DEVIATION 90000
|
||||
u32 deviation;
|
||||
u32 enabled;
|
||||
};
|
||||
|
||||
struct pilot_info {
|
||||
#define MAX_PILOT_DEVIATION 90000
|
||||
u32 deviation;
|
||||
#define MAX_PILOT_FREQUENCY 19000
|
||||
u32 frequency;
|
||||
u32 enabled;
|
||||
};
|
||||
|
||||
struct acomp_info {
|
||||
#define MAX_ACOMP_RELEASE_TIME 1000000
|
||||
u32 release_time;
|
||||
#define MAX_ACOMP_ATTACK_TIME 5000
|
||||
u32 attack_time;
|
||||
#define MAX_ACOMP_THRESHOLD 0
|
||||
#define MIN_ACOMP_THRESHOLD (-40)
|
||||
s32 threshold;
|
||||
#define MAX_ACOMP_GAIN 20
|
||||
u32 gain;
|
||||
u32 enabled;
|
||||
};
|
||||
|
||||
/*
|
||||
* si4713_device - private data
|
||||
*/
|
||||
struct si4713_device {
|
||||
/* v4l2_subdev and i2c reference (v4l2_subdev priv data) */
|
||||
struct v4l2_subdev sd;
|
||||
/* private data structures */
|
||||
struct mutex mutex;
|
||||
struct completion work;
|
||||
struct si4713_platform_data *platform_data;
|
||||
struct rds_info rds_info;
|
||||
struct limiter_info limiter_info;
|
||||
struct pilot_info pilot_info;
|
||||
struct acomp_info acomp_info;
|
||||
u32 frequency;
|
||||
u32 preemphasis;
|
||||
u32 mute;
|
||||
u32 power_level;
|
||||
u32 power_state;
|
||||
u32 antenna_capacitor;
|
||||
u32 stereo;
|
||||
u32 tune_rnl;
|
||||
};
|
||||
#endif /* ifndef SI4713_I2C_H */
|
|
@ -203,9 +203,9 @@ config VIDEO_CS53L32A
|
|||
module will be called cs53l32a.
|
||||
|
||||
config VIDEO_M52790
|
||||
tristate "Mitsubishi M52790 A/V switch"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
---help---
|
||||
tristate "Mitsubishi M52790 A/V switch"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
---help---
|
||||
Support for the Mitsubishi M52790 A/V switch.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
|
|
|
@ -151,7 +151,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
|
|||
dprintk(2, "%s()\n", __func__);
|
||||
|
||||
if (dev->urb_streaming) {
|
||||
dprintk(2, "%s: iso xfer already running!\n", __func__);
|
||||
dprintk(2, "%s: bulk xfer already running!\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -320,7 +320,6 @@ static struct i2c_algorithm au0828_i2c_algo_template = {
|
|||
static struct i2c_adapter au0828_i2c_adap_template = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.id = I2C_HW_B_AU0828,
|
||||
.algo = &au0828_i2c_algo_template,
|
||||
};
|
||||
|
||||
|
|
|
@ -1274,6 +1274,7 @@ struct tvcard bttv_tvcards[] = {
|
|||
.pll = PLL_28,
|
||||
.tuner_type = TUNER_TEMIC_PAL,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.has_remote = 1,
|
||||
},
|
||||
|
||||
/* ---- card 0x3c ---------------------------------- */
|
||||
|
|
|
@ -2652,6 +2652,8 @@ static int bttv_querycap(struct file *file, void *priv,
|
|||
V4L2_CAP_VBI_CAPTURE |
|
||||
V4L2_CAP_READWRITE |
|
||||
V4L2_CAP_STREAMING;
|
||||
if (btv->has_saa6588)
|
||||
cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
|
||||
if (no_overlay <= 0)
|
||||
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
|
||||
|
||||
|
@ -4593,14 +4595,10 @@ static int bttv_resume(struct pci_dev *pci_dev)
|
|||
#endif
|
||||
|
||||
static struct pci_device_id bttv_pci_tbl[] = {
|
||||
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0},
|
||||
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0},
|
||||
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0},
|
||||
{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0},
|
||||
{0,}
|
||||
};
|
||||
|
||||
|
|
|
@ -352,7 +352,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
|
|||
/* bt878 */
|
||||
strlcpy(btv->c.i2c_adap.name, "bt878",
|
||||
sizeof(btv->c.i2c_adap.name));
|
||||
btv->c.i2c_adap.id = I2C_HW_B_BT848; /* FIXME */
|
||||
btv->c.i2c_adap.algo = &bttv_algo;
|
||||
} else {
|
||||
/* bt848 */
|
||||
|
@ -362,7 +361,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
|
|||
|
||||
strlcpy(btv->c.i2c_adap.name, "bttv",
|
||||
sizeof(btv->c.i2c_adap.name));
|
||||
btv->c.i2c_adap.id = I2C_HW_B_BT848;
|
||||
memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
|
||||
sizeof(bttv_i2c_algo_bit_template));
|
||||
btv->i2c_algo.udelay = i2c_udelay;
|
||||
|
|
|
@ -245,7 +245,7 @@ static void bttv_ir_stop(struct bttv *btv)
|
|||
int bttv_input_init(struct bttv *btv)
|
||||
{
|
||||
struct card_ir *ir;
|
||||
IR_KEYTAB_TYPE *ir_codes = NULL;
|
||||
struct ir_scancode_table *ir_codes = NULL;
|
||||
struct input_dev *input_dev;
|
||||
int ir_type = IR_TYPE_OTHER;
|
||||
int err = -ENOMEM;
|
||||
|
@ -263,7 +263,7 @@ int bttv_input_init(struct bttv *btv)
|
|||
case BTTV_BOARD_AVERMEDIA:
|
||||
case BTTV_BOARD_AVPHONE98:
|
||||
case BTTV_BOARD_AVERMEDIA98:
|
||||
ir_codes = ir_codes_avermedia;
|
||||
ir_codes = &ir_codes_avermedia_table;
|
||||
ir->mask_keycode = 0xf88000;
|
||||
ir->mask_keydown = 0x010000;
|
||||
ir->polling = 50; // ms
|
||||
|
@ -271,14 +271,14 @@ int bttv_input_init(struct bttv *btv)
|
|||
|
||||
case BTTV_BOARD_AVDVBT_761:
|
||||
case BTTV_BOARD_AVDVBT_771:
|
||||
ir_codes = ir_codes_avermedia_dvbt;
|
||||
ir_codes = &ir_codes_avermedia_dvbt_table;
|
||||
ir->mask_keycode = 0x0f00c0;
|
||||
ir->mask_keydown = 0x000020;
|
||||
ir->polling = 50; // ms
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_PXELVWPLTVPAK:
|
||||
ir_codes = ir_codes_pixelview;
|
||||
ir_codes = &ir_codes_pixelview_table;
|
||||
ir->mask_keycode = 0x003e00;
|
||||
ir->mask_keyup = 0x010000;
|
||||
ir->polling = 50; // ms
|
||||
|
@ -286,54 +286,55 @@ int bttv_input_init(struct bttv *btv)
|
|||
case BTTV_BOARD_PV_M4900:
|
||||
case BTTV_BOARD_PV_BT878P_9B:
|
||||
case BTTV_BOARD_PV_BT878P_PLUS:
|
||||
ir_codes = ir_codes_pixelview;
|
||||
ir_codes = &ir_codes_pixelview_table;
|
||||
ir->mask_keycode = 0x001f00;
|
||||
ir->mask_keyup = 0x008000;
|
||||
ir->polling = 50; // ms
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_WINFAST2000:
|
||||
ir_codes = ir_codes_winfast;
|
||||
ir_codes = &ir_codes_winfast_table;
|
||||
ir->mask_keycode = 0x1f8;
|
||||
break;
|
||||
case BTTV_BOARD_MAGICTVIEW061:
|
||||
case BTTV_BOARD_MAGICTVIEW063:
|
||||
ir_codes = ir_codes_winfast;
|
||||
ir_codes = &ir_codes_winfast_table;
|
||||
ir->mask_keycode = 0x0008e000;
|
||||
ir->mask_keydown = 0x00200000;
|
||||
break;
|
||||
case BTTV_BOARD_APAC_VIEWCOMP:
|
||||
ir_codes = ir_codes_apac_viewcomp;
|
||||
ir_codes = &ir_codes_apac_viewcomp_table;
|
||||
ir->mask_keycode = 0x001f00;
|
||||
ir->mask_keyup = 0x008000;
|
||||
ir->polling = 50; // ms
|
||||
break;
|
||||
case BTTV_BOARD_ASKEY_CPH03X:
|
||||
case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
|
||||
case BTTV_BOARD_CONTVFMI:
|
||||
ir_codes = ir_codes_pixelview;
|
||||
ir_codes = &ir_codes_pixelview_table;
|
||||
ir->mask_keycode = 0x001F00;
|
||||
ir->mask_keyup = 0x006000;
|
||||
ir->polling = 50; // ms
|
||||
break;
|
||||
case BTTV_BOARD_NEBULA_DIGITV:
|
||||
ir_codes = ir_codes_nebula;
|
||||
ir_codes = &ir_codes_nebula_table;
|
||||
btv->custom_irq = bttv_rc5_irq;
|
||||
ir->rc5_gpio = 1;
|
||||
break;
|
||||
case BTTV_BOARD_MACHTV_MAGICTV:
|
||||
ir_codes = ir_codes_apac_viewcomp;
|
||||
ir_codes = &ir_codes_apac_viewcomp_table;
|
||||
ir->mask_keycode = 0x001F00;
|
||||
ir->mask_keyup = 0x004000;
|
||||
ir->polling = 50; /* ms */
|
||||
break;
|
||||
case BTTV_BOARD_KOZUMI_KTV_01C:
|
||||
ir_codes = ir_codes_pctv_sedna;
|
||||
ir_codes = &ir_codes_pctv_sedna_table;
|
||||
ir->mask_keycode = 0x001f00;
|
||||
ir->mask_keyup = 0x006000;
|
||||
ir->polling = 50; /* ms */
|
||||
break;
|
||||
case BTTV_BOARD_ENLTV_FM_2:
|
||||
ir_codes = ir_codes_encore_enltv2;
|
||||
ir_codes = &ir_codes_encore_enltv2_table;
|
||||
ir->mask_keycode = 0x00fd00;
|
||||
ir->mask_keyup = 0x000080;
|
||||
ir->polling = 1; /* ms */
|
||||
|
|
|
@ -490,7 +490,6 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
|
|||
int ret;
|
||||
|
||||
cafe_smbus_enable_irq(cam);
|
||||
adap->id = I2C_HW_SMBUS_CAFE;
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->algo = &cafe_smbus_algo;
|
||||
strcpy(adap->name, "cafe_ccic");
|
||||
|
|
|
@ -56,7 +56,8 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
|
|||
.hw_audio_ctrl = CX18_HW_418_AV,
|
||||
.hw_muxer = CX18_HW_CS5345,
|
||||
.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
|
||||
CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
|
||||
CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
|
||||
CX18_HW_Z8F0811_IR_HAUP,
|
||||
.video_inputs = {
|
||||
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
|
||||
{ CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
|
||||
|
@ -102,7 +103,8 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
|
|||
.hw_audio_ctrl = CX18_HW_418_AV,
|
||||
.hw_muxer = CX18_HW_CS5345,
|
||||
.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
|
||||
CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
|
||||
CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
|
||||
CX18_HW_Z8F0811_IR_HAUP,
|
||||
.video_inputs = {
|
||||
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
|
||||
{ CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
|
||||
|
@ -204,7 +206,7 @@ static const struct cx18_card cx18_card_mpc718 = {
|
|||
.v4l2_capabilities = CX18_CAP_ENCODER,
|
||||
.hw_audio_ctrl = CX18_HW_418_AV,
|
||||
.hw_muxer = CX18_HW_GPIO_MUX,
|
||||
.hw_all = CX18_HW_418_AV | CX18_HW_TUNER |
|
||||
.hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
|
||||
CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
|
||||
.video_inputs = {
|
||||
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
|
||||
|
|
|
@ -22,13 +22,17 @@
|
|||
*/
|
||||
|
||||
/* hardware flags */
|
||||
#define CX18_HW_TUNER (1 << 0)
|
||||
#define CX18_HW_TVEEPROM (1 << 1)
|
||||
#define CX18_HW_CS5345 (1 << 2)
|
||||
#define CX18_HW_DVB (1 << 3)
|
||||
#define CX18_HW_418_AV (1 << 4)
|
||||
#define CX18_HW_GPIO_MUX (1 << 5)
|
||||
#define CX18_HW_GPIO_RESET_CTRL (1 << 6)
|
||||
#define CX18_HW_TUNER (1 << 0)
|
||||
#define CX18_HW_TVEEPROM (1 << 1)
|
||||
#define CX18_HW_CS5345 (1 << 2)
|
||||
#define CX18_HW_DVB (1 << 3)
|
||||
#define CX18_HW_418_AV (1 << 4)
|
||||
#define CX18_HW_GPIO_MUX (1 << 5)
|
||||
#define CX18_HW_GPIO_RESET_CTRL (1 << 6)
|
||||
#define CX18_HW_Z8F0811_IR_TX_HAUP (1 << 7)
|
||||
#define CX18_HW_Z8F0811_IR_RX_HAUP (1 << 8)
|
||||
#define CX18_HW_Z8F0811_IR_HAUP (CX18_HW_Z8F0811_IR_RX_HAUP | \
|
||||
CX18_HW_Z8F0811_IR_TX_HAUP)
|
||||
|
||||
/* video inputs */
|
||||
#define CX18_CARD_INPUT_VID_TUNER 1
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче