Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6

* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (505 commits)
  [media] af9015: Fix max I2C message size when used with tda18271
  [media] IR: initialize ir_raw_event in few more drivers
  [media] Guard a divide in v4l1 compat layer
  [media] imon: fix nomouse modprobe option
  [media] imon: remove redundant change_protocol call
  [media] imon: fix my egregious brown paper bag w/rdev/idev split
  [media] cafe_ccic: Configure ov7670 correctly
  [media] ov7670: allow configuration of image size, clock speed, and I/O method
  [media] af9015: support for DigitalNow TinyTwin v3 [1f4d:9016]
  [media] af9015: map DigitalNow TinyTwin v2 remote
  [media] DigitalNow TinyTwin remote controller
  [media] af9015: RC fixes and improvements
  videodev2.h.xml: Update to reflect the latest changes at videodev2.h
  [media] v4l: document new Bayer and monochrome pixel formats
  [media] DocBook/v4l: Add missing formats used on gspca cpia1 and sn9c2028
  [media] firedtv: add parameter to fake ca_system_ids in CA_INFO
  [media] tm6000: fix a macro coding style issue
  tm6000: Remove some ugly debug code
  [media] Nova-S-Plus audio line input
  [media] [RFC,1/1] V4L2: Use new CAP bits in existing RDS capable drivers
  ...
This commit is contained in:
Linus Torvalds 2010-10-28 09:35:11 -07:00
commit 0851668fdd
531 changed files with 41145 additions and 13099 deletions

View file

@ -79,6 +79,18 @@ config IR_SONY_DECODER
Enable this option if you have an infrared remote control which
uses the Sony protocol, and you need software decoding support.
config IR_RC5_SZ_DECODER
tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol"
depends on IR_CORE
select BITREVERSE
default y
---help---
Enable this option if you have IR with RC-5 (streamzap) protocol,
and if the IR is decoded in software. (The Streamzap PC Remote
uses an IR protocol that is almost standard RC-5, but not quite,
as it uses an additional bit).
config IR_LIRC_CODEC
tristate "Enable IR to LIRC bridge"
depends on IR_CORE
@ -89,6 +101,20 @@ config IR_LIRC_CODEC
Enable this option to pass raw IR to and from userspace via
the LIRC interface.
config IR_ENE
tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
depends on PNP
depends on IR_CORE
---help---
Say Y here to enable support for integrated infrared receiver
/transceiver made by ENE.
You can see if you have it by looking at lspnp output.
Output should include ENE0100 ENE0200 or something similar.
To compile this driver as a module, choose M here: the
module will be called ene_ir.
config IR_IMON
tristate "SoundGraph iMON Receiver and Display"
depends on USB_ARCH_HAS_HCD
@ -113,19 +139,18 @@ config IR_MCEUSB
To compile this driver as a module, choose M here: the
module will be called mceusb.
config IR_ENE
tristate "ENE eHome Receiver/Transciever (pnp id: ENE0100/ENE02xxx)"
config IR_NUVOTON
tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
depends on PNP
depends on IR_CORE
---help---
Say Y here to enable support for integrated infrared receiver
/transciever made by ENE.
You can see if you have it by looking at lspnp output.
Output should include ENE0100 ENE0200 or something similiar.
/transciever made by Nuvoton (formerly Winbond). This chip is
found in the ASRock ION 330HT, as well as assorted Intel
DP55-series motherboards (and of course, possibly others).
To compile this driver as a module, choose M here: the
module will be called ene_ir.
module will be called nuvoton-cir.
config IR_STREAMZAP
tristate "Streamzap PC Remote IR Receiver"

View file

@ -11,10 +11,12 @@ obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
# stand-alone IR receivers/transmitters
obj-$(CONFIG_IR_IMON) += imon.o
obj-$(CONFIG_IR_MCEUSB) += mceusb.o
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
obj-$(CONFIG_IR_ENE) += ene_ir.o
obj-$(CONFIG_IR_STREAMZAP) += streamzap.o

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*
* driver for ENE KB3926 B/C/D CIR (also known as ENE0XXX)
* driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX)
*
* Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
*
@ -26,43 +26,50 @@
#define ENE_ADDR_HI 1 /* hi byte of register address */
#define ENE_ADDR_LO 2 /* low byte of register address */
#define ENE_IO 3 /* read/write window */
#define ENE_MAX_IO 4
#define ENE_IO_SIZE 4
/* 8 bytes of samples, divided in 2 halfs*/
#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */
#define ENE_SAMPLE_SPC_MASK 0x80 /* sample is space */
#define ENE_SAMPLE_VALUE_MASK 0x7F
#define ENE_SAMPLE_OVERFLOW 0x7F
#define ENE_SAMPLES_SIZE 4
/* 8 bytes of samples, divided in 2 packets*/
#define ENE_FW_SAMPLE_BUFFER 0xF8F0 /* sample buffer */
#define ENE_FW_SAMPLE_SPACE 0x80 /* sample is space */
#define ENE_FW_PACKET_SIZE 4
/* fan input sample buffer */
#define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */
/* each sample of normal buffer */
#define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */
/* if set, says that sample is pulse */
#define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */
/* first firmware register */
#define ENE_FW1 0xF8F8
/* first firmware flag register */
#define ENE_FW1 0xF8F8 /* flagr */
#define ENE_FW1_ENABLE 0x01 /* enable fw processing */
#define ENE_FW1_TXIRQ 0x02 /* TX interrupt pending */
#define ENE_FW1_HAS_EXTRA_BUF 0x04 /* fw uses extra buffer*/
#define ENE_FW1_EXTRA_BUF_HND 0x08 /* extra buffer handshake bit*/
#define ENE_FW1_LED_ON 0x10 /* turn on a led */
#define ENE_FW1_WPATTERN 0x20 /* enable wake pattern */
#define ENE_FW1_WAKE 0x40 /* enable wake from S3 */
#define ENE_FW1_IRQ 0x80 /* enable interrupt */
/* second firmware register */
#define ENE_FW2 0xF8F9
#define ENE_FW2_BUF_HIGH 0x01 /* which half of the buffer to read */
#define ENE_FW2_IRQ_CLR 0x04 /* clear this on IRQ */
#define ENE_FW2_GP40_AS_LEARN 0x08 /* normal input is used as */
/* learning input */
#define ENE_FW2_FAN_AS_NRML_IN 0x40 /* fan is used as normal input */
/* second firmware flag register */
#define ENE_FW2 0xF8F9 /* flagw */
#define ENE_FW2_BUF_WPTR 0x01 /* which half of the buffer to read */
#define ENE_FW2_RXIRQ 0x04 /* RX IRQ pending*/
#define ENE_FW2_GP0A 0x08 /* Use GPIO0A for demodulated input */
#define ENE_FW2_EMMITER1_CONN 0x10 /* TX emmiter 1 connected */
#define ENE_FW2_EMMITER2_CONN 0x20 /* TX emmiter 2 connected */
#define ENE_FW2_FAN_INPUT 0x40 /* fan input used for demodulated data*/
#define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */
/* firmware RX pointer for new style buffer */
#define ENE_FW_RX_POINTER 0xF8FA
/* high parts of samples for fan input (8 samples)*/
#define ENE_FW_SMPL_BUF_FAN 0xF8FB
#define ENE_FW_SMPL_BUF_FAN_PLS 0x8000 /* combined sample is pulse */
#define ENE_FW_SMPL_BUF_FAN_MSK 0x0FFF /* combined sample maximum value */
#define ENE_FW_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */
/* transmitter ports */
#define ENE_TX_PORT2 0xFC01 /* this enables one or both */
#define ENE_TX_PORT2_EN 0x20 /* TX ports */
#define ENE_TX_PORT1 0xFC08
#define ENE_TX_PORT1_EN 0x02
#define ENE_GPIOFS1 0xFC01
#define ENE_GPIOFS1_GPIO0D 0x20 /* enable tx output on GPIO0D */
#define ENE_GPIOFS8 0xFC08
#define ENE_GPIOFS8_GPIO41 0x02 /* enable tx output on GPIO40 */
/* IRQ registers block (for revision B) */
#define ENEB_IRQ 0xFD09 /* IRQ number */
@ -70,98 +77,100 @@
#define ENEB_IRQ_STATUS 0xFD80 /* irq status */
#define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */
/* fan as input settings - only if learning capable */
/* fan as input settings */
#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */
#define ENE_FAN_AS_IN1_EN 0xCD
#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */
#define ENE_FAN_AS_IN2_EN 0x03
#define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */
/* IRQ registers block (for revision C,D) */
#define ENEC_IRQ 0xFE9B /* new irq settings register */
#define ENEC_IRQ_MASK 0x0F /* irq number mask */
#define ENEC_IRQ_UNK_EN 0x10 /* always enabled */
#define ENEC_IRQ_STATUS 0x20 /* irq status and ACK */
#define ENE_IRQ 0xFE9B /* new irq settings register */
#define ENE_IRQ_MASK 0x0F /* irq number mask */
#define ENE_IRQ_UNK_EN 0x10 /* always enabled */
#define ENE_IRQ_STATUS 0x20 /* irq status and ACK */
/* CIR block settings */
#define ENE_CIR_CONF1 0xFEC0
#define ENE_CIR_CONF1_TX_CLEAR 0x01 /* clear that on revC */
/* while transmitting */
#define ENE_CIR_CONF1_RX_ON 0x07 /* normal receiver enabled */
#define ENE_CIR_CONF1_LEARN1 0x08 /* enabled on learning mode */
#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */
#define ENE_CIR_CONF1_TX_CARR 0x80 /* send TX carrier or not */
/* CIR Config register #1 */
#define ENE_CIRCFG 0xFEC0
#define ENE_CIRCFG_RX_EN 0x01 /* RX enable */
#define ENE_CIRCFG_RX_IRQ 0x02 /* Enable hardware interrupt */
#define ENE_CIRCFG_REV_POL 0x04 /* Input polarity reversed */
#define ENE_CIRCFG_CARR_DEMOD 0x08 /* Enable carrier demodulator */
#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */
#define ENE_CIR_CONF2_LEARN2 0x10 /* set on enable learning */
#define ENE_CIR_CONF2_GPIO40DIS 0x20 /* disable input via gpio40 */
#define ENE_CIRCFG_TX_EN 0x10 /* TX enable */
#define ENE_CIRCFG_TX_IRQ 0x20 /* Send interrupt on TX done */
#define ENE_CIRCFG_TX_POL_REV 0x40 /* TX polarity reversed */
#define ENE_CIRCFG_TX_CARR 0x80 /* send TX carrier or not */
#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */
#define ENE_CIR_SAMPLE_OVERFLOW 0x80 /* interrupt on overflows if set */
/* CIR config register #2 */
#define ENE_CIRCFG2 0xFEC1
#define ENE_CIRCFG2_RLC 0x00
#define ENE_CIRCFG2_RC5 0x01
#define ENE_CIRCFG2_RC6 0x02
#define ENE_CIRCFG2_NEC 0x03
#define ENE_CIRCFG2_CARR_DETECT 0x10 /* Enable carrier detection */
#define ENE_CIRCFG2_GPIO0A 0x20 /* Use GPIO0A instead of GPIO40 for input */
#define ENE_CIRCFG2_FAST_SAMPL1 0x40 /* Fast leading pulse detection for RC6 */
#define ENE_CIRCFG2_FAST_SAMPL2 0x80 /* Fast data detection for RC6 */
/* Knobs for protocol decoding - will document when/if will use them */
#define ENE_CIRPF 0xFEC2
#define ENE_CIRHIGH 0xFEC3
#define ENE_CIRBIT 0xFEC4
#define ENE_CIRSTART 0xFEC5
#define ENE_CIRSTART2 0xFEC6
/* Actual register which contains RLC RX data - read by firmware */
#define ENE_CIRDAT_IN 0xFEC7
/* Two byte tx buffer */
#define ENE_TX_INPUT1 0xFEC9
#define ENE_TX_INPUT2 0xFECA
#define ENE_TX_PULSE_MASK 0x80 /* Transmitted sample is pulse */
#define ENE_TX_SMLP_MASK 0x7F
#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period - fixed */
/* RLC configuration - sample period (1us resulution) + idle mode */
#define ENE_CIRRLC_CFG 0xFEC8
#define ENE_CIRRLC_CFG_OVERFLOW 0x80 /* interrupt on overflows if set */
#define ENE_DEFAULT_SAMPLE_PERIOD 50
/* Two byte RLC TX buffer */
#define ENE_CIRRLC_OUT0 0xFEC9
#define ENE_CIRRLC_OUT1 0xFECA
#define ENE_CIRRLC_OUT_PULSE 0x80 /* Transmitted sample is pulse */
#define ENE_CIRRLC_OUT_MASK 0x7F
/* Unknown TX setting - TX sample period ??? */
#define ENE_TX_UNK1 0xFECB /* set to 0x63 */
/* Carrier detect setting
* Low nibble - number of carrier pulses to average
* High nibble - number of initial carrier pulses to discard
*/
#define ENE_CIRCAR_PULS 0xFECB
/* Current received carrier period */
#define ENE_RX_CARRIER 0xFECC /* RX period (500 ns) */
#define ENE_RX_CARRIER_VALID 0x80 /* Register content valid */
/* detected RX carrier period (resolution: 500 ns) */
#define ENE_CIRCAR_PRD 0xFECC
#define ENE_CIRCAR_PRD_VALID 0x80 /* data valid content valid */
/* detected RX carrier pulse width (resolution: 500 ns) */
#define ENE_CIRCAR_HPRD 0xFECD
/* TX period (1/carrier) */
#define ENE_TX_PERIOD 0xFECE /* TX period (500 ns) */
#define ENE_TX_PERIOD_UNKBIT 0x80 /* This bit set on transmit*/
#define ENE_TX_PERIOD_PULSE 0xFECF /* TX pulse period (500 ns)*/
/* TX period (resolution: 500 ns, minimum 2)*/
#define ENE_CIRMOD_PRD 0xFECE
#define ENE_CIRMOD_PRD_POL 0x80 /* TX carrier polarity*/
#define ENE_CIRMOD_PRD_MAX 0x7F /* 15.87 kHz */
#define ENE_CIRMOD_PRD_MIN 0x02 /* 1 Mhz */
/* TX pulse width (resolution: 500 ns)*/
#define ENE_CIRMOD_HPRD 0xFECF
/* Hardware versions */
#define ENE_HW_VERSION 0xFF00 /* hardware revision */
#define ENE_ECHV 0xFF00 /* hardware revision */
#define ENE_PLLFRH 0xFF16
#define ENE_PLLFRL 0xFF17
#define ENE_DEFAULT_PLL_FREQ 1000
#define ENE_HW_UNK 0xFF1D
#define ENE_HW_UNK_CLR 0x04
#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */
#define ENE_HW_VER_MINOR 0xFF1F
#define ENE_ECSTS 0xFF1D
#define ENE_ECSTS_RSRVD 0x04
#define ENE_ECVER_MAJOR 0xFF1E /* chip version */
#define ENE_ECVER_MINOR 0xFF1F
#define ENE_HW_VER_OLD 0xFD00
/* Normal/Learning carrier ranges - only valid if we have learning input*/
/* TODO: test */
#define ENE_NORMAL_RX_LOW 34
#define ENE_NORMAL_RX_HI 38
/* Tx carrier range */
/* Hardware might be able to do more, but this range is enough for
all purposes */
#define ENE_TX_PERIOD_MAX 32 /* corresponds to 29.4 kHz */
#define ENE_TX_PERIOD_MIN 16 /* corrsponds to 62.5 kHz */
/* Minimal and maximal gaps */
/* Normal case:
Minimal gap is 0x7F * sample period
Maximum gap depends on hardware.
For KB3926B, it is unlimited, for newer models its around
250000, after which HW stops sending samples, and that is
not possible to change */
/* Fan case:
Both minimal and maximal gaps are same, and equal to 0xFFF * 0x61
And there is nothing to change this setting
*/
#define ENE_MAXGAP 250000
#define ENE_MINGAP (127 * sample_period)
/******************************************************************************/
#define ENE_DRIVER_NAME "ene_ir"
@ -171,46 +180,60 @@
#define ENE_HW_B 1 /* 3926B */
#define ENE_HW_C 2 /* 3926C */
#define ENE_HW_D 3 /* 3926D */
#define ENE_HW_D 3 /* 3926D or later */
#define ene_printk(level, text, ...) \
printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__)
#define ene_dbg(text, ...) \
if (debug) \
printk(KERN_DEBUG \
ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__)
#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__)
#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__)
#define ene_dbg_verbose(text, ...) \
if (debug > 1) \
printk(KERN_DEBUG \
ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__)
#define __dbg(level, format, ...) \
do { \
if (debug >= level) \
printk(KERN_DEBUG ENE_DRIVER_NAME \
": " format "\n", ## __VA_ARGS__); \
} while (0)
#define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__)
#define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__)
#define dbg_regs(format, ...) __dbg(3, format, ## __VA_ARGS__)
#define MS_TO_NS(msec) ((msec) * 1000)
struct ene_device {
struct pnp_dev *pnp_dev;
struct input_dev *idev;
struct ir_dev_props *props;
int in_use;
/* hw IO settings */
unsigned long hw_io;
long hw_io;
int irq;
spinlock_t hw_lock;
/* HW features */
int hw_revision; /* hardware revision */
bool hw_learning_and_tx_capable; /* learning capable */
bool hw_gpio40_learning; /* gpio40 is learning */
bool hw_fan_as_normal_input; /* fan input is used as */
/* regular input */
bool hw_use_gpio_0a; /* gpio0a is demodulated input*/
bool hw_extra_buffer; /* hardware has 'extra buffer' */
bool hw_fan_input; /* fan input is IR data source */
bool hw_learning_and_tx_capable; /* learning & tx capable */
int pll_freq;
int buffer_len;
/* Extra RX buffer location */
int extra_buf1_address;
int extra_buf1_len;
int extra_buf2_address;
int extra_buf2_len;
/* HW state*/
int rx_pointer; /* hw pointer to rx buffer */
int r_pointer; /* pointer to next sample to read */
int w_pointer; /* pointer to next sample hw will write */
bool rx_fan_input_inuse; /* is fan input in use for rx*/
int tx_reg; /* current reg used for TX */
u8 saved_conf1; /* saved FEC0 reg */
/* TX sample handling */
unsigned int tx_sample; /* current sample for TX */
bool tx_sample_pulse; /* current sample is pulse */
@ -229,7 +252,11 @@ struct ene_device {
int transmitter_mask;
/* RX settings */
bool learning_enabled; /* learning input enabled */
bool learning_mode_enabled; /* learning input enabled */
bool carrier_detect_enabled; /* carrier detect enabled */
int rx_period_adjust;
bool rx_enabled;
};
static int ene_irq_status(struct ene_device *dev);
static void ene_rx_read_hw_pointer(struct ene_device *dev);

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,7 @@
#define _IR_RAW_EVENT
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <media/ir-core.h>
struct ir_raw_handler {
@ -33,6 +34,7 @@ struct ir_raw_handler {
struct ir_raw_event_ctrl {
struct list_head list; /* to keep track of raw clients */
struct task_struct *thread;
spinlock_t lock;
struct kfifo kfifo; /* fifo for the pulse/space durations */
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
@ -76,10 +78,22 @@ struct ir_raw_event_ctrl {
bool first;
bool toggle;
} jvc;
struct rc5_sz_dec {
int state;
u32 bits;
unsigned count;
unsigned wanted_bits;
} rc5_sz;
struct lirc_codec {
struct ir_input_dev *ir_dev;
struct lirc_driver *drv;
int carrier_low;
ktime_t gap_start;
u64 gap_duration;
bool gap;
bool send_timeout_reports;
} lirc;
};
@ -107,13 +121,19 @@ static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
ev->duration -= duration;
}
/* Returns true if event is normal pulse/space event */
static inline bool is_timing_event(struct ir_raw_event ev)
{
return !ev.carrier_report && !ev.reset;
}
#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000)
#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
#define IS_RESET(ev) (ev.duration == 0)
/*
* Routines from ir-sysfs.c - Meant to be called only internally inside
* ir-core
*/
int ir_register_input(struct input_dev *input_dev);
int ir_register_class(struct input_dev *input_dev);
void ir_unregister_class(struct input_dev *input_dev);

View file

@ -50,8 +50,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
return 0;
if (IS_RESET(ev)) {
data->state = STATE_INACTIVE;
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
return 0;
}

View file

@ -435,7 +435,7 @@ EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
* This routine is used to signal that a key has been released on the
* remote control. It reports a keyup input event via input_report_key().
*/
static void ir_keyup(struct ir_input_dev *ir)
void ir_keyup(struct ir_input_dev *ir)
{
if (!ir->keypressed)
return;
@ -445,6 +445,7 @@ static void ir_keyup(struct ir_input_dev *ir)
input_sync(ir->input_dev);
ir->keypressed = false;
}
EXPORT_SYMBOL_GPL(ir_keyup);
/**
* ir_timer_keyup() - generates a keyup event after a timeout
@ -640,6 +641,10 @@ int __ir_input_register(struct input_dev *input_dev,
goto out_event;
}
rc = ir_register_input(input_dev);
if (rc < 0)
goto out_event;
IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
driver_name, rc_tab->name,
(ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ?

View file

@ -32,6 +32,7 @@
static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
struct lirc_codec *lirc = &ir_dev->raw->lirc;
int sample;
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC))
@ -40,21 +41,57 @@ static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf)
return -EINVAL;
if (IS_RESET(ev))
/* Packet start */
if (ev.reset)
return 0;
IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
TO_US(ev.duration), TO_STR(ev.pulse));
/* Carrier reports */
if (ev.carrier_report) {
sample = LIRC_FREQUENCY(ev.carrier);
sample = ev.duration / 1000;
if (ev.pulse)
sample |= PULSE_BIT;
/* Packet end */
} else if (ev.timeout) {
if (lirc->gap)
return 0;
lirc->gap_start = ktime_get();
lirc->gap = true;
lirc->gap_duration = ev.duration;
if (!lirc->send_timeout_reports)
return 0;
sample = LIRC_TIMEOUT(ev.duration / 1000);
/* Normal sample */
} else {
if (lirc->gap) {
int gap_sample;
lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
lirc->gap_start));
/* Convert to ms and cap by LIRC_VALUE_MASK */
do_div(lirc->gap_duration, 1000);
lirc->gap_duration = min(lirc->gap_duration,
(u64)LIRC_VALUE_MASK);
gap_sample = LIRC_SPACE(lirc->gap_duration);
lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
(unsigned char *) &gap_sample);
lirc->gap = false;
}
sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
LIRC_SPACE(ev.duration / 1000);
}
lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
(unsigned char *) &sample);
wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll);
return 0;
}
@ -102,7 +139,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
struct ir_input_dev *ir_dev;
int ret = 0;
void *drv_data;
unsigned long val = 0;
__u32 val = 0, tmp;
lirc = lirc_get_pdata(filep);
if (!lirc)
@ -115,7 +152,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
drv_data = ir_dev->props->priv;
if (_IOC_DIR(cmd) & _IOC_WRITE) {
ret = get_user(val, (unsigned long *)arg);
ret = get_user(val, (__u32 *)arg);
if (ret)
return ret;
}
@ -130,22 +167,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
case LIRC_SET_SEND_MODE:
if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
return -EINVAL;
break;
return 0;
/* TX settings */
case LIRC_SET_TRANSMITTER_MASK:
if (ir_dev->props->s_tx_mask)
ret = ir_dev->props->s_tx_mask(drv_data, (u32)val);
else
if (!ir_dev->props->s_tx_mask)
return -EINVAL;
break;
return ir_dev->props->s_tx_mask(drv_data, val);
case LIRC_SET_SEND_CARRIER:
if (ir_dev->props->s_tx_carrier)
ir_dev->props->s_tx_carrier(drv_data, (u32)val);
else
if (!ir_dev->props->s_tx_carrier)
return -EINVAL;
break;
return ir_dev->props->s_tx_carrier(drv_data, val);
case LIRC_SET_SEND_DUTY_CYCLE:
if (!ir_dev->props->s_tx_duty_cycle)
@ -154,39 +189,42 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
if (val <= 0 || val >= 100)
return -EINVAL;
ir_dev->props->s_tx_duty_cycle(ir_dev->props->priv, val);
break;
return ir_dev->props->s_tx_duty_cycle(drv_data, val);
/* RX settings */
case LIRC_SET_REC_CARRIER:
if (ir_dev->props->s_rx_carrier_range)
ret = ir_dev->props->s_rx_carrier_range(
ir_dev->props->priv,
ir_dev->raw->lirc.carrier_low, val);
else
if (!ir_dev->props->s_rx_carrier_range)
return -ENOSYS;
if (!ret)
ir_dev->raw->lirc.carrier_low = 0;
break;
if (val <= 0)
return -EINVAL;
return ir_dev->props->s_rx_carrier_range(drv_data,
ir_dev->raw->lirc.carrier_low, val);
case LIRC_SET_REC_CARRIER_RANGE:
if (val >= 0)
ir_dev->raw->lirc.carrier_low = val;
break;
if (val <= 0)
return -EINVAL;
ir_dev->raw->lirc.carrier_low = val;
return 0;
case LIRC_GET_REC_RESOLUTION:
val = ir_dev->props->rx_resolution;
break;
case LIRC_SET_WIDEBAND_RECEIVER:
if (ir_dev->props->s_learning_mode)
return ir_dev->props->s_learning_mode(
ir_dev->props->priv, !!val);
else
if (!ir_dev->props->s_learning_mode)
return -ENOSYS;
return ir_dev->props->s_learning_mode(drv_data, !!val);
case LIRC_SET_MEASURE_CARRIER_MODE:
if (!ir_dev->props->s_carrier_report)
return -ENOSYS;
return ir_dev->props->s_carrier_report(drv_data, !!val);
/* Generic timeout support */
case LIRC_GET_MIN_TIMEOUT:
if (!ir_dev->props->max_timeout)
@ -201,10 +239,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
break;
case LIRC_SET_REC_TIMEOUT:
if (val < ir_dev->props->min_timeout ||
val > ir_dev->props->max_timeout)
return -EINVAL;
ir_dev->props->timeout = val * 1000;
if (!ir_dev->props->max_timeout)
return -ENOSYS;
tmp = val * 1000;
if (tmp < ir_dev->props->min_timeout ||
tmp > ir_dev->props->max_timeout)
return -EINVAL;
ir_dev->props->timeout = tmp;
break;
case LIRC_SET_REC_TIMEOUT_REPORTS:
lirc->send_timeout_reports = !!val;
break;
default:
@ -212,7 +260,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
}
if (_IOC_DIR(cmd) & _IOC_READ)
ret = put_user(val, (unsigned long *)arg);
ret = put_user(val, (__u32 *)arg);
return ret;
}
@ -231,6 +279,9 @@ static struct file_operations lirc_fops = {
.owner = THIS_MODULE,
.write = ir_lirc_transmit_ir,
.unlocked_ioctl = ir_lirc_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ir_lirc_ioctl,
#endif
.read = lirc_dev_fop_read,
.poll = lirc_dev_fop_poll,
.open = lirc_dev_fop_open,
@ -278,6 +329,10 @@ static int ir_lirc_register(struct input_dev *input_dev)
if (ir_dev->props->s_learning_mode)
features |= LIRC_CAN_USE_WIDEBAND_RECEIVER;
if (ir_dev->props->s_carrier_report)
features |= LIRC_CAN_MEASURE_CARRIER;
if (ir_dev->props->max_timeout)
features |= LIRC_CAN_SET_REC_TIMEOUT;

View file

@ -54,8 +54,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
return 0;
if (IS_RESET(ev)) {
data->state = STATE_INACTIVE;
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
return 0;
}

View file

@ -39,22 +39,34 @@ static int ir_raw_event_thread(void *data)
struct ir_raw_event ev;
struct ir_raw_handler *handler;
struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
int retval;
while (!kthread_should_stop()) {
try_to_freeze();
mutex_lock(&ir_raw_handler_lock);
spin_lock_irq(&raw->lock);
retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) {
list_for_each_entry(handler, &ir_raw_handler_list, list)
handler->decode(raw->input_dev, ev);
raw->prev_ev = ev;
if (!retval) {
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
set_current_state(TASK_RUNNING);
spin_unlock_irq(&raw->lock);
schedule();
continue;
}
mutex_unlock(&ir_raw_handler_lock);
spin_unlock_irq(&raw->lock);
set_current_state(TASK_INTERRUPTIBLE);
schedule();
BUG_ON(retval != sizeof(ev));
mutex_lock(&ir_raw_handler_lock);
list_for_each_entry(handler, &ir_raw_handler_list, list)
handler->decode(raw->input_dev, ev);
raw->prev_ev = ev;
mutex_unlock(&ir_raw_handler_lock);
}
return 0;
@ -77,7 +89,7 @@ int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev)
if (!ir->raw)
return -EINVAL;
IR_dprintk(2, "sample: (05%dus %s)\n",
IR_dprintk(2, "sample: (%05dus %s)\n",
TO_US(ev->duration), TO_STR(ev->pulse));
if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
@ -162,7 +174,7 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
if (ir->idle && !ev->pulse)
return 0;
else if (ir->idle)
ir_raw_event_set_idle(input_dev, 0);
ir_raw_event_set_idle(input_dev, false);
if (!raw->this_ev.duration) {
raw->this_ev = *ev;
@ -175,48 +187,35 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
/* Enter idle mode if nessesary */
if (!ev->pulse && ir->props->timeout &&
raw->this_ev.duration >= ir->props->timeout)
ir_raw_event_set_idle(input_dev, 1);
raw->this_ev.duration >= ir->props->timeout) {
ir_raw_event_set_idle(input_dev, true);
}
return 0;
}
EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
void ir_raw_event_set_idle(struct input_dev *input_dev, int idle)
/**
* ir_raw_event_set_idle() - hint the ir core if device is receiving
* IR data or not
* @input_dev: the struct input_dev device descriptor
* @idle: the hint value
*/
void ir_raw_event_set_idle(struct input_dev *input_dev, bool idle)
{
struct ir_input_dev *ir = input_get_drvdata(input_dev);
struct ir_raw_event_ctrl *raw = ir->raw;
ktime_t now;
u64 delta;
if (!ir->props)
if (!ir->props || !ir->raw)
return;
if (!ir->raw)
goto out;
IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
if (idle) {
IR_dprintk(2, "enter idle mode\n");
raw->last_event = ktime_get();
} else {
IR_dprintk(2, "exit idle mode\n");
now = ktime_get();
delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
WARN_ON(raw->this_ev.pulse);
raw->this_ev.duration =
min(raw->this_ev.duration + delta,
(u64)IR_MAX_DURATION);
raw->this_ev.timeout = true;
ir_raw_event_store(input_dev, &raw->this_ev);
if (raw->this_ev.duration == IR_MAX_DURATION)
ir_raw_event_reset(input_dev);
raw->this_ev.duration = 0;
init_ir_raw_event(&raw->this_ev);
}
out:
if (ir->props->s_idle)
ir->props->s_idle(ir->props->priv, idle);
ir->idle = idle;
@ -232,11 +231,14 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
void ir_raw_event_handle(struct input_dev *input_dev)
{
struct ir_input_dev *ir = input_get_drvdata(input_dev);
unsigned long flags;
if (!ir->raw)
return;
spin_lock_irqsave(&ir->raw->lock, flags);
wake_up_process(ir->raw->thread);
spin_unlock_irqrestore(&ir->raw->lock, flags);
}
EXPORT_SYMBOL_GPL(ir_raw_event_handle);
@ -275,6 +277,7 @@ int ir_raw_event_register(struct input_dev *input_dev)
return rc;
}
spin_lock_init(&ir->raw->lock);
ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw,
"rc%u", (unsigned int)ir->devno);

View file

@ -55,8 +55,9 @@ static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
return 0;
if (IS_RESET(ev)) {
data->state = STATE_INACTIVE;
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
return 0;
}

View file

@ -0,0 +1,154 @@
/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol
*
* Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
* Copyright (C) 2010 by Jarod Wilson <jarod@redhat.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 version 2 of the License.
*
* 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.
*/
/*
* This code handles the 15 bit RC5-ish protocol used by the Streamzap
* PC Remote.
* It considers a carrier of 36 kHz, with a total of 15 bits, where
* the first two bits are start bits, and a third one is a filing bit
*/
#include "ir-core-priv.h"
#define RC5_SZ_NBITS 15
#define RC5_UNIT 888888 /* ns */
#define RC5_BIT_START (1 * RC5_UNIT)
#define RC5_BIT_END (1 * RC5_UNIT)
enum rc5_sz_state {
STATE_INACTIVE,
STATE_BIT_START,
STATE_BIT_END,
STATE_FINISHED,
};
/**
* ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
* @input_dev: the struct input_dev descriptor of the device
* @ev: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
static int ir_rc5_sz_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
struct rc5_sz_dec *data = &ir_dev->raw->rc5_sz;
u8 toggle, command, system;
u32 scancode;
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5_SZ))
return 0;
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
return 0;
}
if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
goto out;
again:
IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n",
data->state, TO_US(ev.duration), TO_STR(ev.pulse));
if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
return 0;
switch (data->state) {
case STATE_INACTIVE:
if (!ev.pulse)
break;
data->state = STATE_BIT_START;
data->count = 1;
data->wanted_bits = RC5_SZ_NBITS;
decrease_duration(&ev, RC5_BIT_START);
goto again;
case STATE_BIT_START:
if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
break;
data->bits <<= 1;
if (!ev.pulse)
data->bits |= 1;
data->count++;
data->state = STATE_BIT_END;
return 0;
case STATE_BIT_END:
if (!is_transition(&ev, &ir_dev->raw->prev_ev))
break;
if (data->count == data->wanted_bits)
data->state = STATE_FINISHED;
else
data->state = STATE_BIT_START;
decrease_duration(&ev, RC5_BIT_END);
goto again;
case STATE_FINISHED:
if (ev.pulse)
break;
/* RC5-sz */
command = (data->bits & 0x0003F) >> 0;
system = (data->bits & 0x02FC0) >> 6;
toggle = (data->bits & 0x01000) ? 1 : 0;
scancode = system << 6 | command;
IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
scancode, toggle);
ir_keydown(input_dev, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
out:
IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n",
data->state, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
static struct ir_raw_handler rc5_sz_handler = {
.protocols = IR_TYPE_RC5_SZ,
.decode = ir_rc5_sz_decode,
};
static int __init ir_rc5_sz_decode_init(void)
{
ir_raw_handler_register(&rc5_sz_handler);
printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n");
return 0;
}
static void __exit ir_rc5_sz_decode_exit(void)
{
ir_raw_handler_unregister(&rc5_sz_handler);
}
module_init(ir_rc5_sz_decode_init);
module_exit(ir_rc5_sz_decode_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jarod Wilson <[email protected]>");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder");

View file

@ -85,8 +85,9 @@ static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
return 0;
if (IS_RESET(ev)) {
data->state = STATE_INACTIVE;
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
return 0;
}

View file

@ -48,8 +48,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
return 0;
if (IS_RESET(ev)) {
data->state = STATE_INACTIVE;
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
return 0;
}

View file

@ -43,6 +43,7 @@ static struct {
{ IR_TYPE_RC6, "rc-6" },
{ IR_TYPE_JVC, "jvc" },
{ IR_TYPE_SONY, "sony" },
{ IR_TYPE_RC5_SZ, "rc-5-sz" },
{ IR_TYPE_LIRC, "lirc" },
};
@ -67,6 +68,10 @@ static ssize_t show_protocols(struct device *d,
char *tmp = buf;
int i;
/* Device is being removed */
if (!ir_dev)
return -EINVAL;
if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
enabled = ir_dev->rc_tab.ir_type;
allowed = ir_dev->props->allowed_protos;
@ -122,6 +127,10 @@ static ssize_t store_protocols(struct device *d,
int rc, i, count = 0;
unsigned long flags;
/* Device is being removed */
if (!ir_dev)
return -EINVAL;
if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
type = ir_dev->rc_tab.ir_type;
else if (ir_dev->raw)
@ -256,8 +265,6 @@ static struct device_type rc_dev_type = {
*/
int ir_register_class(struct input_dev *input_dev)
{
int rc;
const char *path;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
int devno = find_first_zero_bit(&ir_core_dev_number,
IRRCV_NUM_DEVICES);
@ -266,17 +273,28 @@ int ir_register_class(struct input_dev *input_dev)
return devno;
ir_dev->dev.type = &rc_dev_type;
ir_dev->devno = devno;
ir_dev->dev.class = &ir_input_class;
ir_dev->dev.parent = input_dev->dev.parent;
input_dev->dev.parent = &ir_dev->dev;
dev_set_name(&ir_dev->dev, "rc%d", devno);
dev_set_drvdata(&ir_dev->dev, ir_dev);
rc = device_register(&ir_dev->dev);
if (rc)
return rc;
return device_register(&ir_dev->dev);
};
/**
* ir_register_input - registers ir input device with input subsystem
* @input_dev: the struct input_dev descriptor of the device
*/
int ir_register_input(struct input_dev *input_dev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
int rc;
const char *path;
input_dev->dev.parent = &ir_dev->dev;
rc = input_register_device(input_dev);
if (rc < 0) {
device_del(&ir_dev->dev);
@ -292,11 +310,9 @@ int ir_register_class(struct input_dev *input_dev)
path ? path : "N/A");
kfree(path);
ir_dev->devno = devno;
set_bit(devno, &ir_core_dev_number);
set_bit(ir_dev->devno, &ir_core_dev_number);
return 0;
};
}
/**
* ir_unregister_class() - removes the sysfs for sysfs for
@ -309,6 +325,7 @@ void ir_unregister_class(struct input_dev *input_dev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
input_set_drvdata(input_dev, NULL);
clear_bit(ir_dev->devno, &ir_core_dev_number);
input_unregister_device(input_dev);
device_del(&ir_dev->dev);

View file

@ -1,4 +1,6 @@
obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-alink-dtu-m.o \
rc-anysee.o \
rc-apac-viewcomp.o \
rc-asus-pc39.o \
rc-ati-tv-wonder-hd-600.o \
@ -8,7 +10,9 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-avermedia-dvbt.o \
rc-avermedia-m135a.o \
rc-avermedia-m733a-rm-k6.o \
rc-avermedia-rm-ks.o \
rc-avertv-303.o \
rc-azurewave-ad-tu700.o \
rc-behold.o \
rc-behold-columbus.o \
rc-budget-ci-old.o \
@ -16,6 +20,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-cinergy.o \
rc-dib0700-nec.o \
rc-dib0700-rc5.o \
rc-digitalnow-tinytwin.o \
rc-digittrade.o \
rc-dm1105-nec.o \
rc-dntv-live-dvb-t.o \
rc-dntv-live-dvbt-pro.o \
@ -38,8 +44,12 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-kaiomy.o \
rc-kworld-315u.o \
rc-kworld-plus-tv-analog.o \
rc-leadtek-y04g0051.o \
rc-lirc.o \
rc-lme2510.o \
rc-manli.o \
rc-msi-digivox-ii.o \
rc-msi-digivox-iii.o \
rc-msi-tvanywhere.o \
rc-msi-tvanywhere-plus.o \
rc-nebula.o \
@ -58,14 +68,18 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-purpletv.o \
rc-pv951.o \
rc-rc5-hauppauge-new.o \
rc-rc5-streamzap.o \
rc-rc5-tv.o \
rc-rc6-mce.o \
rc-real-audio-220-32-keys.o \
rc-streamzap.o \
rc-tbs-nec.o \
rc-terratec-cinergy-xs.o \
rc-terratec-slim.o \
rc-tevii-nec.o \
rc-total-media-in-hand.o \
rc-trekstor.o \
rc-tt-1500.o \
rc-twinhan1027.o \
rc-videomate-s350.o \
rc-videomate-tv-pvr.o \
rc-winfast.o \

View file

@ -0,0 +1,68 @@
/*
* A-Link DTU(m) remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
/* A-Link DTU(m) slim remote, 6 rows, 3 columns. */
static struct ir_scancode alink_dtu_m[] = {
{ 0x0800, KEY_VOLUMEUP },
{ 0x0801, KEY_1 },
{ 0x0802, KEY_3 },
{ 0x0803, KEY_7 },
{ 0x0804, KEY_9 },
{ 0x0805, KEY_NEW }, /* symbol: PIP */
{ 0x0806, KEY_0 },
{ 0x0807, KEY_CHANNEL }, /* JUMP */
{ 0x080d, KEY_5 },
{ 0x080f, KEY_2 },
{ 0x0812, KEY_POWER2 },
{ 0x0814, KEY_CHANNELUP },
{ 0x0816, KEY_VOLUMEDOWN },
{ 0x0818, KEY_6 },
{ 0x081a, KEY_MUTE },
{ 0x081b, KEY_8 },
{ 0x081c, KEY_4 },
{ 0x081d, KEY_CHANNELDOWN },
};
static struct rc_keymap alink_dtu_m_map = {
.map = {
.scan = alink_dtu_m,
.size = ARRAY_SIZE(alink_dtu_m),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_ALINK_DTU_M,
}
};
static int __init init_rc_map_alink_dtu_m(void)
{
return ir_register_map(&alink_dtu_m_map);
}
static void __exit exit_rc_map_alink_dtu_m(void)
{
ir_unregister_map(&alink_dtu_m_map);
}
module_init(init_rc_map_alink_dtu_m)
module_exit(exit_rc_map_alink_dtu_m)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,93 @@
/*
* Anysee remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
static struct ir_scancode anysee[] = {
{ 0x0800, KEY_0 },
{ 0x0801, KEY_1 },
{ 0x0802, KEY_2 },
{ 0x0803, KEY_3 },
{ 0x0804, KEY_4 },
{ 0x0805, KEY_5 },
{ 0x0806, KEY_6 },
{ 0x0807, KEY_7 },
{ 0x0808, KEY_8 },
{ 0x0809, KEY_9 },
{ 0x080a, KEY_POWER2 }, /* [red power button] */
{ 0x080b, KEY_VIDEO }, /* [*] MODE */
{ 0x080c, KEY_CHANNEL }, /* [symbol counterclockwise arrow] */
{ 0x080d, KEY_NEXT }, /* [>>|] */
{ 0x080e, KEY_MENU }, /* MENU */
{ 0x080f, KEY_EPG }, /* [EPG] */
{ 0x0810, KEY_CLEAR }, /* EXIT */
{ 0x0811, KEY_CHANNELUP },
{ 0x0812, KEY_VOLUMEDOWN },
{ 0x0813, KEY_VOLUMEUP },
{ 0x0814, KEY_CHANNELDOWN },
{ 0x0815, KEY_OK },
{ 0x0816, KEY_RADIO }, /* [symbol TV/radio] */
{ 0x0817, KEY_INFO }, /* [i] */
{ 0x0818, KEY_PREVIOUS }, /* [|<<] */
{ 0x0819, KEY_FAVORITES }, /* FAV. */
{ 0x081a, KEY_SUBTITLE }, /* Subtitle */
{ 0x081b, KEY_CAMERA }, /* [symbol camera] */
{ 0x081c, KEY_YELLOW },
{ 0x081d, KEY_RED },
{ 0x081e, KEY_LANGUAGE }, /* [symbol Second Audio Program] */
{ 0x081f, KEY_GREEN },
{ 0x0820, KEY_SLEEP }, /* Sleep */
{ 0x0821, KEY_SCREEN }, /* 16:9 / 4:3 */
{ 0x0822, KEY_ZOOM }, /* SIZE */
{ 0x0824, KEY_FN }, /* [F1] */
{ 0x0825, KEY_FN }, /* [F2] */
{ 0x0842, KEY_MUTE }, /* symbol mute */
{ 0x0844, KEY_BLUE },
{ 0x0847, KEY_TEXT }, /* TEXT */
{ 0x0848, KEY_STOP },
{ 0x0849, KEY_RECORD },
{ 0x0850, KEY_PLAY },
{ 0x0851, KEY_PAUSE },
};
static struct rc_keymap anysee_map = {
.map = {
.scan = anysee,
.size = ARRAY_SIZE(anysee),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_ANYSEE,
}
};
static int __init init_rc_map_anysee(void)
{
return ir_register_map(&anysee_map);
}
static void __exit exit_rc_map_anysee(void)
{
ir_unregister_map(&anysee_map);
}
module_init(init_rc_map_anysee)
module_exit(exit_rc_map_anysee)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -20,56 +20,56 @@
static struct ir_scancode asus_pc39[] = {
/* Keys 0 to 9 */
{ 0x15, KEY_0 },
{ 0x29, KEY_1 },
{ 0x2d, KEY_2 },
{ 0x2b, KEY_3 },
{ 0x09, KEY_4 },
{ 0x0d, KEY_5 },
{ 0x0b, KEY_6 },
{ 0x31, KEY_7 },
{ 0x35, KEY_8 },
{ 0x33, KEY_9 },
{ 0x082a, KEY_0 },
{ 0x0816, KEY_1 },
{ 0x0812, KEY_2 },
{ 0x0814, KEY_3 },
{ 0x0836, KEY_4 },
{ 0x0832, KEY_5 },
{ 0x0834, KEY_6 },
{ 0x080e, KEY_7 },
{ 0x080a, KEY_8 },
{ 0x080c, KEY_9 },
{ 0x3e, KEY_RADIO }, /* radio */
{ 0x03, KEY_MENU }, /* dvd/menu */
{ 0x2a, KEY_VOLUMEUP },
{ 0x19, KEY_VOLUMEDOWN },
{ 0x37, KEY_UP },
{ 0x3b, KEY_DOWN },
{ 0x27, KEY_LEFT },
{ 0x2f, KEY_RIGHT },
{ 0x25, KEY_VIDEO }, /* video */
{ 0x39, KEY_AUDIO }, /* music */
{ 0x0801, KEY_RADIO }, /* radio */
{ 0x083c, KEY_MENU }, /* dvd/menu */
{ 0x0815, KEY_VOLUMEUP },
{ 0x0826, KEY_VOLUMEDOWN },
{ 0x0808, KEY_UP },
{ 0x0804, KEY_DOWN },
{ 0x0818, KEY_LEFT },
{ 0x0810, KEY_RIGHT },
{ 0x081a, KEY_VIDEO }, /* video */
{ 0x0806, KEY_AUDIO }, /* music */
{ 0x21, KEY_TV }, /* tv */
{ 0x1d, KEY_EXIT }, /* back */
{ 0x0a, KEY_CHANNELUP }, /* channel / program + */
{ 0x1b, KEY_CHANNELDOWN }, /* channel / program - */
{ 0x1a, KEY_ENTER }, /* enter */
{ 0x081e, KEY_TV }, /* tv */
{ 0x0822, KEY_EXIT }, /* back */
{ 0x0835, KEY_CHANNELUP }, /* channel / program + */
{ 0x0824, KEY_CHANNELDOWN }, /* channel / program - */
{ 0x0825, KEY_ENTER }, /* enter */
{ 0x06, KEY_PAUSE }, /* play/pause */
{ 0x1e, KEY_PREVIOUS }, /* rew */
{ 0x26, KEY_NEXT }, /* forward */
{ 0x0e, KEY_REWIND }, /* backward << */
{ 0x3a, KEY_FASTFORWARD }, /* forward >> */
{ 0x36, KEY_STOP },
{ 0x2e, KEY_RECORD }, /* recording */
{ 0x16, KEY_POWER }, /* the button that reads "close" */
{ 0x0839, KEY_PAUSE }, /* play/pause */
{ 0x0821, KEY_PREVIOUS }, /* rew */
{ 0x0819, KEY_NEXT }, /* forward */
{ 0x0831, KEY_REWIND }, /* backward << */
{ 0x0805, KEY_FASTFORWARD }, /* forward >> */
{ 0x0809, KEY_STOP },
{ 0x0811, KEY_RECORD }, /* recording */
{ 0x0829, KEY_POWER }, /* the button that reads "close" */
{ 0x11, KEY_ZOOM }, /* full screen */
{ 0x13, KEY_MACRO }, /* recall */
{ 0x23, KEY_HOME }, /* home */
{ 0x05, KEY_PVR }, /* picture */
{ 0x3d, KEY_MUTE }, /* mute */
{ 0x01, KEY_DVD }, /* dvd */
{ 0x082e, KEY_ZOOM }, /* full screen */
{ 0x082c, KEY_MACRO }, /* recall */
{ 0x081c, KEY_HOME }, /* home */
{ 0x083a, KEY_PVR }, /* picture */
{ 0x0802, KEY_MUTE }, /* mute */
{ 0x083e, KEY_DVD }, /* dvd */
};
static struct rc_keymap asus_pc39_map = {
.map = {
.scan = asus_pc39,
.size = ARRAY_SIZE(asus_pc39),
.ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
.ir_type = IR_TYPE_RC5,
.name = RC_MAP_ASUS_PC39,
}
};

View file

@ -0,0 +1,79 @@
/*
* AverMedia RM-KS remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
/* Initial keytable is from Jose Alberto Reguero <[email protected]>
and Felipe Morales Moreno <felipe.morales.moreno@gmail.com> */
/* FIXME: mappings are not 100% correct? */
static struct ir_scancode avermedia_rm_ks[] = {
{ 0x0501, KEY_POWER2 },
{ 0x0502, KEY_CHANNELUP },
{ 0x0503, KEY_CHANNELDOWN },
{ 0x0504, KEY_VOLUMEUP },
{ 0x0505, KEY_VOLUMEDOWN },
{ 0x0506, KEY_MUTE },
{ 0x0507, KEY_RIGHT },
{ 0x0508, KEY_PROG1 },
{ 0x0509, KEY_1 },
{ 0x050a, KEY_2 },
{ 0x050b, KEY_3 },
{ 0x050c, KEY_4 },
{ 0x050d, KEY_5 },
{ 0x050e, KEY_6 },
{ 0x050f, KEY_7 },
{ 0x0510, KEY_8 },
{ 0x0511, KEY_9 },
{ 0x0512, KEY_0 },
{ 0x0513, KEY_AUDIO },
{ 0x0515, KEY_EPG },
{ 0x0516, KEY_PLAY },
{ 0x0517, KEY_RECORD },
{ 0x0518, KEY_STOP },
{ 0x051c, KEY_BACK },
{ 0x051d, KEY_FORWARD },
{ 0x054d, KEY_LEFT },
{ 0x0556, KEY_ZOOM },
};
static struct rc_keymap avermedia_rm_ks_map = {
.map = {
.scan = avermedia_rm_ks,
.size = ARRAY_SIZE(avermedia_rm_ks),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_AVERMEDIA_RM_KS,
}
};
static int __init init_rc_map_avermedia_rm_ks(void)
{
return ir_register_map(&avermedia_rm_ks_map);
}
static void __exit exit_rc_map_avermedia_rm_ks(void)
{
ir_unregister_map(&avermedia_rm_ks_map);
}
module_init(init_rc_map_avermedia_rm_ks)
module_exit(exit_rc_map_avermedia_rm_ks)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,102 @@
/*
* TwinHan AzureWave AD-TU700(704J) remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
static struct ir_scancode azurewave_ad_tu700[] = {
{ 0x0000, KEY_TAB }, /* Tab */
{ 0x0001, KEY_2 },
{ 0x0002, KEY_CHANNELDOWN },
{ 0x0003, KEY_1 },
{ 0x0004, KEY_MENU }, /* Record List */
{ 0x0005, KEY_CHANNELUP },
{ 0x0006, KEY_3 },
{ 0x0007, KEY_SLEEP }, /* Hibernate */
{ 0x0008, KEY_VIDEO }, /* A/V */
{ 0x0009, KEY_4 },
{ 0x000a, KEY_VOLUMEDOWN },
{ 0x000c, KEY_CANCEL }, /* Cancel */
{ 0x000d, KEY_7 },
{ 0x000e, KEY_AGAIN }, /* Recall */
{ 0x000f, KEY_TEXT }, /* Teletext */
{ 0x0010, KEY_MUTE },
{ 0x0011, KEY_RECORD },
{ 0x0012, KEY_FASTFORWARD }, /* FF >> */
{ 0x0013, KEY_BACK }, /* Back */
{ 0x0014, KEY_PLAY },
{ 0x0015, KEY_0 },
{ 0x0016, KEY_POWER2 }, /* [red power button] */
{ 0x0017, KEY_FAVORITES }, /* Favorite List */
{ 0x0018, KEY_RED },
{ 0x0019, KEY_8 },
{ 0x001a, KEY_STOP },
{ 0x001b, KEY_9 },
{ 0x001c, KEY_EPG }, /* Info/EPG */
{ 0x001d, KEY_5 },
{ 0x001e, KEY_VOLUMEUP },
{ 0x001f, KEY_6 },
{ 0x0040, KEY_REWIND }, /* FR << */
{ 0x0041, KEY_PREVIOUS }, /* Replay */
{ 0x0042, KEY_NEXT }, /* Skip */
{ 0x0043, KEY_SUBTITLE }, /* Subtitle / CC */
{ 0x0045, KEY_KPPLUS }, /* Zoom+ */
{ 0x0046, KEY_KPMINUS }, /* Zoom- */
{ 0x0047, KEY_NEW }, /* PIP */
{ 0x0048, KEY_INFO }, /* Preview */
{ 0x0049, KEY_MODE }, /* L/R */
{ 0x004a, KEY_CLEAR }, /* Clear */
{ 0x004b, KEY_UP }, /* up arrow */
{ 0x004c, KEY_PAUSE },
{ 0x004d, KEY_ZOOM }, /* Full Screen */
{ 0x004e, KEY_LEFT }, /* left arrow */
{ 0x004f, KEY_OK }, /* Enter / ok */
{ 0x0050, KEY_LANGUAGE }, /* SAP */
{ 0x0051, KEY_DOWN }, /* down arrow */
{ 0x0052, KEY_RIGHT }, /* right arrow */
{ 0x0053, KEY_GREEN },
{ 0x0054, KEY_CAMERA }, /* Capture */
{ 0x005e, KEY_YELLOW },
{ 0x005f, KEY_BLUE },
};
static struct rc_keymap azurewave_ad_tu700_map = {
.map = {
.scan = azurewave_ad_tu700,
.size = ARRAY_SIZE(azurewave_ad_tu700),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_AZUREWAVE_AD_TU700,
}
};
static int __init init_rc_map_azurewave_ad_tu700(void)
{
return ir_register_map(&azurewave_ad_tu700_map);
}
static void __exit exit_rc_map_azurewave_ad_tu700(void)
{
ir_unregister_map(&azurewave_ad_tu700_map);
}
module_init(init_rc_map_azurewave_ad_tu700)
module_exit(exit_rc_map_azurewave_ad_tu700)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,98 @@
/*
* DigitalNow TinyTwin remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
static struct ir_scancode digitalnow_tinytwin[] = {
{ 0x0000, KEY_MUTE }, /* [symbol speaker] */
{ 0x0001, KEY_VOLUMEUP },
{ 0x0002, KEY_POWER2 }, /* TV [power button] */
{ 0x0003, KEY_2 },
{ 0x0004, KEY_3 },
{ 0x0005, KEY_4 },
{ 0x0006, KEY_6 },
{ 0x0007, KEY_7 },
{ 0x0008, KEY_8 },
{ 0x0009, KEY_NUMERIC_STAR }, /* [*] */
{ 0x000a, KEY_0 },
{ 0x000b, KEY_NUMERIC_POUND }, /* [#] */
{ 0x000c, KEY_RIGHT }, /* [right arrow] */
{ 0x000d, KEY_HOMEPAGE }, /* [symbol home] Start */
{ 0x000e, KEY_RED }, /* [red] Videos */
{ 0x0010, KEY_POWER }, /* PC [power button] */
{ 0x0011, KEY_YELLOW }, /* [yellow] Pictures */
{ 0x0012, KEY_DOWN }, /* [down arrow] */
{ 0x0013, KEY_GREEN }, /* [green] Music */
{ 0x0014, KEY_CYCLEWINDOWS }, /* BACK */
{ 0x0015, KEY_FAVORITES }, /* MORE */
{ 0x0016, KEY_UP }, /* [up arrow] */
{ 0x0017, KEY_LEFT }, /* [left arrow] */
{ 0x0018, KEY_OK }, /* OK */
{ 0x0019, KEY_BLUE }, /* [blue] MyTV */
{ 0x001a, KEY_REWIND }, /* REW [<<] */
{ 0x001b, KEY_PLAY }, /* PLAY */
{ 0x001c, KEY_5 },
{ 0x001d, KEY_9 },
{ 0x001e, KEY_VOLUMEDOWN },
{ 0x001f, KEY_1 },
{ 0x0040, KEY_STOP }, /* STOP */
{ 0x0042, KEY_PAUSE }, /* PAUSE */
{ 0x0043, KEY_SCREEN }, /* Aspect */
{ 0x0044, KEY_FORWARD }, /* FWD [>>] */
{ 0x0045, KEY_NEXT }, /* SKIP */
{ 0x0048, KEY_RECORD }, /* RECORD */
{ 0x0049, KEY_VIDEO }, /* RTV */
{ 0x004a, KEY_EPG }, /* Guide */
{ 0x004b, KEY_CHANNELUP },
{ 0x004c, KEY_HELP }, /* Help */
{ 0x004d, KEY_RADIO }, /* Radio */
{ 0x004f, KEY_CHANNELDOWN },
{ 0x0050, KEY_DVD }, /* DVD */
{ 0x0051, KEY_AUDIO }, /* Audio */
{ 0x0052, KEY_TITLE }, /* Title */
{ 0x0053, KEY_NEW }, /* [symbol PIP?] */
{ 0x0057, KEY_MENU }, /* Mouse */
{ 0x005a, KEY_PREVIOUS }, /* REPLAY */
};
static struct rc_keymap digitalnow_tinytwin_map = {
.map = {
.scan = digitalnow_tinytwin,
.size = ARRAY_SIZE(digitalnow_tinytwin),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_DIGITALNOW_TINYTWIN,
}
};
static int __init init_rc_map_digitalnow_tinytwin(void)
{
return ir_register_map(&digitalnow_tinytwin_map);
}
static void __exit exit_rc_map_digitalnow_tinytwin(void)
{
ir_unregister_map(&digitalnow_tinytwin_map);
}
module_init(init_rc_map_digitalnow_tinytwin)
module_exit(exit_rc_map_digitalnow_tinytwin)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,82 @@
/*
* Digittrade DVB-T USB Stick remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
/* Digittrade DVB-T USB Stick remote controller. */
/* Imported from af9015.h.
Initial keytable was from Alain Kalker <miki@dds.nl> */
/* Digittrade DVB-T USB Stick */
static struct ir_scancode digittrade[] = {
{ 0x0000, KEY_9 },
{ 0x0001, KEY_EPG }, /* EPG */
{ 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */
{ 0x0003, KEY_TEXT }, /* TELETEXT */
{ 0x0004, KEY_8 },
{ 0x0005, KEY_MUTE }, /* MUTE */
{ 0x0006, KEY_POWER2 }, /* POWER */
{ 0x0009, KEY_ZOOM }, /* FULLSCREEN */
{ 0x000a, KEY_RECORD }, /* RECORD */
{ 0x000d, KEY_SUBTITLE }, /* SUBTITLE */
{ 0x000e, KEY_STOP }, /* STOP */
{ 0x0010, KEY_OK }, /* RETURN */
{ 0x0011, KEY_2 },
{ 0x0012, KEY_4 },
{ 0x0015, KEY_3 },
{ 0x0016, KEY_5 },
{ 0x0017, KEY_CHANNELDOWN }, /* Ch Dn */
{ 0x0019, KEY_CHANNELUP }, /* CH Up */
{ 0x001a, KEY_PAUSE }, /* PAUSE */
{ 0x001b, KEY_1 },
{ 0x001d, KEY_AUDIO }, /* DUAL SOUND */
{ 0x001e, KEY_PLAY }, /* PLAY */
{ 0x001f, KEY_CAMERA }, /* SNAPSHOT */
{ 0x0040, KEY_VOLUMEUP }, /* Vol Up */
{ 0x0048, KEY_7 },
{ 0x004c, KEY_6 },
{ 0x004d, KEY_PLAYPAUSE }, /* TIMESHIFT */
{ 0x0054, KEY_0 },
};
static struct rc_keymap digittrade_map = {
.map = {
.scan = digittrade,
.size = ARRAY_SIZE(digittrade),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_DIGITTRADE,
}
};
static int __init init_rc_map_digittrade(void)
{
return ir_register_map(&digittrade_map);
}
static void __exit exit_rc_map_digittrade(void)
{
ir_unregister_map(&digittrade_map);
}
module_init(init_rc_map_digittrade)
module_exit(exit_rc_map_digittrade)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,99 @@
/*
* LeadTek Y04G0051 remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
static struct ir_scancode leadtek_y04g0051[] = {
{ 0x0300, KEY_POWER2 },
{ 0x0303, KEY_SCREEN },
{ 0x0304, KEY_RIGHT },
{ 0x0305, KEY_1 },
{ 0x0306, KEY_2 },
{ 0x0307, KEY_3 },
{ 0x0308, KEY_LEFT },
{ 0x0309, KEY_4 },
{ 0x030a, KEY_5 },
{ 0x030b, KEY_6 },
{ 0x030c, KEY_UP },
{ 0x030d, KEY_7 },
{ 0x030e, KEY_8 },
{ 0x030f, KEY_9 },
{ 0x0310, KEY_DOWN },
{ 0x0311, KEY_AGAIN },
{ 0x0312, KEY_0 },
{ 0x0313, KEY_OK }, /* 1st ok */
{ 0x0314, KEY_MUTE },
{ 0x0316, KEY_OK }, /* 2nd ok */
{ 0x031e, KEY_VIDEO }, /* 2nd video */
{ 0x031b, KEY_AUDIO },
{ 0x031f, KEY_TEXT },
{ 0x0340, KEY_SLEEP },
{ 0x0341, KEY_DOT },
{ 0x0342, KEY_REWIND },
{ 0x0343, KEY_PLAY },
{ 0x0344, KEY_FASTFORWARD },
{ 0x0345, KEY_TIME },
{ 0x0346, KEY_STOP }, /* 2nd stop */
{ 0x0347, KEY_RECORD },
{ 0x0348, KEY_CAMERA },
{ 0x0349, KEY_ESC },
{ 0x034a, KEY_NEW },
{ 0x034b, KEY_RED },
{ 0x034c, KEY_GREEN },
{ 0x034d, KEY_YELLOW },
{ 0x034e, KEY_BLUE },
{ 0x034f, KEY_MENU },
{ 0x0350, KEY_STOP }, /* 1st stop */
{ 0x0351, KEY_CHANNEL },
{ 0x0352, KEY_VIDEO }, /* 1st video */
{ 0x0353, KEY_EPG },
{ 0x0354, KEY_PREVIOUS },
{ 0x0355, KEY_NEXT },
{ 0x0356, KEY_TV },
{ 0x035a, KEY_VOLUMEDOWN },
{ 0x035b, KEY_CHANNELUP },
{ 0x035e, KEY_VOLUMEUP },
{ 0x035f, KEY_CHANNELDOWN },
};
static struct rc_keymap leadtek_y04g0051_map = {
.map = {
.scan = leadtek_y04g0051,
.size = ARRAY_SIZE(leadtek_y04g0051),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_LEADTEK_Y04G0051,
}
};
static int __init init_rc_map_leadtek_y04g0051(void)
{
return ir_register_map(&leadtek_y04g0051_map);
}
static void __exit exit_rc_map_leadtek_y04g0051(void)
{
ir_unregister_map(&leadtek_y04g0051_map);
}
module_init(init_rc_map_leadtek_y04g0051)
module_exit(exit_rc_map_leadtek_y04g0051)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,68 @@
/* LME2510 remote control
*
*
* Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.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.
*/
#include <media/rc-map.h>
static struct ir_scancode lme2510_rc[] = {
{ 0xba45, KEY_0 },
{ 0xa05f, KEY_1 },
{ 0xaf50, KEY_2 },
{ 0xa25d, KEY_3 },
{ 0xbe41, KEY_4 },
{ 0xf50a, KEY_5 },
{ 0xbd42, KEY_6 },
{ 0xb847, KEY_7 },
{ 0xb649, KEY_8 },
{ 0xfa05, KEY_9 },
{ 0xbc43, KEY_POWER },
{ 0xb946, KEY_SUBTITLE },
{ 0xf906, KEY_PAUSE },
{ 0xfc03, KEY_MEDIA_REPEAT},
{ 0xfd02, KEY_PAUSE },
{ 0xa15e, KEY_VOLUMEUP },
{ 0xa35c, KEY_VOLUMEDOWN },
{ 0xf609, KEY_CHANNELUP },
{ 0xe51a, KEY_CHANNELDOWN },
{ 0xe11e, KEY_PLAY },
{ 0xe41b, KEY_ZOOM },
{ 0xa659, KEY_MUTE },
{ 0xa55a, KEY_TV },
{ 0xe718, KEY_RECORD },
{ 0xf807, KEY_EPG },
{ 0xfe01, KEY_STOP },
};
static struct rc_keymap lme2510_map = {
.map = {
.scan = lme2510_rc,
.size = ARRAY_SIZE(lme2510_rc),
.ir_type = IR_TYPE_UNKNOWN,
.name = RC_MAP_LME2510,
}
};
static int __init init_rc_lme2510_map(void)
{
return ir_register_map(&lme2510_map);
}
static void __exit exit_rc_lme2510_map(void)
{
ir_unregister_map(&lme2510_map);
}
module_init(init_rc_lme2510_map)
module_exit(exit_rc_lme2510_map)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Malcolm Priestley [email protected]");

View file

@ -0,0 +1,67 @@
/*
* MSI DIGIVOX mini II remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
static struct ir_scancode msi_digivox_ii[] = {
{ 0x0002, KEY_2 },
{ 0x0003, KEY_UP }, /* up */
{ 0x0004, KEY_3 },
{ 0x0005, KEY_CHANNELDOWN },
{ 0x0008, KEY_5 },
{ 0x0009, KEY_0 },
{ 0x000b, KEY_8 },
{ 0x000d, KEY_DOWN }, /* down */
{ 0x0010, KEY_9 },
{ 0x0011, KEY_7 },
{ 0x0014, KEY_VOLUMEUP },
{ 0x0015, KEY_CHANNELUP },
{ 0x0016, KEY_OK },
{ 0x0017, KEY_POWER2 },
{ 0x001a, KEY_1 },
{ 0x001c, KEY_4 },
{ 0x001d, KEY_6 },
{ 0x001f, KEY_VOLUMEDOWN },
};
static struct rc_keymap msi_digivox_ii_map = {
.map = {
.scan = msi_digivox_ii,
.size = ARRAY_SIZE(msi_digivox_ii),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_MSI_DIGIVOX_II,
}
};
static int __init init_rc_map_msi_digivox_ii(void)
{
return ir_register_map(&msi_digivox_ii_map);
}
static void __exit exit_rc_map_msi_digivox_ii(void)
{
ir_unregister_map(&msi_digivox_ii_map);
}
module_init(init_rc_map_msi_digivox_ii)
module_exit(exit_rc_map_msi_digivox_ii)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,85 @@
/*
* MSI DIGIVOX mini III remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
/* MSI DIGIVOX mini III */
/* Uses NEC extended 0x61d6. */
/* This remote seems to be same as rc-kworld-315u.c. Anyhow, add new remote
since rc-kworld-315u.c lacks NEC extended address byte. */
static struct ir_scancode msi_digivox_iii[] = {
{ 0x61d601, KEY_VIDEO }, /* Source */
{ 0x61d602, KEY_3 },
{ 0x61d603, KEY_POWER }, /* ShutDown */
{ 0x61d604, KEY_1 },
{ 0x61d605, KEY_5 },
{ 0x61d606, KEY_6 },
{ 0x61d607, KEY_CHANNELDOWN }, /* CH- */
{ 0x61d608, KEY_2 },
{ 0x61d609, KEY_CHANNELUP }, /* CH+ */
{ 0x61d60a, KEY_9 },
{ 0x61d60b, KEY_ZOOM }, /* Zoom */
{ 0x61d60c, KEY_7 },
{ 0x61d60d, KEY_8 },
{ 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */
{ 0x61d60f, KEY_4 },
{ 0x61d610, KEY_ESC }, /* [back up arrow] */
{ 0x61d611, KEY_0 },
{ 0x61d612, KEY_OK }, /* [enter arrow] */
{ 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */
{ 0x61d614, KEY_RECORD }, /* Rec */
{ 0x61d615, KEY_STOP }, /* Stop */
{ 0x61d616, KEY_PLAY }, /* Play */
{ 0x61d617, KEY_MUTE }, /* Mute */
{ 0x61d618, KEY_UP },
{ 0x61d619, KEY_DOWN },
{ 0x61d61a, KEY_LEFT },
{ 0x61d61b, KEY_RIGHT },
{ 0x61d61c, KEY_RED },
{ 0x61d61d, KEY_GREEN },
{ 0x61d61e, KEY_YELLOW },
{ 0x61d61f, KEY_BLUE },
{ 0x61d643, KEY_POWER2 }, /* [red power button] */
};
static struct rc_keymap msi_digivox_iii_map = {
.map = {
.scan = msi_digivox_iii,
.size = ARRAY_SIZE(msi_digivox_iii),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_MSI_DIGIVOX_III,
}
};
static int __init init_rc_map_msi_digivox_iii(void)
{
return ir_register_map(&msi_digivox_iii_map);
}
static void __exit exit_rc_map_msi_digivox_iii(void)
{
ir_unregister_map(&msi_digivox_iii_map);
}
module_init(init_rc_map_msi_digivox_iii)
module_exit(exit_rc_map_msi_digivox_iii)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -1,81 +0,0 @@
/* rc-rc5-streamzap.c - Keytable for Streamzap PC Remote, for use
* with the Streamzap PC Remote IR Receiver.
*
* Copyright (c) 2010 by Jarod Wilson <jarod@redhat.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.
*/
#include <media/rc-map.h>
static struct ir_scancode rc5_streamzap[] = {
/*
* FIXME: The Streamzap remote isn't actually true RC-5, it has an extra
* bit in it, which presently throws the in-kernel RC-5 decoder for a loop.
* We either have to enhance the decoder to support it, add a new decoder,
* or just rely on lirc userspace decoding.
*/
{ 0x00, KEY_NUMERIC_0 },
{ 0x01, KEY_NUMERIC_1 },
{ 0x02, KEY_NUMERIC_2 },
{ 0x03, KEY_NUMERIC_3 },
{ 0x04, KEY_NUMERIC_4 },
{ 0x05, KEY_NUMERIC_5 },
{ 0x06, KEY_NUMERIC_6 },
{ 0x07, KEY_NUMERIC_7 },
{ 0x08, KEY_NUMERIC_8 },
{ 0x0a, KEY_POWER },
{ 0x0b, KEY_MUTE },
{ 0x0c, KEY_CHANNELUP },
{ 0x0d, KEY_VOLUMEUP },
{ 0x0e, KEY_CHANNELDOWN },
{ 0x0f, KEY_VOLUMEDOWN },
{ 0x10, KEY_UP },
{ 0x11, KEY_LEFT },
{ 0x12, KEY_OK },
{ 0x13, KEY_RIGHT },
{ 0x14, KEY_DOWN },
{ 0x15, KEY_MENU },
{ 0x16, KEY_EXIT },
{ 0x17, KEY_PLAY },
{ 0x18, KEY_PAUSE },
{ 0x19, KEY_STOP },
{ 0x1a, KEY_BACK },
{ 0x1b, KEY_FORWARD },
{ 0x1c, KEY_RECORD },
{ 0x1d, KEY_REWIND },
{ 0x1e, KEY_FASTFORWARD },
{ 0x20, KEY_RED },
{ 0x21, KEY_GREEN },
{ 0x22, KEY_YELLOW },
{ 0x23, KEY_BLUE },
};
static struct rc_keymap rc5_streamzap_map = {
.map = {
.scan = rc5_streamzap,
.size = ARRAY_SIZE(rc5_streamzap),
.ir_type = IR_TYPE_RC5,
.name = RC_MAP_RC5_STREAMZAP,
}
};
static int __init init_rc_map_rc5_streamzap(void)
{
return ir_register_map(&rc5_streamzap_map);
}
static void __exit exit_rc_map_rc5_streamzap(void)
{
ir_unregister_map(&rc5_streamzap_map);
}
module_init(init_rc_map_rc5_streamzap)
module_exit(exit_rc_map_rc5_streamzap)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jarod Wilson <[email protected]>");

View file

@ -12,35 +12,8 @@
#include <media/rc-map.h>
static struct ir_scancode rc6_mce[] = {
{ 0x800f0415, KEY_REWIND },
{ 0x800f0414, KEY_FASTFORWARD },
{ 0x800f041b, KEY_PREVIOUS },
{ 0x800f041a, KEY_NEXT },
{ 0x800f0416, KEY_PLAY },
{ 0x800f0418, KEY_PAUSE },
{ 0x800f046e, KEY_PLAYPAUSE },
{ 0x800f0419, KEY_STOP },
{ 0x800f0417, KEY_RECORD },
{ 0x800f041e, KEY_UP },
{ 0x800f041f, KEY_DOWN },
{ 0x800f0420, KEY_LEFT },
{ 0x800f0421, KEY_RIGHT },
{ 0x800f040b, KEY_ENTER },
{ 0x800f0422, KEY_OK },
{ 0x800f0423, KEY_EXIT },
{ 0x800f040a, KEY_DELETE },
{ 0x800f040e, KEY_MUTE },
{ 0x800f0410, KEY_VOLUMEUP },
{ 0x800f0411, KEY_VOLUMEDOWN },
{ 0x800f0412, KEY_CHANNELUP },
{ 0x800f0413, KEY_CHANNELDOWN },
{ 0x800f043a, KEY_BRIGHTNESSUP },
{ 0x800f0480, KEY_BRIGHTNESSDOWN },
{ 0x800f0400, KEY_NUMERIC_0 },
{ 0x800f0401, KEY_NUMERIC_1 },
{ 0x800f0402, KEY_NUMERIC_2 },
{ 0x800f0403, KEY_NUMERIC_3 },
@ -50,38 +23,67 @@ static struct ir_scancode rc6_mce[] = {
{ 0x800f0407, KEY_NUMERIC_7 },
{ 0x800f0408, KEY_NUMERIC_8 },
{ 0x800f0409, KEY_NUMERIC_9 },
{ 0x800f0400, KEY_NUMERIC_0 },
{ 0x800f041d, KEY_NUMERIC_STAR },
{ 0x800f040a, KEY_DELETE },
{ 0x800f040b, KEY_ENTER },
{ 0x800f040c, KEY_POWER },
{ 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
{ 0x800f040e, KEY_MUTE },
{ 0x800f040f, KEY_INFO },
{ 0x800f0410, KEY_VOLUMEUP },
{ 0x800f0411, KEY_VOLUMEDOWN },
{ 0x800f0412, KEY_CHANNELUP },
{ 0x800f0413, KEY_CHANNELDOWN },
{ 0x800f0414, KEY_FASTFORWARD },
{ 0x800f0415, KEY_REWIND },
{ 0x800f0416, KEY_PLAY },
{ 0x800f0417, KEY_RECORD },
{ 0x800f0418, KEY_PAUSE },
{ 0x800f046e, KEY_PLAYPAUSE },
{ 0x800f0419, KEY_STOP },
{ 0x800f041a, KEY_NEXT },
{ 0x800f041b, KEY_PREVIOUS },
{ 0x800f041c, KEY_NUMERIC_POUND },
{ 0x800f041d, KEY_NUMERIC_STAR },
{ 0x800f041e, KEY_UP },
{ 0x800f041f, KEY_DOWN },
{ 0x800f0420, KEY_LEFT },
{ 0x800f0421, KEY_RIGHT },
{ 0x800f0422, KEY_OK },
{ 0x800f0423, KEY_EXIT },
{ 0x800f0424, KEY_DVD },
{ 0x800f0425, KEY_TUNER }, /* LiveTV */
{ 0x800f0426, KEY_EPG }, /* Guide */
{ 0x800f0427, KEY_ZOOM }, /* Aspect */
{ 0x800f043a, KEY_BRIGHTNESSUP },
{ 0x800f0446, KEY_TV },
{ 0x800f0447, KEY_AUDIO }, /* My Music */
{ 0x800f0448, KEY_PVR }, /* RecordedTV */
{ 0x800f0447, KEY_AUDIO }, /* My Music */
{ 0x800f0448, KEY_PVR }, /* RecordedTV */
{ 0x800f0449, KEY_CAMERA },
{ 0x800f044a, KEY_VIDEO },
{ 0x800f0424, KEY_DVD },
{ 0x800f0425, KEY_TUNER }, /* LiveTV */
{ 0x800f044c, KEY_LANGUAGE },
{ 0x800f044d, KEY_TITLE },
{ 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
{ 0x800f0450, KEY_RADIO },
{ 0x800f044c, KEY_LANGUAGE },
{ 0x800f0427, KEY_ZOOM }, /* Aspect */
{ 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
{ 0x800f045b, KEY_RED },
{ 0x800f045c, KEY_GREEN },
{ 0x800f045d, KEY_YELLOW },
{ 0x800f045e, KEY_BLUE },
{ 0x800f040f, KEY_INFO },
{ 0x800f0426, KEY_EPG }, /* Guide */
{ 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
{ 0x800f044d, KEY_TITLE },
{ 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
{ 0x800f040c, KEY_POWER },
{ 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
{ 0x800f046e, KEY_PLAYPAUSE },
{ 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */
{ 0x800f0480, KEY_BRIGHTNESSDOWN },
{ 0x800f0481, KEY_PLAYPAUSE },
};
static struct rc_keymap rc6_mce_map = {

View file

@ -0,0 +1,82 @@
/* rc-streamzap.c - Keytable for Streamzap PC Remote, for use
* with the Streamzap PC Remote IR Receiver.
*
* Copyright (c) 2010 by Jarod Wilson <jarod@redhat.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.
*/
#include <media/rc-map.h>
static struct ir_scancode streamzap[] = {
/*
* The Streamzap remote is almost, but not quite, RC-5, as it has an extra
* bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently,
* an additional RC-5-sz decoder is being deployed to support it, but it
* may be possible to merge it back with the standard RC-5 decoder.
*/
{ 0x28c0, KEY_NUMERIC_0 },
{ 0x28c1, KEY_NUMERIC_1 },
{ 0x28c2, KEY_NUMERIC_2 },
{ 0x28c3, KEY_NUMERIC_3 },
{ 0x28c4, KEY_NUMERIC_4 },
{ 0x28c5, KEY_NUMERIC_5 },
{ 0x28c6, KEY_NUMERIC_6 },
{ 0x28c7, KEY_NUMERIC_7 },
{ 0x28c8, KEY_NUMERIC_8 },
{ 0x28c9, KEY_NUMERIC_9 },
{ 0x28ca, KEY_POWER },
{ 0x28cb, KEY_MUTE },
{ 0x28cc, KEY_CHANNELUP },
{ 0x28cd, KEY_VOLUMEUP },
{ 0x28ce, KEY_CHANNELDOWN },
{ 0x28cf, KEY_VOLUMEDOWN },
{ 0x28d0, KEY_UP },
{ 0x28d1, KEY_LEFT },
{ 0x28d2, KEY_OK },
{ 0x28d3, KEY_RIGHT },
{ 0x28d4, KEY_DOWN },
{ 0x28d5, KEY_MENU },
{ 0x28d6, KEY_EXIT },
{ 0x28d7, KEY_PLAY },
{ 0x28d8, KEY_PAUSE },
{ 0x28d9, KEY_STOP },
{ 0x28da, KEY_BACK },
{ 0x28db, KEY_FORWARD },
{ 0x28dc, KEY_RECORD },
{ 0x28dd, KEY_REWIND },
{ 0x28de, KEY_FASTFORWARD },
{ 0x28e0, KEY_RED },
{ 0x28e1, KEY_GREEN },
{ 0x28e2, KEY_YELLOW },
{ 0x28e3, KEY_BLUE },
};
static struct rc_keymap streamzap_map = {
.map = {
.scan = streamzap,
.size = ARRAY_SIZE(streamzap),
.ir_type = IR_TYPE_RC5_SZ,
.name = RC_MAP_STREAMZAP,
}
};
static int __init init_rc_map_streamzap(void)
{
return ir_register_map(&streamzap_map);
}
static void __exit exit_rc_map_streamzap(void)
{
ir_unregister_map(&streamzap_map);
}
module_init(init_rc_map_streamzap)
module_exit(exit_rc_map_streamzap)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jarod Wilson <[email protected]>");

View file

@ -0,0 +1,79 @@
/*
* TerraTec remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
/* TerraTec slim remote, 7 rows, 4 columns. */
/* Uses NEC extended 0x02bd. */
static struct ir_scancode terratec_slim[] = {
{ 0x02bd00, KEY_1 },
{ 0x02bd01, KEY_2 },
{ 0x02bd02, KEY_3 },
{ 0x02bd03, KEY_4 },
{ 0x02bd04, KEY_5 },
{ 0x02bd05, KEY_6 },
{ 0x02bd06, KEY_7 },
{ 0x02bd07, KEY_8 },
{ 0x02bd08, KEY_9 },
{ 0x02bd09, KEY_0 },
{ 0x02bd0a, KEY_MUTE },
{ 0x02bd0b, KEY_NEW }, /* symbol: PIP */
{ 0x02bd0e, KEY_VOLUMEDOWN },
{ 0x02bd0f, KEY_PLAYPAUSE },
{ 0x02bd10, KEY_RIGHT },
{ 0x02bd11, KEY_LEFT },
{ 0x02bd12, KEY_UP },
{ 0x02bd13, KEY_DOWN },
{ 0x02bd15, KEY_OK },
{ 0x02bd16, KEY_STOP },
{ 0x02bd17, KEY_CAMERA }, /* snapshot */
{ 0x02bd18, KEY_CHANNELUP },
{ 0x02bd19, KEY_RECORD },
{ 0x02bd1a, KEY_CHANNELDOWN },
{ 0x02bd1c, KEY_ESC },
{ 0x02bd1f, KEY_VOLUMEUP },
{ 0x02bd44, KEY_EPG },
{ 0x02bd45, KEY_POWER2 }, /* [red power button] */
};
static struct rc_keymap terratec_slim_map = {
.map = {
.scan = terratec_slim,
.size = ARRAY_SIZE(terratec_slim),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_TERRATEC_SLIM,
}
};
static int __init init_rc_map_terratec_slim(void)
{
return ir_register_map(&terratec_slim_map);
}
static void __exit exit_rc_map_terratec_slim(void)
{
ir_unregister_map(&terratec_slim_map);
}
module_init(init_rc_map_terratec_slim)
module_exit(exit_rc_map_terratec_slim)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,85 @@
/*
* Total Media In Hand remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
/* Uses NEC extended 0x02bd */
static struct ir_scancode total_media_in_hand[] = {
{ 0x02bd00, KEY_1 },
{ 0x02bd01, KEY_2 },
{ 0x02bd02, KEY_3 },
{ 0x02bd03, KEY_4 },
{ 0x02bd04, KEY_5 },
{ 0x02bd05, KEY_6 },
{ 0x02bd06, KEY_7 },
{ 0x02bd07, KEY_8 },
{ 0x02bd08, KEY_9 },
{ 0x02bd09, KEY_0 },
{ 0x02bd0a, KEY_MUTE },
{ 0x02bd0b, KEY_CYCLEWINDOWS }, /* yellow, [min / max] */
{ 0x02bd0c, KEY_VIDEO }, /* TV / AV */
{ 0x02bd0e, KEY_VOLUMEDOWN },
{ 0x02bd0f, KEY_TIME }, /* TimeShift */
{ 0x02bd10, KEY_RIGHT }, /* right arrow */
{ 0x02bd11, KEY_LEFT }, /* left arrow */
{ 0x02bd12, KEY_UP }, /* up arrow */
{ 0x02bd13, KEY_DOWN }, /* down arrow */
{ 0x02bd14, KEY_POWER2 }, /* [red] */
{ 0x02bd15, KEY_OK }, /* OK */
{ 0x02bd16, KEY_STOP },
{ 0x02bd17, KEY_CAMERA }, /* Snapshot */
{ 0x02bd18, KEY_CHANNELUP },
{ 0x02bd19, KEY_RECORD },
{ 0x02bd1a, KEY_CHANNELDOWN },
{ 0x02bd1c, KEY_ESC }, /* Esc */
{ 0x02bd1e, KEY_PLAY },
{ 0x02bd1f, KEY_VOLUMEUP },
{ 0x02bd40, KEY_PAUSE },
{ 0x02bd41, KEY_FASTFORWARD }, /* FF >> */
{ 0x02bd42, KEY_REWIND }, /* FR << */
{ 0x02bd43, KEY_ZOOM }, /* [window + mouse pointer] */
{ 0x02bd44, KEY_SHUFFLE }, /* Shuffle */
{ 0x02bd45, KEY_INFO }, /* [red (I)] */
};
static struct rc_keymap total_media_in_hand_map = {
.map = {
.scan = total_media_in_hand,
.size = ARRAY_SIZE(total_media_in_hand),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_TOTAL_MEDIA_IN_HAND,
}
};
static int __init init_rc_map_total_media_in_hand(void)
{
return ir_register_map(&total_media_in_hand_map);
}
static void __exit exit_rc_map_total_media_in_hand(void)
{
ir_unregister_map(&total_media_in_hand_map);
}
module_init(init_rc_map_total_media_in_hand)
module_exit(exit_rc_map_total_media_in_hand)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,80 @@
/*
* TrekStor remote controller keytable
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <media/rc-map.h>
/* TrekStor DVB-T USB Stick remote controller. */
/* Imported from af9015.h.
Initial keytable was from Marc Schneider <macke@macke.org> */
static struct ir_scancode trekstor[] = {
{ 0x0084, KEY_0 },
{ 0x0085, KEY_MUTE }, /* Mute */
{ 0x0086, KEY_HOMEPAGE }, /* Home */
{ 0x0087, KEY_UP }, /* Up */
{ 0x0088, KEY_OK }, /* OK */
{ 0x0089, KEY_RIGHT }, /* Right */
{ 0x008a, KEY_FASTFORWARD }, /* Fast forward */
{ 0x008b, KEY_VOLUMEUP }, /* Volume + */
{ 0x008c, KEY_DOWN }, /* Down */
{ 0x008d, KEY_PLAY }, /* Play/Pause */
{ 0x008e, KEY_STOP }, /* Stop */
{ 0x008f, KEY_EPG }, /* Info/EPG */
{ 0x0090, KEY_7 },
{ 0x0091, KEY_4 },
{ 0x0092, KEY_1 },
{ 0x0093, KEY_CHANNELDOWN }, /* Channel - */
{ 0x0094, KEY_8 },
{ 0x0095, KEY_5 },
{ 0x0096, KEY_2 },
{ 0x0097, KEY_CHANNELUP }, /* Channel + */
{ 0x0098, KEY_9 },
{ 0x0099, KEY_6 },
{ 0x009a, KEY_3 },
{ 0x009b, KEY_VOLUMEDOWN }, /* Volume - */
{ 0x009c, KEY_TV }, /* TV */
{ 0x009d, KEY_RECORD }, /* Record */
{ 0x009e, KEY_REWIND }, /* Rewind */
{ 0x009f, KEY_LEFT }, /* Left */
};
static struct rc_keymap trekstor_map = {
.map = {
.scan = trekstor,
.size = ARRAY_SIZE(trekstor),
.ir_type = IR_TYPE_NEC,
.name = RC_MAP_TREKSTOR,
}
};
static int __init init_rc_map_trekstor(void)
{
return ir_register_map(&trekstor_map);
}
static void __exit exit_rc_map_trekstor(void)
{
ir_unregister_map(&trekstor_map);
}
module_init(init_rc_map_trekstor)
module_exit(exit_rc_map_trekstor)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");

View file

@ -0,0 +1,87 @@
#include <media/rc-map.h>
static struct ir_scancode twinhan_vp1027[] = {
{ 0x16, KEY_POWER2 },
{ 0x17, KEY_FAVORITES },
{ 0x0f, KEY_TEXT },
{ 0x48, KEY_INFO},
{ 0x1c, KEY_EPG },
{ 0x04, KEY_LIST },
{ 0x03, KEY_1 },
{ 0x01, KEY_2 },
{ 0x06, KEY_3 },
{ 0x09, KEY_4 },
{ 0x1d, KEY_5 },
{ 0x1f, KEY_6 },
{ 0x0d, KEY_7 },
{ 0x19, KEY_8 },
{ 0x1b, KEY_9 },
{ 0x15, KEY_0 },
{ 0x0c, KEY_CANCEL },
{ 0x4a, KEY_CLEAR },
{ 0x13, KEY_BACKSPACE },
{ 0x00, KEY_TAB },
{ 0x4b, KEY_UP },
{ 0x51, KEY_DOWN },
{ 0x4e, KEY_LEFT },
{ 0x52, KEY_RIGHT },
{ 0x4f, KEY_ENTER },
{ 0x1e, KEY_VOLUMEUP },
{ 0x0a, KEY_VOLUMEDOWN },
{ 0x02, KEY_CHANNELDOWN },
{ 0x05, KEY_CHANNELUP },
{ 0x11, KEY_RECORD },
{ 0x14, KEY_PLAY },
{ 0x4c, KEY_PAUSE },
{ 0x1a, KEY_STOP },
{ 0x40, KEY_REWIND },
{ 0x12, KEY_FASTFORWARD },
{ 0x41, KEY_PREVIOUSSONG },
{ 0x42, KEY_NEXTSONG },
{ 0x54, KEY_SAVE },
{ 0x50, KEY_LANGUAGE },
{ 0x47, KEY_MEDIA },
{ 0x4d, KEY_SCREEN },
{ 0x43, KEY_SUBTITLE },
{ 0x10, KEY_MUTE },
{ 0x49, KEY_AUDIO },
{ 0x07, KEY_SLEEP },
{ 0x08, KEY_VIDEO },
{ 0x0e, KEY_AGAIN },
{ 0x45, KEY_EQUAL },
{ 0x46, KEY_MINUS },
{ 0x18, KEY_RED },
{ 0x53, KEY_GREEN },
{ 0x5e, KEY_YELLOW },
{ 0x5f, KEY_BLUE },
};
static struct rc_keymap twinhan_vp1027_map = {
.map = {
.scan = twinhan_vp1027,
.size = ARRAY_SIZE(twinhan_vp1027),
.ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_TWINHAN_VP1027_DVBS,
}
};
static int __init init_rc_map_twinhan_vp1027(void)
{
return ir_register_map(&twinhan_vp1027_map);
}
static void __exit exit_rc_map_twinhan_vp1027(void)
{
ir_unregister_map(&twinhan_vp1027_map);
}
module_init(init_rc_map_twinhan_vp1027)
module_exit(exit_rc_map_twinhan_vp1027)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sergey Ivanov <[email protected]>");

View file

@ -57,13 +57,12 @@ struct irctl {
struct task_struct *task;
long jiffies_to_wait;
struct cdev cdev;
};
static DEFINE_MUTEX(lirc_dev_lock);
static struct irctl *irctls[MAX_IRCTL_DEVICES];
static struct cdev cdevs[MAX_IRCTL_DEVICES];
/* Only used for sysfs but defined to void otherwise */
static struct class *lirc_class;
@ -71,15 +70,13 @@ static struct class *lirc_class;
/* helper function
* initializes the irctl structure
*/
static void init_irctl(struct irctl *ir)
static void lirc_irctl_init(struct irctl *ir)
{
dev_dbg(ir->d.dev, LOGHEAD "initializing irctl\n",
ir->d.name, ir->d.minor);
mutex_init(&ir->irctl_lock);
ir->d.minor = NOPLUG;
}
static void cleanup(struct irctl *ir)
static void lirc_irctl_cleanup(struct irctl *ir)
{
dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
@ -96,7 +93,7 @@ static void cleanup(struct irctl *ir)
* reads key codes from driver and puts them into buffer
* returns 0 on success
*/
static int add_to_buf(struct irctl *ir)
static int lirc_add_to_buf(struct irctl *ir)
{
if (ir->d.add_to_buf) {
int res = -ENODATA;
@ -139,7 +136,7 @@ static int lirc_thread(void *irctl)
}
if (kthread_should_stop())
break;
if (!add_to_buf(ir))
if (!lirc_add_to_buf(ir))
wake_up_interruptible(&ir->buf->wait_poll);
} else {
set_current_state(TASK_INTERRUPTIBLE);
@ -154,12 +151,15 @@ static int lirc_thread(void *irctl)
}
static struct file_operations fops = {
static struct file_operations lirc_dev_fops = {
.owner = THIS_MODULE,
.read = lirc_dev_fop_read,
.write = lirc_dev_fop_write,
.poll = lirc_dev_fop_poll,
.unlocked_ioctl = lirc_dev_fop_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = lirc_dev_fop_ioctl,
#endif
.open = lirc_dev_fop_open,
.release = lirc_dev_fop_close,
.llseek = noop_llseek,
@ -169,19 +169,20 @@ static int lirc_cdev_add(struct irctl *ir)
{
int retval;
struct lirc_driver *d = &ir->d;
struct cdev *cdev = &cdevs[d->minor];
if (d->fops) {
cdev_init(&ir->cdev, d->fops);
ir->cdev.owner = d->owner;
cdev_init(cdev, d->fops);
cdev->owner = d->owner;
} else {
cdev_init(&ir->cdev, &fops);
ir->cdev.owner = THIS_MODULE;
cdev_init(cdev, &lirc_dev_fops);
cdev->owner = THIS_MODULE;
}
kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor);
kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
if (retval)
kobject_put(&ir->cdev.kobj);
kobject_put(&cdev->kobj);
return retval;
}
@ -202,6 +203,12 @@ int lirc_register_driver(struct lirc_driver *d)
goto out;
}
if (!d->dev) {
printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__);
err = -EINVAL;
goto out;
}
if (MAX_IRCTL_DEVICES <= d->minor) {
dev_err(d->dev, "lirc_dev: lirc_register_driver: "
"\"minor\" must be between 0 and %d (%d)!\n",
@ -277,7 +284,7 @@ int lirc_register_driver(struct lirc_driver *d)
err = -ENOMEM;
goto out_lock;
}
init_irctl(ir);
lirc_irctl_init(ir);
irctls[minor] = ir;
d->minor = minor;
@ -316,7 +323,6 @@ int lirc_register_driver(struct lirc_driver *d)
d->features = LIRC_CAN_REC_LIRCCODE;
ir->d = *d;
ir->d.minor = minor;
device_create(lirc_class, ir->d.dev,
MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
@ -357,21 +363,28 @@ EXPORT_SYMBOL(lirc_register_driver);
int lirc_unregister_driver(int minor)
{
struct irctl *ir;
struct cdev *cdev;
if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
"\"minor (%d)\" must be between 0 and %d!\n",
minor, MAX_IRCTL_DEVICES-1);
printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
"0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1);
return -EBADRQC;
}
ir = irctls[minor];
if (!ir) {
printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct "
"for minor %d!\n", __func__, minor);
return -ENOENT;
}
cdev = &cdevs[minor];
mutex_lock(&lirc_dev_lock);
if (ir->d.minor != minor) {
printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
"minor (%d) device not registered!", minor);
printk(KERN_ERR "lirc_dev: %s: minor (%d) device not "
"registered!\n", __func__, minor);
mutex_unlock(&lirc_dev_lock);
return -ENOENT;
}
@ -390,12 +403,11 @@ int lirc_unregister_driver(int minor)
wake_up_interruptible(&ir->buf->wait_poll);
mutex_lock(&ir->irctl_lock);
ir->d.set_use_dec(ir->d.data);
module_put(ir->d.owner);
module_put(cdev->owner);
mutex_unlock(&ir->irctl_lock);
cdev_del(&ir->cdev);
} else {
cleanup(ir);
cdev_del(&ir->cdev);
lirc_irctl_cleanup(ir);
cdev_del(cdev);
kfree(ir);
irctls[minor] = NULL;
}
@ -409,6 +421,7 @@ EXPORT_SYMBOL(lirc_unregister_driver);
int lirc_dev_fop_open(struct inode *inode, struct file *file)
{
struct irctl *ir;
struct cdev *cdev;
int retval = 0;
if (iminor(inode) >= MAX_IRCTL_DEVICES) {
@ -425,7 +438,6 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
retval = -ENODEV;
goto error;
}
file->private_data = ir;
dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
@ -439,13 +451,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
goto error;
}
if (try_module_get(ir->d.owner)) {
++ir->open;
cdev = &cdevs[iminor(inode)];
if (try_module_get(cdev->owner)) {
ir->open++;
retval = ir->d.set_use_inc(ir->d.data);
if (retval) {
module_put(ir->d.owner);
--ir->open;
module_put(cdev->owner);
ir->open--;
} else {
lirc_buffer_clear(ir->buf);
}
@ -469,17 +482,24 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
int lirc_dev_fop_close(struct inode *inode, struct file *file)
{
struct irctl *ir = irctls[iminor(inode)];
struct cdev *cdev = &cdevs[iminor(inode)];
if (!ir) {
printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
return -EINVAL;
}
dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
WARN_ON(mutex_lock_killable(&lirc_dev_lock));
--ir->open;
ir->open--;
if (ir->attached) {
ir->d.set_use_dec(ir->d.data);
module_put(ir->d.owner);
module_put(cdev->owner);
} else {
cleanup(ir);
lirc_irctl_cleanup(ir);
cdev_del(cdev);
irctls[ir->d.minor] = NULL;
kfree(ir);
}
@ -495,6 +515,11 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
unsigned int ret;
if (!ir) {
printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
return POLLERR;
}
dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
if (!ir->attached) {
@ -521,9 +546,14 @@ EXPORT_SYMBOL(lirc_dev_fop_poll);
long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned long mode;
__u32 mode;
int result = 0;
struct irctl *ir = file->private_data;
struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
if (!ir) {
printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__);
return -ENODEV;
}
dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
ir->d.name, ir->d.minor, cmd);
@ -538,7 +568,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
case LIRC_GET_FEATURES:
result = put_user(ir->d.features, (unsigned long *)arg);
result = put_user(ir->d.features, (__u32 *)arg);
break;
case LIRC_GET_REC_MODE:
if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@ -548,7 +578,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
result = put_user(LIRC_REC2MODE
(ir->d.features & LIRC_CAN_REC_MASK),
(unsigned long *)arg);
(__u32 *)arg);
break;
case LIRC_SET_REC_MODE:
if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@ -556,7 +586,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
result = get_user(mode, (unsigned long *)arg);
result = get_user(mode, (__u32 *)arg);
if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
result = -EINVAL;
/*
@ -565,7 +595,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
*/
break;
case LIRC_GET_LENGTH:
result = put_user(ir->d.code_length, (unsigned long *)arg);
result = put_user(ir->d.code_length, (__u32 *)arg);
break;
case LIRC_GET_MIN_TIMEOUT:
if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@ -574,7 +604,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
result = put_user(ir->d.min_timeout, (unsigned long *)arg);
result = put_user(ir->d.min_timeout, (__u32 *)arg);
break;
case LIRC_GET_MAX_TIMEOUT:
if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@ -583,7 +613,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
result = put_user(ir->d.max_timeout, (unsigned long *)arg);
result = put_user(ir->d.max_timeout, (__u32 *)arg);
break;
default:
result = -EINVAL;
@ -604,12 +634,21 @@ ssize_t lirc_dev_fop_read(struct file *file,
loff_t *ppos)
{
struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
unsigned char buf[ir->chunk_size];
unsigned char *buf;
int ret = 0, written = 0;
DECLARE_WAITQUEUE(wait, current);
if (!ir) {
printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
return -ENODEV;
}
dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
buf = kzalloc(ir->chunk_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (mutex_lock_interruptible(&ir->irctl_lock))
return -ERESTARTSYS;
if (!ir->attached) {
@ -681,6 +720,7 @@ ssize_t lirc_dev_fop_read(struct file *file,
mutex_unlock(&ir->irctl_lock);
out_unlocked:
kfree(buf);
dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
@ -709,6 +749,11 @@ ssize_t lirc_dev_fop_write(struct file *file, const char *buffer,
{
struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
if (!ir) {
printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
return -ENODEV;
}
dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
if (!ir->attached)

View file

@ -46,24 +46,58 @@
"device driver"
#define DRIVER_NAME "mceusb"
#define USB_BUFLEN 32 /* USB reception buffer length */
#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
#define USB_BUFLEN 32 /* USB reception buffer length */
#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
/* MCE constants */
#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
#define MCE_TIME_UNIT 50 /* Approx 50us resolution */
#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */
#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */
#define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
#define MCE_CONTROL_HEADER 0x9F /* MCE status header */
#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
#define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */
#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */
#define MCE_PULSE_MASK 0x7F /* Pulse mask */
#define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */
#define MCE_PACKET_LENGTH_MASK 0x1F /* Packet length mask */
#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
#define MCE_TIME_UNIT 50 /* Approx 50us resolution */
#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */
#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */
#define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
#define MCE_IRDATA_TRAILER 0x80 /* End of IR data */
#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
#define MCE_DEFAULT_TX_MASK 0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */
#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */
#define MCE_PULSE_MASK 0x7f /* Pulse mask */
#define MCE_MAX_PULSE_LENGTH 0x7f /* Longest transmittable pulse symbol */
#define MCE_HW_CMD_HEADER 0xff /* MCE hardware command header */
#define MCE_COMMAND_HEADER 0x9f /* MCE command header */
#define MCE_COMMAND_MASK 0xe0 /* Mask out command bits */
#define MCE_COMMAND_NULL 0x00 /* These show up various places... */
/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER,
* then we're looking at a raw IR data sample */
#define MCE_COMMAND_IRDATA 0x80
#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
#define MCE_CMD_PING 0x03 /* Ping device */
#define MCE_CMD_UNKNOWN 0x04 /* Unknown */
#define MCE_CMD_UNKNOWN2 0x05 /* Unknown */
#define MCE_CMD_S_CARRIER 0x06 /* Set TX carrier frequency */
#define MCE_CMD_G_CARRIER 0x07 /* Get TX carrier frequency */
#define MCE_CMD_S_TXMASK 0x08 /* Set TX port bitmask */
#define MCE_CMD_UNKNOWN3 0x09 /* Unknown */
#define MCE_CMD_UNKNOWN4 0x0a /* Unknown */
#define MCE_CMD_G_REVISION 0x0b /* Get hw/sw revision */
#define MCE_CMD_S_TIMEOUT 0x0c /* Set RX timeout value */
#define MCE_CMD_G_TIMEOUT 0x0d /* Get RX timeout value */
#define MCE_CMD_UNKNOWN5 0x0e /* Unknown */
#define MCE_CMD_UNKNOWN6 0x0f /* Unknown */
#define MCE_CMD_G_RXPORTSTS 0x11 /* Get RX port status */
#define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */
#define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */
#define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */
#define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */
#define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */
#define MCE_CMD_UNKNOWN7 0x18 /* Unknown */
#define MCE_CMD_UNKNOWN8 0x19 /* Unknown */
#define MCE_CMD_UNKNOWN9 0x1b /* Unknown */
#define MCE_CMD_DEVICE_RESET 0xaa /* Reset the hardware */
#define MCE_RSP_CMD_INVALID 0xfe /* Invalid command issued */
/* module parameters */
@ -104,14 +138,64 @@ static int debug;
#define VENDOR_NORTHSTAR 0x04eb
#define VENDOR_REALTEK 0x0bda
#define VENDOR_TIVO 0x105a
#define VENDOR_CONEXANT 0x0572
enum mceusb_model_type {
MCE_GEN2 = 0, /* Most boards */
MCE_GEN1,
MCE_GEN3,
MCE_GEN2_TX_INV,
POLARIS_EVK,
};
struct mceusb_model {
u32 mce_gen1:1;
u32 mce_gen2:1;
u32 mce_gen3:1;
u32 tx_mask_inverted:1;
u32 is_polaris:1;
const char *rc_map; /* Allow specify a per-board map */
const char *name; /* per-board name */
};
static const struct mceusb_model mceusb_model[] = {
[MCE_GEN1] = {
.mce_gen1 = 1,
.tx_mask_inverted = 1,
},
[MCE_GEN2] = {
.mce_gen2 = 1,
},
[MCE_GEN2_TX_INV] = {
.mce_gen2 = 1,
.tx_mask_inverted = 1,
},
[MCE_GEN3] = {
.mce_gen3 = 1,
.tx_mask_inverted = 1,
},
[POLARIS_EVK] = {
.is_polaris = 1,
/*
* In fact, the EVK is shipped without
* remotes, but we should have something handy,
* to allow testing it
*/
.rc_map = RC_MAP_RC5_HAUPPAUGE_NEW,
.name = "cx231xx MCE IR",
},
};
static struct usb_device_id mceusb_dev_table[] = {
/* Original Microsoft MCE IR Transceiver (often HP-branded) */
{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d),
.driver_info = MCE_GEN1 },
/* Philips Infrared Transceiver - Sahara branded */
{ USB_DEVICE(VENDOR_PHILIPS, 0x0608) },
/* Philips Infrared Transceiver - HP branded */
{ USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
{ USB_DEVICE(VENDOR_PHILIPS, 0x060c),
.driver_info = MCE_GEN2_TX_INV },
/* Philips SRM5100 */
{ USB_DEVICE(VENDOR_PHILIPS, 0x060d) },
/* Philips Infrared Transceiver - Omaura */
@ -127,11 +211,14 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Realtek MCE IR Receiver */
{ USB_DEVICE(VENDOR_REALTEK, 0x0161) },
/* SMK/Toshiba G83C0004D410 */
{ USB_DEVICE(VENDOR_SMK, 0x031d) },
{ USB_DEVICE(VENDOR_SMK, 0x031d),
.driver_info = MCE_GEN2_TX_INV },
/* SMK eHome Infrared Transceiver (Sony VAIO) */
{ USB_DEVICE(VENDOR_SMK, 0x0322) },
{ USB_DEVICE(VENDOR_SMK, 0x0322),
.driver_info = MCE_GEN2_TX_INV },
/* bundled with Hauppauge PVR-150 */
{ USB_DEVICE(VENDOR_SMK, 0x0334) },
{ USB_DEVICE(VENDOR_SMK, 0x0334),
.driver_info = MCE_GEN2_TX_INV },
/* SMK eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_SMK, 0x0338) },
/* Tatung eHome Infrared Transceiver */
@ -145,17 +232,23 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Mitsumi */
{ USB_DEVICE(VENDOR_MITSUMI, 0x2501) },
/* Topseed eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0001),
.driver_info = MCE_GEN2_TX_INV },
/* Topseed HP eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0006),
.driver_info = MCE_GEN2_TX_INV },
/* Topseed eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0007),
.driver_info = MCE_GEN2_TX_INV },
/* Topseed eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0008),
.driver_info = MCE_GEN3 },
/* Topseed eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x000a),
.driver_info = MCE_GEN2_TX_INV },
/* Topseed eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0011),
.driver_info = MCE_GEN2_TX_INV },
/* Ricavision internal Infrared Transceiver */
{ USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
/* Itron ione Libra Q-11 */
@ -185,7 +278,8 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
{ USB_DEVICE(VENDOR_FINTEK, 0x0702) },
/* Pinnacle Remote Kit */
{ USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
{ USB_DEVICE(VENDOR_PINNACLE, 0x0225),
.driver_info = MCE_GEN3 },
/* Elitegroup Computer Systems IR */
{ USB_DEVICE(VENDOR_ECS, 0x0f38) },
/* Wistron Corp. eHome Infrared Receiver */
@ -198,37 +292,13 @@ static struct usb_device_id mceusb_dev_table[] = {
{ USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
/* TiVo PC IR Receiver */
{ USB_DEVICE(VENDOR_TIVO, 0x2000) },
/* Conexant SDK */
{ USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
.driver_info = POLARIS_EVK },
/* Terminating entry */
{ }
};
static struct usb_device_id gen3_list[] = {
{ USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
{}
};
static struct usb_device_id microsoft_gen1_list[] = {
{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
{}
};
static struct usb_device_id std_tx_mask_list[] = {
{ USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
{ USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
{ USB_DEVICE(VENDOR_SMK, 0x031d) },
{ USB_DEVICE(VENDOR_SMK, 0x0322) },
{ USB_DEVICE(VENDOR_SMK, 0x0334) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
{ USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
{ USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
{}
};
/* data structure for each usb transceiver */
struct mceusb_dev {
/* ir-core bits */
@ -248,8 +318,15 @@ struct mceusb_dev {
/* buffers and dma */
unsigned char *buf_in;
unsigned int len_in;
u8 cmd; /* MCE command type */
u8 rem; /* Remaining IR data bytes in packet */
enum {
CMD_HEADER = 0,
SUBCMD,
CMD_DATA,
PARSE_IRDATA,
} parser_state;
u8 cmd, rem; /* Remaining IR data bytes in packet */
dma_addr_t dma_in;
dma_addr_t dma_out;
@ -257,7 +334,6 @@ struct mceusb_dev {
u32 connected:1;
u32 tx_mask_inverted:1;
u32 microsoft_gen1:1;
u32 reserved:29;
} flags;
/* transmit support */
@ -267,6 +343,7 @@ struct mceusb_dev {
char name[128];
char phys[64];
enum mceusb_model_type model;
};
/*
@ -291,43 +368,81 @@ struct mceusb_dev {
* - SET_RX_TIMEOUT sets the receiver timeout
* - SET_RX_SENSOR sets which receiver sensor to use
*/
static char DEVICE_RESET[] = {0x00, 0xff, 0xaa};
static char GET_REVISION[] = {0xff, 0x0b};
static char GET_UNKNOWN[] = {0xff, 0x18};
static char GET_UNKNOWN2[] = {0x9f, 0x05};
static char GET_CARRIER_FREQ[] = {0x9f, 0x07};
static char GET_RX_TIMEOUT[] = {0x9f, 0x0d};
static char GET_TX_BITMASK[] = {0x9f, 0x13};
static char GET_RX_SENSOR[] = {0x9f, 0x15};
static char DEVICE_RESET[] = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER,
MCE_CMD_DEVICE_RESET};
static char GET_REVISION[] = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION};
static char GET_UNKNOWN[] = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7};
static char GET_UNKNOWN2[] = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2};
static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER};
static char GET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT};
static char GET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK};
static char GET_RX_SENSOR[] = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR};
/* sub in desired values in lower byte or bytes for full command */
/* FIXME: make use of these for transmit.
static char SET_CARRIER_FREQ[] = {0x9f, 0x06, 0x00, 0x00};
static char SET_TX_BITMASK[] = {0x9f, 0x08, 0x00};
static char SET_RX_TIMEOUT[] = {0x9f, 0x0c, 0x00, 0x00};
static char SET_RX_SENSOR[] = {0x9f, 0x14, 0x00};
static char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER,
MCE_CMD_S_CARRIER, 0x00, 0x00};
static char SET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00};
static char SET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER,
MCE_CMD_S_TIMEOUT, 0x00, 0x00};
static char SET_RX_SENSOR[] = {MCE_COMMAND_HEADER,
MCE_CMD_S_RXSENSOR, 0x00};
*/
static int mceusb_cmdsize(u8 cmd, u8 subcmd)
{
int datasize = 0;
switch (cmd) {
case MCE_COMMAND_NULL:
if (subcmd == MCE_HW_CMD_HEADER)
datasize = 1;
break;
case MCE_HW_CMD_HEADER:
switch (subcmd) {
case MCE_CMD_G_REVISION:
datasize = 2;
break;
}
case MCE_COMMAND_HEADER:
switch (subcmd) {
case MCE_CMD_UNKNOWN:
case MCE_CMD_S_CARRIER:
case MCE_CMD_S_TIMEOUT:
case MCE_CMD_G_RXSENSOR:
datasize = 2;
break;
case MCE_CMD_S_TXMASK:
case MCE_CMD_S_RXSENSOR:
datasize = 1;
break;
}
}
return datasize;
}
static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
int len, bool out)
int offset, int len, bool out)
{
char codes[USB_BUFLEN * 3 + 1];
char inout[9];
int i;
u8 cmd, subcmd, data1, data2;
struct device *dev = ir->dev;
int idx = 0;
int i, start, skip = 0;
if (!debug)
return;
/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
if (ir->flags.microsoft_gen1 && !out)
idx = 2;
skip = 2;
if (len <= idx)
if (len <= skip)
return;
for (i = 0; i < len && i < USB_BUFLEN; i++)
snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF);
snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff);
dev_info(dev, "%sx data: %s (length=%d)\n",
dev_info(dev, "%sx data: %s(length=%d)\n",
(out ? "t" : "r"), codes, len);
if (out)
@ -335,91 +450,93 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
else
strcpy(inout, "Got\0");
cmd = buf[idx] & 0xff;
subcmd = buf[idx + 1] & 0xff;
data1 = buf[idx + 2] & 0xff;
data2 = buf[idx + 3] & 0xff;
start = offset + skip;
cmd = buf[start] & 0xff;
subcmd = buf[start + 1] & 0xff;
data1 = buf[start + 2] & 0xff;
data2 = buf[start + 3] & 0xff;
switch (cmd) {
case 0x00:
if (subcmd == 0xff && data1 == 0xaa)
case MCE_COMMAND_NULL:
if ((subcmd == MCE_HW_CMD_HEADER) &&
(data1 == MCE_CMD_DEVICE_RESET))
dev_info(dev, "Device reset requested\n");
else
dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
cmd, subcmd);
break;
case 0xff:
case MCE_HW_CMD_HEADER:
switch (subcmd) {
case 0x0b:
case MCE_CMD_G_REVISION:
if (len == 2)
dev_info(dev, "Get hw/sw rev?\n");
else
dev_info(dev, "hw/sw rev 0x%02x 0x%02x "
"0x%02x 0x%02x\n", data1, data2,
buf[idx + 4], buf[idx + 5]);
buf[start + 4], buf[start + 5]);
break;
case 0xaa:
case MCE_CMD_DEVICE_RESET:
dev_info(dev, "Device reset requested\n");
break;
case 0xfe:
case MCE_RSP_CMD_INVALID:
dev_info(dev, "Previous command not supported\n");
break;
case 0x18:
case 0x1b:
case MCE_CMD_UNKNOWN7:
case MCE_CMD_UNKNOWN9:
default:
dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
cmd, subcmd);
break;
}
break;
case 0x9f:
case MCE_COMMAND_HEADER:
switch (subcmd) {
case 0x03:
case MCE_CMD_PING:
dev_info(dev, "Ping\n");
break;
case 0x04:
case MCE_CMD_UNKNOWN:
dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
data1, data2);
break;
case 0x06:
case MCE_CMD_S_CARRIER:
dev_info(dev, "%s carrier mode and freq of "
"0x%02x 0x%02x\n", inout, data1, data2);
break;
case 0x07:
case MCE_CMD_G_CARRIER:
dev_info(dev, "Get carrier mode and freq\n");
break;
case 0x08:
case MCE_CMD_S_TXMASK:
dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
inout, data1);
break;
case 0x0c:
case MCE_CMD_S_TIMEOUT:
/* value is in units of 50us, so x*50/100 or x/2 ms */
dev_info(dev, "%s receive timeout of %d ms\n",
inout, ((data1 << 8) | data2) / 2);
break;
case 0x0d:
case MCE_CMD_G_TIMEOUT:
dev_info(dev, "Get receive timeout\n");
break;
case 0x13:
case MCE_CMD_G_TXMASK:
dev_info(dev, "Get transmit blaster mask\n");
break;
case 0x14:
case MCE_CMD_S_RXSENSOR:
dev_info(dev, "%s %s-range receive sensor in use\n",
inout, data1 == 0x02 ? "short" : "long");
break;
case 0x15:
case MCE_CMD_G_RXSENSOR:
if (len == 2)
dev_info(dev, "Get receive sensor\n");
else
dev_info(dev, "Received pulse count is %d\n",
((data1 << 8) | data2));
break;
case 0xfe:
case MCE_RSP_CMD_INVALID:
dev_info(dev, "Error! Hardware is likely wedged...\n");
break;
case 0x05:
case 0x09:
case 0x0f:
case MCE_CMD_UNKNOWN2:
case MCE_CMD_UNKNOWN3:
case MCE_CMD_UNKNOWN5:
default:
dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
cmd, subcmd);
@ -429,6 +546,12 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
default:
break;
}
if (cmd == MCE_IRDATA_TRAILER)
dev_info(dev, "End of raw IR data\n");
else if ((cmd != MCE_COMMAND_HEADER) &&
((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA))
dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
}
static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
@ -446,9 +569,7 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
dev_dbg(ir->dev, "callback called (status=%d len=%d)\n",
urb->status, len);
if (debug)
mceusb_dev_printdata(ir, urb->transfer_buffer,
len, true);
mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
}
}
@ -536,8 +657,8 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
return -ENOMEM;
/* MCE tx init header */
cmdbuf[cmdcount++] = MCE_CONTROL_HEADER;
cmdbuf[cmdcount++] = 0x08;
cmdbuf[cmdcount++] = MCE_COMMAND_HEADER;
cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK;
cmdbuf[cmdcount++] = ir->tx_mask;
/* Generate mce packet data */
@ -551,7 +672,7 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
if ((cmdcount < MCE_CMDBUF_SIZE) &&
(cmdcount - MCE_TX_HEADER_LENGTH) %
MCE_CODE_LENGTH == 0)
cmdbuf[cmdcount++] = MCE_PACKET_HEADER;
cmdbuf[cmdcount++] = MCE_IRDATA_HEADER;
/* Insert mce packet data */
if (cmdcount < MCE_CMDBUF_SIZE)
@ -570,7 +691,8 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
/* Fix packet length in last header */
cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1;
MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) %
MCE_CODE_LENGTH - 1;
/* Check if we have room for the empty packet at the end */
if (cmdcount >= MCE_CMDBUF_SIZE) {
@ -579,7 +701,7 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
}
/* All mce commands end with an empty packet (0x80) */
cmdbuf[cmdcount++] = 0x80;
cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER;
/* Transmit the command to the mce device */
mce_async_out(ir, cmdbuf, cmdcount);
@ -608,7 +730,8 @@ static int mceusb_set_tx_mask(void *priv, u32 mask)
struct mceusb_dev *ir = priv;
if (ir->flags.tx_mask_inverted)
ir->tx_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1;
ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ?
mask ^ MCE_DEFAULT_TX_MASK : mask) << 1;
else
ir->tx_mask = mask;
@ -621,7 +744,8 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
struct mceusb_dev *ir = priv;
int clk = 10000000;
int prescaler = 0, divisor = 0;
unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 };
unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
MCE_CMD_S_CARRIER, 0x00, 0x00 };
/* Carrier has changed */
if (ir->carrier != carrier) {
@ -629,7 +753,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
if (carrier == 0) {
ir->carrier = carrier;
cmdbuf[2] = 0x01;
cmdbuf[3] = 0x80;
cmdbuf[3] = MCE_IRDATA_TRAILER;
dev_dbg(ir->dev, "%s: disabling carrier "
"modulation\n", __func__);
mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
@ -638,7 +762,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
for (prescaler = 0; prescaler < 4; ++prescaler) {
divisor = (clk >> (2 * prescaler)) / carrier;
if (divisor <= 0xFF) {
if (divisor <= 0xff) {
ir->carrier = carrier;
cmdbuf[2] = prescaler;
cmdbuf[3] = divisor;
@ -660,47 +784,36 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
{
struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
int i, start_index = 0;
u8 hdr = MCE_CONTROL_HEADER;
DEFINE_IR_RAW_EVENT(rawir);
int i = 0;
/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
if (ir->flags.microsoft_gen1)
start_index = 2;
i = 2;
for (i = start_index; i < buf_len;) {
if (ir->rem == 0) {
/* decode mce packets of the form (84),AA,BB,CC,DD */
/* IR data packets can span USB messages - rem */
hdr = ir->buf_in[i];
ir->rem = (hdr & MCE_PACKET_LENGTH_MASK);
ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK);
dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n",
ir->rem, ir->cmd);
i++;
}
/* don't process MCE commands */
if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) {
ir->rem = 0;
return;
}
for (; (ir->rem > 0) && (i < buf_len); i++) {
for (; i < buf_len; i++) {
switch (ir->parser_state) {
case SUBCMD:
ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]);
mceusb_dev_printdata(ir, ir->buf_in, i - 1,
ir->rem + 2, false);
ir->parser_state = CMD_DATA;
break;
case PARSE_IRDATA:
ir->rem--;
rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
* MCE_TIME_UNIT * 1000;
if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) {
if (ir->rawir.pulse == rawir.pulse)
if (ir->rawir.pulse == rawir.pulse) {
ir->rawir.duration += rawir.duration;
else {
} else {
ir->rawir.duration = rawir.duration;
ir->rawir.pulse = rawir.pulse;
}
continue;
if (ir->rem)
break;
}
rawir.duration += ir->rawir.duration;
ir->rawir.duration = 0;
@ -711,14 +824,40 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
rawir.duration);
ir_raw_event_store(ir->idev, &rawir);
break;
case CMD_DATA:
ir->rem--;
break;
case CMD_HEADER:
/* decode mce packets of the form (84),AA,BB,CC,DD */
/* IR data packets can span USB messages - rem */
ir->cmd = ir->buf_in[i];
if ((ir->cmd == MCE_COMMAND_HEADER) ||
((ir->cmd & MCE_COMMAND_MASK) !=
MCE_COMMAND_IRDATA)) {
ir->parser_state = SUBCMD;
continue;
}
ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
mceusb_dev_printdata(ir, ir->buf_in, i, ir->rem + 1, false);
if (ir->rem) {
ir->parser_state = PARSE_IRDATA;
break;
}
/*
* a package with len=0 (e. g. 0x80) means end of
* data. We could use it to do the call to
* ir_raw_event_handle(). For now, we don't need to
* use it.
*/
break;
}
if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f)
ir->rem = 0;
dev_dbg(ir->dev, "calling ir_raw_event_handle\n");
ir_raw_event_handle(ir->idev);
if (ir->parser_state != CMD_HEADER && !ir->rem)
ir->parser_state = CMD_HEADER;
}
dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
ir_raw_event_handle(ir->idev);
}
static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
@ -737,9 +876,6 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
buf_len = urb->actual_length;
if (debug)
mceusb_dev_printdata(ir, urb->transfer_buffer, buf_len, false);
if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
ir->send_flags = SEND_FLAG_COMPLETE;
dev_dbg(ir->dev, "setup answer received %d bytes\n",
@ -760,6 +896,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
case -EPIPE:
default:
dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
break;
}
@ -865,6 +1002,8 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
struct input_dev *idev;
struct ir_dev_props *props;
struct device *dev = ir->dev;
const char *rc_map = RC_MAP_RC6_MCE;
const char *name = "Media Center Ed. eHome Infrared Remote Transceiver";
int ret = -ENODEV;
idev = input_allocate_device();
@ -880,8 +1019,11 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
goto props_alloc_failed;
}
snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome "
"Infrared Remote Transceiver (%04x:%04x)",
if (mceusb_model[ir->model].name)
name = mceusb_model[ir->model].name;
snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)",
name,
le16_to_cpu(ir->usbdev->descriptor.idVendor),
le16_to_cpu(ir->usbdev->descriptor.idProduct));
@ -899,7 +1041,10 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
ir->props = props;
ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME);
if (mceusb_model[ir->model].rc_map)
rc_map = mceusb_model[ir->model].rc_map;
ret = ir_input_register(idev, rc_map, props, DRIVER_NAME);
if (ret < 0) {
dev_err(dev, "remote input device register failed\n");
goto irdev_failed;
@ -926,17 +1071,26 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
struct mceusb_dev *ir = NULL;
int pipe, maxp, i;
char buf[63], name[128] = "";
enum mceusb_model_type model = id->driver_info;
bool is_gen3;
bool is_microsoft_gen1;
bool tx_mask_inverted;
bool is_polaris;
dev_dbg(&intf->dev, ": %s called\n", __func__);
idesc = intf->cur_altsetting;
is_gen3 = usb_match_id(intf, gen3_list) ? 1 : 0;
is_microsoft_gen1 = usb_match_id(intf, microsoft_gen1_list) ? 1 : 0;
tx_mask_inverted = usb_match_id(intf, std_tx_mask_list) ? 0 : 1;
is_gen3 = mceusb_model[model].mce_gen3;
is_microsoft_gen1 = mceusb_model[model].mce_gen1;
tx_mask_inverted = mceusb_model[model].tx_mask_inverted;
is_polaris = mceusb_model[model].is_polaris;
if (is_polaris) {
/* Interface 0 is IR */
if (idesc->desc.bInterfaceNumber)
return -ENODEV;
}
/* step through the endpoints to find first bulk in and out endpoint */
for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
@ -997,6 +1151,9 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
ir->len_in = maxp;
ir->flags.microsoft_gen1 = is_microsoft_gen1;
ir->flags.tx_mask_inverted = tx_mask_inverted;
ir->model = model;
init_ir_raw_event(&ir->rawir);
/* Saving usb interface data for use by the transmitter routine */
ir->usb_ep_in = ep_in;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,408 @@
/*
* Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR
*
* Copyright (C) 2010 Jarod Wilson <jarod@redhat.com>
* Copyright (C) 2009 Nuvoton PS Team
*
* Special thanks to Nuvoton for providing hardware, spec sheets and
* sample code upon which portions of this driver are based. Indirect
* thanks also to Maxim Levitsky, whose ene_ir driver this driver is
* modeled after.
*
* 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/spinlock.h>
#include <linux/ioctl.h>
/* platform driver name to register */
#define NVT_DRIVER_NAME "nuvoton-cir"
/* debugging module parameter */
static int debug;
#define nvt_pr(level, text, ...) \
printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
#define nvt_dbg(text, ...) \
if (debug) \
printk(KERN_DEBUG \
KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
#define nvt_dbg_verbose(text, ...) \
if (debug > 1) \
printk(KERN_DEBUG \
KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
#define nvt_dbg_wake(text, ...) \
if (debug > 2) \
printk(KERN_DEBUG \
KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
/*
* Original lirc driver said min value of 76, and recommended value of 256
* for the buffer length, but then used 2048. Never mind that the size of the
* RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm
* not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes),
* and I don't have TX-capable hardware to test/debug on...
*/
#define TX_BUF_LEN 256
#define RX_BUF_LEN 32
struct nvt_dev {
struct pnp_dev *pdev;
struct input_dev *rdev;
struct ir_dev_props *props;
struct ir_raw_event rawir;
spinlock_t nvt_lock;
bool in_use;
/* for rx */
u8 buf[RX_BUF_LEN];
unsigned int pkts;
struct {
spinlock_t lock;
u8 buf[TX_BUF_LEN];
unsigned int buf_count;
unsigned int cur_buf_num;
wait_queue_head_t queue;
u8 tx_state;
} tx;
/* EFER Config register index/data pair */
u8 cr_efir;
u8 cr_efdr;
/* hardware I/O settings */
unsigned long cir_addr;
unsigned long cir_wake_addr;
int cir_irq;
int cir_wake_irq;
/* hardware id */
u8 chip_major;
u8 chip_minor;
/* hardware features */
bool hw_learning_capable;
bool hw_tx_capable;
/* rx settings */
bool learning_enabled;
bool carrier_detect_enabled;
/* track cir wake state */
u8 wake_state;
/* for study */
u8 study_state;
/* carrier period = 1 / frequency */
u32 carrier;
};
/* study states */
#define ST_STUDY_NONE 0x0
#define ST_STUDY_START 0x1
#define ST_STUDY_CARRIER 0x2
#define ST_STUDY_ALL_RECV 0x4
/* wake states */
#define ST_WAKE_NONE 0x0
#define ST_WAKE_START 0x1
#define ST_WAKE_FINISH 0x2
/* receive states */
#define ST_RX_WAIT_7F 0x1
#define ST_RX_WAIT_HEAD 0x2
#define ST_RX_WAIT_SILENT_END 0x4
/* send states */
#define ST_TX_NONE 0x0
#define ST_TX_REQUEST 0x2
#define ST_TX_REPLY 0x4
/* buffer packet constants */
#define BUF_PULSE_BIT 0x80
#define BUF_LEN_MASK 0x7f
#define BUF_REPEAT_BYTE 0x70
#define BUF_REPEAT_MASK 0xf0
/* CIR settings */
/* total length of CIR and CIR WAKE */
#define CIR_IOREG_LENGTH 0x0f
/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL (0x7d0 = 2000) */
#define CIR_RX_LIMIT_COUNT 0x7d0
/* CIR Regs */
#define CIR_IRCON 0x00
#define CIR_IRSTS 0x01
#define CIR_IREN 0x02
#define CIR_RXFCONT 0x03
#define CIR_CP 0x04
#define CIR_CC 0x05
#define CIR_SLCH 0x06
#define CIR_SLCL 0x07
#define CIR_FIFOCON 0x08
#define CIR_IRFIFOSTS 0x09
#define CIR_SRXFIFO 0x0a
#define CIR_TXFCONT 0x0b
#define CIR_STXFIFO 0x0c
#define CIR_FCCH 0x0d
#define CIR_FCCL 0x0e
#define CIR_IRFSM 0x0f
/* CIR IRCON settings */
#define CIR_IRCON_RECV 0x80
#define CIR_IRCON_WIREN 0x40
#define CIR_IRCON_TXEN 0x20
#define CIR_IRCON_RXEN 0x10
#define CIR_IRCON_WRXINV 0x08
#define CIR_IRCON_RXINV 0x04
#define CIR_IRCON_SAMPLE_PERIOD_SEL_1 0x00
#define CIR_IRCON_SAMPLE_PERIOD_SEL_25 0x01
#define CIR_IRCON_SAMPLE_PERIOD_SEL_50 0x02
#define CIR_IRCON_SAMPLE_PERIOD_SEL_100 0x03
/* FIXME: make this a runtime option */
/* select sample period as 50us */
#define CIR_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50
/* CIR IRSTS settings */
#define CIR_IRSTS_RDR 0x80
#define CIR_IRSTS_RTR 0x40
#define CIR_IRSTS_PE 0x20
#define CIR_IRSTS_RFO 0x10
#define CIR_IRSTS_TE 0x08
#define CIR_IRSTS_TTR 0x04
#define CIR_IRSTS_TFU 0x02
#define CIR_IRSTS_GH 0x01
/* CIR IREN settings */
#define CIR_IREN_RDR 0x80
#define CIR_IREN_RTR 0x40
#define CIR_IREN_PE 0x20
#define CIR_IREN_RFO 0x10
#define CIR_IREN_TE 0x08
#define CIR_IREN_TTR 0x04
#define CIR_IREN_TFU 0x02
#define CIR_IREN_GH 0x01
/* CIR FIFOCON settings */
#define CIR_FIFOCON_TXFIFOCLR 0x80
#define CIR_FIFOCON_TX_TRIGGER_LEV_31 0x00
#define CIR_FIFOCON_TX_TRIGGER_LEV_24 0x10
#define CIR_FIFOCON_TX_TRIGGER_LEV_16 0x20
#define CIR_FIFOCON_TX_TRIGGER_LEV_8 0x30
/* FIXME: make this a runtime option */
/* select TX trigger level as 16 */
#define CIR_FIFOCON_TX_TRIGGER_LEV CIR_FIFOCON_TX_TRIGGER_LEV_16
#define CIR_FIFOCON_RXFIFOCLR 0x08
#define CIR_FIFOCON_RX_TRIGGER_LEV_1 0x00
#define CIR_FIFOCON_RX_TRIGGER_LEV_8 0x01
#define CIR_FIFOCON_RX_TRIGGER_LEV_16 0x02
#define CIR_FIFOCON_RX_TRIGGER_LEV_24 0x03
/* FIXME: make this a runtime option */
/* select RX trigger level as 24 */
#define CIR_FIFOCON_RX_TRIGGER_LEV CIR_FIFOCON_RX_TRIGGER_LEV_24
/* CIR IRFIFOSTS settings */
#define CIR_IRFIFOSTS_IR_PENDING 0x80
#define CIR_IRFIFOSTS_RX_GS 0x40
#define CIR_IRFIFOSTS_RX_FTA 0x20
#define CIR_IRFIFOSTS_RX_EMPTY 0x10
#define CIR_IRFIFOSTS_RX_FULL 0x08
#define CIR_IRFIFOSTS_TX_FTA 0x04
#define CIR_IRFIFOSTS_TX_EMPTY 0x02
#define CIR_IRFIFOSTS_TX_FULL 0x01
/* CIR WAKE UP Regs */
#define CIR_WAKE_IRCON 0x00
#define CIR_WAKE_IRSTS 0x01
#define CIR_WAKE_IREN 0x02
#define CIR_WAKE_FIFO_CMP_DEEP 0x03
#define CIR_WAKE_FIFO_CMP_TOL 0x04
#define CIR_WAKE_FIFO_COUNT 0x05
#define CIR_WAKE_SLCH 0x06
#define CIR_WAKE_SLCL 0x07
#define CIR_WAKE_FIFOCON 0x08
#define CIR_WAKE_SRXFSTS 0x09
#define CIR_WAKE_SAMPLE_RX_FIFO 0x0a
#define CIR_WAKE_WR_FIFO_DATA 0x0b
#define CIR_WAKE_RD_FIFO_ONLY 0x0c
#define CIR_WAKE_RD_FIFO_ONLY_IDX 0x0d
#define CIR_WAKE_FIFO_IGNORE 0x0e
#define CIR_WAKE_IRFSM 0x0f
/* CIR WAKE UP IRCON settings */
#define CIR_WAKE_IRCON_DEC_RST 0x80
#define CIR_WAKE_IRCON_MODE1 0x40
#define CIR_WAKE_IRCON_MODE0 0x20
#define CIR_WAKE_IRCON_RXEN 0x10
#define CIR_WAKE_IRCON_R 0x08
#define CIR_WAKE_IRCON_RXINV 0x04
/* FIXME/jarod: make this a runtime option */
/* select a same sample period like cir register */
#define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50
/* CIR WAKE IRSTS Bits */
#define CIR_WAKE_IRSTS_RDR 0x80
#define CIR_WAKE_IRSTS_RTR 0x40
#define CIR_WAKE_IRSTS_PE 0x20
#define CIR_WAKE_IRSTS_RFO 0x10
#define CIR_WAKE_IRSTS_GH 0x08
#define CIR_WAKE_IRSTS_IR_PENDING 0x01
/* CIR WAKE UP IREN Bits */
#define CIR_WAKE_IREN_RDR 0x80
#define CIR_WAKE_IREN_RTR 0x40
#define CIR_WAKE_IREN_PE 0x20
#define CIR_WAKE_IREN_RFO 0x10
#define CIR_WAKE_IREN_TE 0x08
#define CIR_WAKE_IREN_TTR 0x04
#define CIR_WAKE_IREN_TFU 0x02
#define CIR_WAKE_IREN_GH 0x01
/* CIR WAKE FIFOCON settings */
#define CIR_WAKE_FIFOCON_RXFIFOCLR 0x08
#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 0x00
#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_66 0x01
#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_65 0x02
#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_64 0x03
/* FIXME: make this a runtime option */
/* select WAKE UP RX trigger level as 67 */
#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67
/* CIR WAKE SRXFSTS settings */
#define CIR_WAKE_IRFIFOSTS_RX_GS 0x80
#define CIR_WAKE_IRFIFOSTS_RX_FTA 0x40
#define CIR_WAKE_IRFIFOSTS_RX_EMPTY 0x20
#define CIR_WAKE_IRFIFOSTS_RX_FULL 0x10
/* CIR Wake FIFO buffer is 67 bytes long */
#define CIR_WAKE_FIFO_LEN 67
/* CIR Wake byte comparison tolerance */
#define CIR_WAKE_CMP_TOLERANCE 5
/*
* Extended Function Enable Registers:
* Extended Function Index Register
* Extended Function Data Register
*/
#define CR_EFIR 0x2e
#define CR_EFDR 0x2f
/* Possible alternate EFER values, depends on how the chip is wired */
#define CR_EFIR2 0x4e
#define CR_EFDR2 0x4f
/* Extended Function Mode enable/disable magic values */
#define EFER_EFM_ENABLE 0x87
#define EFER_EFM_DISABLE 0xaa
/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
#define CHIP_ID_HIGH 0xb4
#define CHIP_ID_LOW 0x72
#define CHIP_ID_LOW2 0x73
/* Config regs we need to care about */
#define CR_SOFTWARE_RESET 0x02
#define CR_LOGICAL_DEV_SEL 0x07
#define CR_CHIP_ID_HI 0x20
#define CR_CHIP_ID_LO 0x21
#define CR_DEV_POWER_DOWN 0x22 /* bit 2 is CIR power, default power on */
#define CR_OUTPUT_PIN_SEL 0x27
#define CR_LOGICAL_DEV_EN 0x30 /* valid for all logical devices */
/* next three regs valid for both the CIR and CIR_WAKE logical devices */
#define CR_CIR_BASE_ADDR_HI 0x60
#define CR_CIR_BASE_ADDR_LO 0x61
#define CR_CIR_IRQ_RSRC 0x70
/* next three regs valid only for ACPI logical dev */
#define CR_ACPI_CIR_WAKE 0xe0
#define CR_ACPI_IRQ_EVENTS 0xf6
#define CR_ACPI_IRQ_EVENTS2 0xf7
/* Logical devices that we need to care about */
#define LOGICAL_DEV_LPT 0x01
#define LOGICAL_DEV_CIR 0x06
#define LOGICAL_DEV_ACPI 0x0a
#define LOGICAL_DEV_CIR_WAKE 0x0e
#define LOGICAL_DEV_DISABLE 0x00
#define LOGICAL_DEV_ENABLE 0x01
#define CIR_WAKE_ENABLE_BIT 0x08
#define CIR_INTR_MOUSE_IRQ_BIT 0x80
#define PME_INTR_CIR_PASS_BIT 0x08
#define OUTPUT_PIN_SEL_MASK 0xbc
#define OUTPUT_ENABLE_CIR 0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */
#define OUTPUT_ENABLE_CIRWB 0x40 /* enable wide-band sensor */
/* MCE CIR signal length, related on sample period */
/* MCE CIR controller signal length: about 43ms
* 43ms / 50us (sample period) * 0.85 (inaccuracy)
*/
#define CONTROLLER_BUF_LEN_MIN 830
/* MCE CIR keyboard signal length: about 26ms
* 26ms / 50us (sample period) * 0.85 (inaccuracy)
*/
#define KEYBOARD_BUF_LEN_MAX 650
#define KEYBOARD_BUF_LEN_MIN 610
/* MCE CIR mouse signal length: about 24ms
* 24ms / 50us (sample period) * 0.85 (inaccuracy)
*/
#define MOUSE_BUF_LEN_MIN 565
#define CIR_SAMPLE_PERIOD 50
#define CIR_SAMPLE_LOW_INACCURACY 0.85
/* MAX silence time that driver will sent to lirc */
#define MAX_SILENCE_TIME 60000
#if CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_100
#define SAMPLE_PERIOD 100
#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_50
#define SAMPLE_PERIOD 50
#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_25
#define SAMPLE_PERIOD 25
#else
#define SAMPLE_PERIOD 1
#endif
/* as VISTA MCE definition, valid carrier value */
#define MAX_CARRIER 60000
#define MIN_CARRIER 30000

View file

@ -38,7 +38,7 @@
#include <linux/input.h>
#include <media/ir-core.h>
#define DRIVER_VERSION "1.60"
#define DRIVER_VERSION "1.61"
#define DRIVER_NAME "streamzap"
#define DRIVER_DESC "Streamzap Remote Control driver"
@ -61,14 +61,21 @@ static struct usb_device_id streamzap_table[] = {
MODULE_DEVICE_TABLE(usb, streamzap_table);
#define STREAMZAP_PULSE_MASK 0xf0
#define STREAMZAP_SPACE_MASK 0x0f
#define STREAMZAP_TIMEOUT 0xff
#define STREAMZAP_RESOLUTION 256
#define SZ_PULSE_MASK 0xf0
#define SZ_SPACE_MASK 0x0f
#define SZ_TIMEOUT 0xff
#define SZ_RESOLUTION 256
/* number of samples buffered */
#define SZ_BUF_LEN 128
/* from ir-rc5-sz-decoder.c */
#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE
#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder")
#else
#define load_rc5_sz_decode() 0
#endif
enum StreamzapDecoderState {
PulseSpace,
FullPulse,
@ -81,7 +88,6 @@ struct streamzap_ir {
/* ir-core */
struct ir_dev_props *props;
struct ir_raw_event rawir;
/* core device info */
struct device *dev;
@ -98,17 +104,6 @@ struct streamzap_ir {
dma_addr_t dma_in;
unsigned int buf_in_len;
/* timer used to support delay buffering */
struct timer_list delay_timer;
bool timer_running;
spinlock_t timer_lock;
struct timer_list flush_timer;
bool flush;
/* delay buffer */
struct kfifo fifo;
bool fifo_initialized;
/* track what state we're in */
enum StreamzapDecoderState decoder_state;
/* tracks whether we are currently receiving some signal */
@ -118,7 +113,7 @@ struct streamzap_ir {
/* start time of signal; necessary for gap tracking */
struct timeval signal_last;
struct timeval signal_start;
/* bool timeout_enabled; */
bool timeout_enabled;
char name[128];
char phys[64];
@ -143,122 +138,16 @@ static struct usb_driver streamzap_driver = {
.id_table = streamzap_table,
};
static void streamzap_stop_timer(struct streamzap_ir *sz)
static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
{
unsigned long flags;
spin_lock_irqsave(&sz->timer_lock, flags);
if (sz->timer_running) {
sz->timer_running = false;
spin_unlock_irqrestore(&sz->timer_lock, flags);
del_timer_sync(&sz->delay_timer);
} else {
spin_unlock_irqrestore(&sz->timer_lock, flags);
}
}
static void streamzap_flush_timeout(unsigned long arg)
{
struct streamzap_ir *sz = (struct streamzap_ir *)arg;
dev_info(sz->dev, "%s: callback firing\n", __func__);
/* finally start accepting data */
sz->flush = false;
}
static void streamzap_delay_timeout(unsigned long arg)
{
struct streamzap_ir *sz = (struct streamzap_ir *)arg;
struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
unsigned long flags;
int len, ret;
static unsigned long delay;
bool wake = false;
/* deliver data every 10 ms */
delay = msecs_to_jiffies(10);
spin_lock_irqsave(&sz->timer_lock, flags);
if (kfifo_len(&sz->fifo) > 0) {
ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
if (ret != sizeof(rawir))
dev_err(sz->dev, "Problem w/kfifo_out...\n");
ir_raw_event_store(sz->idev, &rawir);
wake = true;
}
len = kfifo_len(&sz->fifo);
if (len > 0) {
while ((len < SZ_BUF_LEN / 2) &&
(len < SZ_BUF_LEN * sizeof(int))) {
ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
if (ret != sizeof(rawir))
dev_err(sz->dev, "Problem w/kfifo_out...\n");
ir_raw_event_store(sz->idev, &rawir);
wake = true;
len = kfifo_len(&sz->fifo);
}
if (sz->timer_running)
mod_timer(&sz->delay_timer, jiffies + delay);
} else {
sz->timer_running = false;
}
if (wake)
ir_raw_event_handle(sz->idev);
spin_unlock_irqrestore(&sz->timer_lock, flags);
}
static void streamzap_flush_delay_buffer(struct streamzap_ir *sz)
{
struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
bool wake = false;
int ret;
while (kfifo_len(&sz->fifo) > 0) {
ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
if (ret != sizeof(rawir))
dev_err(sz->dev, "Problem w/kfifo_out...\n");
ir_raw_event_store(sz->idev, &rawir);
wake = true;
}
if (wake)
ir_raw_event_handle(sz->idev);
}
static void sz_push(struct streamzap_ir *sz)
{
struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
unsigned long flags;
int ret;
spin_lock_irqsave(&sz->timer_lock, flags);
if (kfifo_len(&sz->fifo) >= sizeof(int) * SZ_BUF_LEN) {
ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
if (ret != sizeof(rawir))
dev_err(sz->dev, "Problem w/kfifo_out...\n");
ir_raw_event_store(sz->idev, &rawir);
}
kfifo_in(&sz->fifo, &sz->rawir, sizeof(rawir));
if (!sz->timer_running) {
sz->delay_timer.expires = jiffies + (HZ / 10);
add_timer(&sz->delay_timer);
sz->timer_running = true;
}
spin_unlock_irqrestore(&sz->timer_lock, flags);
ir_raw_event_store(sz->idev, &rawir);
}
static void sz_push_full_pulse(struct streamzap_ir *sz,
unsigned char value)
{
DEFINE_IR_RAW_EVENT(rawir);
if (sz->idle) {
long deltv;
@ -266,57 +155,59 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
do_gettimeofday(&sz->signal_start);
deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
sz->rawir.pulse = false;
rawir.pulse = false;
if (deltv > 15) {
/* really long time */
sz->rawir.duration = IR_MAX_DURATION;
rawir.duration = IR_MAX_DURATION;
} else {
sz->rawir.duration = (int)(deltv * 1000000 +
rawir.duration = (int)(deltv * 1000000 +
sz->signal_start.tv_usec -
sz->signal_last.tv_usec);
sz->rawir.duration -= sz->sum;
sz->rawir.duration *= 1000;
sz->rawir.duration &= IR_MAX_DURATION;
rawir.duration -= sz->sum;
rawir.duration *= 1000;
rawir.duration &= IR_MAX_DURATION;
}
dev_dbg(sz->dev, "ls %u\n", sz->rawir.duration);
sz_push(sz);
dev_dbg(sz->dev, "ls %u\n", rawir.duration);
sz_push(sz, rawir);
sz->idle = 0;
sz->idle = false;
sz->sum = 0;
}
sz->rawir.pulse = true;
sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
sz->rawir.duration += STREAMZAP_RESOLUTION / 2;
sz->sum += sz->rawir.duration;
sz->rawir.duration *= 1000;
sz->rawir.duration &= IR_MAX_DURATION;
dev_dbg(sz->dev, "p %u\n", sz->rawir.duration);
sz_push(sz);
rawir.pulse = true;
rawir.duration = ((int) value) * SZ_RESOLUTION;
rawir.duration += SZ_RESOLUTION / 2;
sz->sum += rawir.duration;
rawir.duration *= 1000;
rawir.duration &= IR_MAX_DURATION;
dev_dbg(sz->dev, "p %u\n", rawir.duration);
sz_push(sz, rawir);
}
static void sz_push_half_pulse(struct streamzap_ir *sz,
unsigned char value)
{
sz_push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK) >> 4);
sz_push_full_pulse(sz, (value & SZ_PULSE_MASK) >> 4);
}
static void sz_push_full_space(struct streamzap_ir *sz,
unsigned char value)
{
sz->rawir.pulse = false;
sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
sz->rawir.duration += STREAMZAP_RESOLUTION / 2;
sz->sum += sz->rawir.duration;
sz->rawir.duration *= 1000;
dev_dbg(sz->dev, "s %u\n", sz->rawir.duration);
sz_push(sz);
DEFINE_IR_RAW_EVENT(rawir);
rawir.pulse = false;
rawir.duration = ((int) value) * SZ_RESOLUTION;
rawir.duration += SZ_RESOLUTION / 2;
sz->sum += rawir.duration;
rawir.duration *= 1000;
dev_dbg(sz->dev, "s %u\n", rawir.duration);
sz_push(sz, rawir);
}
static void sz_push_half_space(struct streamzap_ir *sz,
unsigned long value)
{
sz_push_full_space(sz, value & STREAMZAP_SPACE_MASK);
sz_push_full_space(sz, value & SZ_SPACE_MASK);
}
/**
@ -330,10 +221,8 @@ static void streamzap_callback(struct urb *urb)
struct streamzap_ir *sz;
unsigned int i;
int len;
#if 0
static int timeout = (((STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) &
static int timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
IR_MAX_DURATION) | 0x03000000);
#endif
if (!urb)
return;
@ -356,57 +245,53 @@ static void streamzap_callback(struct urb *urb)
}
dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len);
if (!sz->flush) {
for (i = 0; i < urb->actual_length; i++) {
dev_dbg(sz->dev, "%d: %x\n", i,
(unsigned char)sz->buf_in[i]);
switch (sz->decoder_state) {
case PulseSpace:
if ((sz->buf_in[i] & STREAMZAP_PULSE_MASK) ==
STREAMZAP_PULSE_MASK) {
sz->decoder_state = FullPulse;
continue;
} else if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK)
== STREAMZAP_SPACE_MASK) {
sz_push_half_pulse(sz, sz->buf_in[i]);
sz->decoder_state = FullSpace;
continue;
} else {
sz_push_half_pulse(sz, sz->buf_in[i]);
sz_push_half_space(sz, sz->buf_in[i]);
}
break;
case FullPulse:
sz_push_full_pulse(sz, sz->buf_in[i]);
sz->decoder_state = IgnorePulse;
break;
case FullSpace:
if (sz->buf_in[i] == STREAMZAP_TIMEOUT) {
sz->idle = 1;
streamzap_stop_timer(sz);
#if 0
if (sz->timeout_enabled) {
sz->rawir.pulse = false;
sz->rawir.duration = timeout;
sz->rawir.duration *= 1000;
sz_push(sz);
}
#endif
streamzap_flush_delay_buffer(sz);
} else
sz_push_full_space(sz, sz->buf_in[i]);
sz->decoder_state = PulseSpace;
break;
case IgnorePulse:
if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) ==
STREAMZAP_SPACE_MASK) {
sz->decoder_state = FullSpace;
continue;
}
for (i = 0; i < len; i++) {
dev_dbg(sz->dev, "sz idx %d: %x\n",
i, (unsigned char)sz->buf_in[i]);
switch (sz->decoder_state) {
case PulseSpace:
if ((sz->buf_in[i] & SZ_PULSE_MASK) ==
SZ_PULSE_MASK) {
sz->decoder_state = FullPulse;
continue;
} else if ((sz->buf_in[i] & SZ_SPACE_MASK)
== SZ_SPACE_MASK) {
sz_push_half_pulse(sz, sz->buf_in[i]);
sz->decoder_state = FullSpace;
continue;
} else {
sz_push_half_pulse(sz, sz->buf_in[i]);
sz_push_half_space(sz, sz->buf_in[i]);
sz->decoder_state = PulseSpace;
break;
}
break;
case FullPulse:
sz_push_full_pulse(sz, sz->buf_in[i]);
sz->decoder_state = IgnorePulse;
break;
case FullSpace:
if (sz->buf_in[i] == SZ_TIMEOUT) {
DEFINE_IR_RAW_EVENT(rawir);
rawir.pulse = false;
rawir.duration = timeout;
sz->idle = true;
if (sz->timeout_enabled)
sz_push(sz, rawir);
ir_raw_event_handle(sz->idev);
} else {
sz_push_full_space(sz, sz->buf_in[i]);
}
sz->decoder_state = PulseSpace;
break;
case IgnorePulse:
if ((sz->buf_in[i] & SZ_SPACE_MASK) ==
SZ_SPACE_MASK) {
sz->decoder_state = FullSpace;
continue;
}
sz_push_half_space(sz, sz->buf_in[i]);
sz->decoder_state = PulseSpace;
break;
}
}
@ -446,12 +331,11 @@ static struct input_dev *streamzap_init_input_dev(struct streamzap_ir *sz)
props->priv = sz;
props->driver_type = RC_DRIVER_IR_RAW;
/* FIXME: not sure about supported protocols, check on this */
props->allowed_protos = IR_TYPE_RC5 | IR_TYPE_RC6;
props->allowed_protos = IR_TYPE_ALL;
sz->props = props;
ret = ir_input_register(idev, RC_MAP_RC5_STREAMZAP, props, DRIVER_NAME);
ret = ir_input_register(idev, RC_MAP_STREAMZAP, props, DRIVER_NAME);
if (ret < 0) {
dev_err(dev, "remote input device register failed\n");
goto irdev_failed;
@ -467,29 +351,6 @@ idev_alloc_failed:
return NULL;
}
static int streamzap_delay_buf_init(struct streamzap_ir *sz)
{
int ret;
ret = kfifo_alloc(&sz->fifo, sizeof(int) * SZ_BUF_LEN,
GFP_KERNEL);
if (ret == 0)
sz->fifo_initialized = 1;
return ret;
}
static void streamzap_start_flush_timer(struct streamzap_ir *sz)
{
sz->flush_timer.expires = jiffies + HZ;
sz->flush = true;
add_timer(&sz->flush_timer);
sz->urb_in->dev = sz->usbdev;
if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
dev_err(sz->dev, "urb submit failed\n");
}
/**
* streamzap_probe
*
@ -575,35 +436,21 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
snprintf(name + strlen(name), sizeof(name) - strlen(name),
" %s", buf);
retval = streamzap_delay_buf_init(sz);
if (retval) {
dev_err(&intf->dev, "%s: delay buffer init failed\n", __func__);
goto free_urb_in;
}
sz->idev = streamzap_init_input_dev(sz);
if (!sz->idev)
goto input_dev_fail;
sz->idle = true;
sz->decoder_state = PulseSpace;
/* FIXME: don't yet have a way to set this */
sz->timeout_enabled = true;
#if 0
/* not yet supported, depends on patches from maxim */
/* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
sz->timeout_enabled = false;
sz->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
sz->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
#endif
init_timer(&sz->delay_timer);
sz->delay_timer.function = streamzap_delay_timeout;
sz->delay_timer.data = (unsigned long)sz;
spin_lock_init(&sz->timer_lock);
init_timer(&sz->flush_timer);
sz->flush_timer.function = streamzap_flush_timeout;
sz->flush_timer.data = (unsigned long)sz;
do_gettimeofday(&sz->signal_start);
/* Complete final initialisations */
@ -615,16 +462,18 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
usb_set_intfdata(intf, sz);
streamzap_start_flush_timer(sz);
if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
dev_err(sz->dev, "urb submit failed\n");
dev_info(sz->dev, "Registered %s on usb%d:%d\n", name,
usbdev->bus->busnum, usbdev->devnum);
/* Load the streamzap not-quite-rc5 decoder too */
load_rc5_sz_decode();
return 0;
input_dev_fail:
kfifo_free(&sz->fifo);
free_urb_in:
usb_free_urb(sz->urb_in);
free_buf_in:
usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in);
@ -654,13 +503,6 @@ static void streamzap_disconnect(struct usb_interface *interface)
if (!sz)
return;
if (sz->flush) {
sz->flush = false;
del_timer_sync(&sz->flush_timer);
}
streamzap_stop_timer(sz);
sz->usbdev = NULL;
ir_input_unregister(sz->idev);
usb_kill_urb(sz->urb_in);
@ -674,13 +516,6 @@ static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
{
struct streamzap_ir *sz = usb_get_intfdata(intf);
if (sz->flush) {
sz->flush = false;
del_timer_sync(&sz->flush_timer);
}
streamzap_stop_timer(sz);
usb_kill_urb(sz->urb_in);
return 0;
@ -690,13 +525,6 @@ static int streamzap_resume(struct usb_interface *intf)
{
struct streamzap_ir *sz = usb_get_intfdata(intf);
if (sz->fifo_initialized)
kfifo_reset(&sz->fifo);
sz->flush_timer.expires = jiffies + HZ;
sz->flush = true;
add_timer(&sz->flush_timer);
if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
dev_err(sz->dev, "Error sumbiting urb\n");
return -EIO;

View file

@ -56,7 +56,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
videobuf_waiton(q, &buf->vb, 0, 0);
videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
buf->vb.state = VIDEOBUF_NEEDS_INIT;

View file

@ -414,7 +414,6 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
i2c_adapter->dev.parent = &dev->pci->dev;
i2c_adapter->algo = &saa7146_algo;
i2c_adapter->algo_data = NULL;
i2c_adapter->id = I2C_HW_SAA7146;
i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
i2c_adapter->retries = SAA7146_I2C_RETRIES;
}

View file

@ -412,7 +412,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
sizeof(struct saa7146_buf),
file);
file, NULL);
init_timer(&fh->vbi_read_timeout);
fh->vbi_read_timeout.function = vbi_read_timeout;

View file

@ -1386,7 +1386,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7146_buf),
file);
file, NULL);
return 0;
}

View file

@ -179,4 +179,11 @@ config MEDIA_TUNER_MAX2165
help
A driver for the silicon tuner MAX2165 from Maxim.
config MEDIA_TUNER_TDA18218
tristate "NXP TDA18218 silicon tuner"
depends on VIDEO_MEDIA && I2C
default m if MEDIA_TUNER_CUSTOMISE
help
NXP TDA18218 silicon tuner driver.
endif # MEDIA_TUNER_CUSTOMISE

View file

@ -24,6 +24,7 @@ obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends

View file

@ -0,0 +1,334 @@
/*
* NXP TDA18218HN silicon tuner driver
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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 "tda18218.h"
#include "tda18218_priv.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
/* write multiple registers */
static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
{
int ret;
u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
struct i2c_msg msg[1] = {
{
.addr = priv->cfg->i2c_address,
.flags = 0,
.buf = buf,
}
};
msg_len_max = priv->cfg->i2c_wr_max - 1;
quotient = len / msg_len_max;
remainder = len % msg_len_max;
msg_len = msg_len_max;
for (i = 0; (i <= quotient && remainder); i++) {
if (i == quotient) /* set len of the last msg */
msg_len = remainder;
msg[0].len = msg_len + 1;
buf[0] = reg + i * msg_len_max;
memcpy(&buf[1], &val[i * msg_len_max], msg_len);
ret = i2c_transfer(priv->i2c, msg, 1);
if (ret != 1)
break;
}
if (ret == 1) {
ret = 0;
} else {
warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* read multiple registers */
static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
{
int ret;
u8 buf[reg+len]; /* we must start read always from reg 0x00 */
struct i2c_msg msg[2] = {
{
.addr = priv->cfg->i2c_address,
.flags = 0,
.len = 1,
.buf = "\x00",
}, {
.addr = priv->cfg->i2c_address,
.flags = I2C_M_RD,
.len = sizeof(buf),
.buf = buf,
}
};
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret == 2) {
memcpy(val, &buf[reg], len);
ret = 0;
} else {
warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
/* write single register */
static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
{
return tda18218_wr_regs(priv, reg, &val, 1);
}
/* read single register */
static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
{
return tda18218_rd_regs(priv, reg, val, 1);
}
static int tda18218_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
struct tda18218_priv *priv = fe->tuner_priv;
int ret;
u8 buf[3], i, BP_Filter, LP_Fc;
u32 LO_Frac;
/* TODO: find out correct AGC algorithm */
u8 agc[][2] = {
{ R20_AGC11, 0x60 },
{ R23_AGC21, 0x02 },
{ R20_AGC11, 0xa0 },
{ R23_AGC21, 0x09 },
{ R20_AGC11, 0xe0 },
{ R23_AGC21, 0x0c },
{ R20_AGC11, 0x40 },
{ R23_AGC21, 0x01 },
{ R20_AGC11, 0x80 },
{ R23_AGC21, 0x08 },
{ R20_AGC11, 0xc0 },
{ R23_AGC21, 0x0b },
{ R24_AGC22, 0x1c },
{ R24_AGC22, 0x0c },
};
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
/* low-pass filter cut-off frequency */
switch (params->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
LP_Fc = 0;
LO_Frac = params->frequency + 4000000;
break;
case BANDWIDTH_7_MHZ:
LP_Fc = 1;
LO_Frac = params->frequency + 3500000;
break;
case BANDWIDTH_8_MHZ:
default:
LP_Fc = 2;
LO_Frac = params->frequency + 4000000;
break;
}
/* band-pass filter */
if (LO_Frac < 188000000)
BP_Filter = 3;
else if (LO_Frac < 253000000)
BP_Filter = 4;
else if (LO_Frac < 343000000)
BP_Filter = 5;
else
BP_Filter = 6;
buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
buf[2] = priv->regs[R1C_AGC2B];
ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
if (ret)
goto error;
buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
buf[2] = (LO_Frac / 1000) << 4 |
(priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
if (ret)
goto error;
buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
if (ret)
goto error;
buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
if (ret)
goto error;
/* trigger AGC */
for (i = 0; i < ARRAY_SIZE(agc); i++) {
ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
if (ret)
goto error;
}
error:
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
if (ret)
dbg("%s: failed ret:%d", __func__, ret);
return ret;
}
static int tda18218_sleep(struct dvb_frontend *fe)
{
struct tda18218_priv *priv = fe->tuner_priv;
int ret;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
/* standby */
ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
if (ret)
dbg("%s: failed ret:%d", __func__, ret);
return ret;
}
static int tda18218_init(struct dvb_frontend *fe)
{
struct tda18218_priv *priv = fe->tuner_priv;
int ret;
/* TODO: calibrations */
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
if (ret)
dbg("%s: failed ret:%d", __func__, ret);
return ret;
}
static int tda18218_release(struct dvb_frontend *fe)
{
kfree(fe->tuner_priv);
fe->tuner_priv = NULL;
return 0;
}
static const struct dvb_tuner_ops tda18218_tuner_ops = {
.info = {
.name = "NXP TDA18218",
.frequency_min = 174000000,
.frequency_max = 864000000,
.frequency_step = 1000,
},
.release = tda18218_release,
.init = tda18218_init,
.sleep = tda18218_sleep,
.set_params = tda18218_set_params,
};
struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18218_config *cfg)
{
struct tda18218_priv *priv = NULL;
u8 val;
int ret;
/* chip default registers values */
static u8 def_regs[] = {
0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
};
priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
if (priv == NULL)
return NULL;
priv->cfg = cfg;
priv->i2c = i2c;
fe->tuner_priv = priv;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
/* check if the tuner is there */
ret = tda18218_rd_reg(priv, R00_ID, &val);
dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
if (ret || val != def_regs[R00_ID]) {
kfree(priv);
return NULL;
}
info("NXP TDA18218HN successfully identified.");
memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
sizeof(struct dvb_tuner_ops));
memcpy(priv->regs, def_regs, sizeof(def_regs));
/* loop-through enabled chip default register values */
if (priv->cfg->loop_through) {
priv->regs[R17_PD1] = 0xb0;
priv->regs[R18_PD2] = 0x59;
}
/* standby */
ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
if (ret)
dbg("%s: failed ret:%d", __func__, ret);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
return fe;
}
EXPORT_SYMBOL(tda18218_attach);
MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
MODULE_AUTHOR("Antti Palosaari <[email protected]>");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,45 @@
/*
* NXP TDA18218HN silicon tuner driver
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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 TDA18218_H
#define TDA18218_H
#include "dvb_frontend.h"
struct tda18218_config {
u8 i2c_address;
u8 i2c_wr_max;
u8 loop_through:1;
};
#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \
(defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE))
extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18218_config *cfg);
#else
static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18218_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
#endif

View file

@ -0,0 +1,106 @@
/*
* NXP TDA18218HN silicon tuner driver
*
* Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
*
* 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 TDA18218_PRIV_H
#define TDA18218_PRIV_H
#define LOG_PREFIX "tda18218"
#undef dbg
#define dbg(f, arg...) \
if (debug) \
printk(KERN_DEBUG LOG_PREFIX": " f "\n" , ## arg)
#undef err
#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
#undef info
#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
#undef warn
#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
#define R00_ID 0x00 /* ID byte */
#define R01_R1 0x01 /* Read byte 1 */
#define R02_R2 0x02 /* Read byte 2 */
#define R03_R3 0x03 /* Read byte 3 */
#define R04_R4 0x04 /* Read byte 4 */
#define R05_R5 0x05 /* Read byte 5 */
#define R06_R6 0x06 /* Read byte 6 */
#define R07_MD1 0x07 /* Main divider byte 1 */
#define R08_PSM1 0x08 /* PSM byte 1 */
#define R09_MD2 0x09 /* Main divider byte 2 */
#define R0A_MD3 0x0a /* Main divider byte 1 */
#define R0B_MD4 0x0b /* Main divider byte 4 */
#define R0C_MD5 0x0c /* Main divider byte 5 */
#define R0D_MD6 0x0d /* Main divider byte 6 */
#define R0E_MD7 0x0e /* Main divider byte 7 */
#define R0F_MD8 0x0f /* Main divider byte 8 */
#define R10_CD1 0x10 /* Call divider byte 1 */
#define R11_CD2 0x11 /* Call divider byte 2 */
#define R12_CD3 0x12 /* Call divider byte 3 */
#define R13_CD4 0x13 /* Call divider byte 4 */
#define R14_CD5 0x14 /* Call divider byte 5 */
#define R15_CD6 0x15 /* Call divider byte 6 */
#define R16_CD7 0x16 /* Call divider byte 7 */
#define R17_PD1 0x17 /* Power-down byte 1 */
#define R18_PD2 0x18 /* Power-down byte 2 */
#define R19_XTOUT 0x19 /* XTOUT byte */
#define R1A_IF1 0x1a /* IF byte 1 */
#define R1B_IF2 0x1b /* IF byte 2 */
#define R1C_AGC2B 0x1c /* AGC2b byte */
#define R1D_PSM2 0x1d /* PSM byte 2 */
#define R1E_PSM3 0x1e /* PSM byte 3 */
#define R1F_PSM4 0x1f /* PSM byte 4 */
#define R20_AGC11 0x20 /* AGC1 byte 1 */
#define R21_AGC12 0x21 /* AGC1 byte 2 */
#define R22_AGC13 0x22 /* AGC1 byte 3 */
#define R23_AGC21 0x23 /* AGC2 byte 1 */
#define R24_AGC22 0x24 /* AGC2 byte 2 */
#define R25_AAGC 0x25 /* Analog AGC byte */
#define R26_RC 0x26 /* RC byte */
#define R27_RSSI 0x27 /* RSSI byte */
#define R28_IRCAL1 0x28 /* IR CAL byte 1 */
#define R29_IRCAL2 0x29 /* IR CAL byte 2 */
#define R2A_IRCAL3 0x2a /* IR CAL byte 3 */
#define R2B_IRCAL4 0x2b /* IR CAL byte 4 */
#define R2C_RFCAL1 0x2c /* RF CAL byte 1 */
#define R2D_RFCAL2 0x2d /* RF CAL byte 2 */
#define R2E_RFCAL3 0x2e /* RF CAL byte 3 */
#define R2F_RFCAL4 0x2f /* RF CAL byte 4 */
#define R30_RFCAL5 0x30 /* RF CAL byte 5 */
#define R31_RFCAL6 0x31 /* RF CAL byte 6 */
#define R32_RFCAL7 0x32 /* RF CAL byte 7 */
#define R33_RFCAL8 0x33 /* RF CAL byte 8 */
#define R34_RFCAL9 0x34 /* RF CAL byte 9 */
#define R35_RFCAL10 0x35 /* RF CAL byte 10 */
#define R36_RFCALRAM1 0x36 /* RF CAL RAM byte 1 */
#define R37_RFCALRAM2 0x37 /* RF CAL RAM byte 2 */
#define R38_MARGIN 0x38 /* Margin byte */
#define R39_FMAX1 0x39 /* Fmax byte 1 */
#define R3A_FMAX2 0x3a /* Fmax byte 2 */
#define TDA18218_NUM_REGS 59
struct tda18218_priv {
struct tda18218_config *cfg;
struct i2c_adapter *i2c;
u8 regs[TDA18218_NUM_REGS];
};
#endif

View file

@ -193,25 +193,51 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
unsigned char *regs = priv->tda18271_regs;
unsigned char buf[TDA18271_NUM_REGS + 1];
struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0,
.buf = buf, .len = len + 1 };
int i, ret;
.buf = buf };
int i, ret = 1, max;
BUG_ON((len == 0) || (idx + len > sizeof(buf)));
buf[0] = idx;
for (i = 1; i <= len; i++)
buf[i] = regs[idx - 1 + i];
switch (priv->small_i2c) {
case TDA18271_03_BYTE_CHUNK_INIT:
max = 3;
break;
case TDA18271_08_BYTE_CHUNK_INIT:
max = 8;
break;
case TDA18271_16_BYTE_CHUNK_INIT:
max = 16;
break;
case TDA18271_39_BYTE_CHUNK_INIT:
default:
max = 39;
}
tda18271_i2c_gate_ctrl(fe, 1);
while (len) {
if (max > len)
max = len;
/* write registers */
ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
buf[0] = idx;
for (i = 1; i <= max; i++)
buf[i] = regs[idx - 1 + i];
msg.len = max + 1;
/* write registers */
ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
if (ret != 1)
break;
idx += max;
len -= max;
}
tda18271_i2c_gate_ctrl(fe, 0);
if (ret != 1)
tda_err("ERROR: idx = 0x%x, len = %d, "
"i2c_transfer returned: %d\n", idx, len, ret);
"i2c_transfer returned: %d\n", idx, max, ret);
return (ret == 1 ? 0 : ret);
}
@ -326,24 +352,7 @@ int tda18271_init_regs(struct dvb_frontend *fe)
regs[R_EB22] = 0x48;
regs[R_EB23] = 0xb0;
switch (priv->small_i2c) {
case TDA18271_08_BYTE_CHUNK_INIT:
tda18271_write_regs(fe, 0x00, 0x08);
tda18271_write_regs(fe, 0x08, 0x08);
tda18271_write_regs(fe, 0x10, 0x08);
tda18271_write_regs(fe, 0x18, 0x08);
tda18271_write_regs(fe, 0x20, 0x07);
break;
case TDA18271_16_BYTE_CHUNK_INIT:
tda18271_write_regs(fe, 0x00, 0x10);
tda18271_write_regs(fe, 0x10, 0x10);
tda18271_write_regs(fe, 0x20, 0x07);
break;
case TDA18271_39_BYTE_CHUNK_INIT:
default:
tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
break;
}
tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
/* setup agc1 gain */
regs[R_EB17] = 0x00;

View file

@ -1156,7 +1156,6 @@ static int tda18271_get_id(struct dvb_frontend *fe)
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
char *name;
int ret = 0;
mutex_lock(&priv->lock);
tda18271_read_regs(fe);
@ -1172,17 +1171,16 @@ static int tda18271_get_id(struct dvb_frontend *fe)
priv->id = TDA18271HDC2;
break;
default:
name = "Unknown device";
ret = -EINVAL;
break;
tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n",
regs[R_ID], i2c_adapter_id(priv->i2c_props.adap),
priv->i2c_props.addr);
return -EINVAL;
}
tda_info("%s detected @ %d-%04x%s\n", name,
i2c_adapter_id(priv->i2c_props.adap),
priv->i2c_props.addr,
(0 == ret) ? "" : ", device not supported.");
tda_info("%s detected @ %d-%04x\n", name,
i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr);
return ret;
return 0;
}
static int tda18271_setup_configuration(struct dvb_frontend *fe,

View file

@ -80,8 +80,9 @@ enum tda18271_output_options {
enum tda18271_small_i2c {
TDA18271_39_BYTE_CHUNK_INIT = 0,
TDA18271_16_BYTE_CHUNK_INIT = 1,
TDA18271_08_BYTE_CHUNK_INIT = 2,
TDA18271_16_BYTE_CHUNK_INIT = 16,
TDA18271_08_BYTE_CHUNK_INIT = 8,
TDA18271_03_BYTE_CHUNK_INIT = 3,
};
struct tda18271_config {

View file

@ -1042,7 +1042,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct xc5000_config *cfg)
const struct xc5000_config *cfg)
{
struct xc5000_priv *priv = NULL;
int instance;

View file

@ -53,11 +53,11 @@ struct xc5000_config {
(defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct xc5000_config *cfg);
const struct xc5000_config *cfg);
#else
static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct xc5000_config *cfg)
const struct xc5000_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;

View file

@ -245,9 +245,6 @@ int flexcop_i2c_init(struct flexcop_device *fc)
i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
fc->fc_i2c_adap[0].i2c_adap.class =
fc->fc_i2c_adap[1].i2c_adap.class =
fc->fc_i2c_adap[2].i2c_adap.class = I2C_CLASS_TV_DIGITAL;
fc->fc_i2c_adap[0].i2c_adap.algo =
fc->fc_i2c_adap[1].i2c_adap.algo =
fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;

View file

@ -862,7 +862,6 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
i2c_set_adapdata(&dev->i2c_adap, dev);
strcpy(dev->i2c_adap.name, DRIVER_NAME);
dev->i2c_adap.owner = THIS_MODULE;
dev->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
dev->i2c_adap.dev.parent = &pdev->dev;
dev->i2c_adap.algo = &dm1105_algo;
dev->i2c_adap.algo_data = dev;

View file

@ -702,7 +702,7 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
kthread_stop(fepriv->thread);
init_MUTEX (&fepriv->sem);
sema_init(&fepriv->sem, 1);
fepriv->state = FESTATE_IDLE;
/* paranoia check in case a signal arrived */
@ -2062,7 +2062,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
}
fepriv = fe->frontend_priv;
init_MUTEX (&fepriv->sem);
sema_init(&fepriv->sem, 1);
init_waitqueue_head (&fepriv->wait_queue);
init_waitqueue_head (&fepriv->events.wait_queue);
mutex_init(&fepriv->events.mtx);

View file

@ -260,7 +260,7 @@ struct dvb_frontend_ops {
int (*init)(struct dvb_frontend* fe);
int (*sleep)(struct dvb_frontend* fe);
int (*write)(struct dvb_frontend* fe, u8* buf, int len);
int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
/* if this is set, it overrides the default swzigzag */
int (*tune)(struct dvb_frontend* fe,

View file

@ -314,6 +314,8 @@ config DVB_USB_AF9015
select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
@ -346,3 +348,13 @@ config DVB_USB_AZ6027
select DVB_STB6100 if !DVB_FE_CUSTOMISE
help
Say Y here to support the AZ6027 device
config DVB_USB_LME2510
tristate "LME DM04/QQBOX DVB-S USB2.0 support"
depends on DVB_USB
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
select DVB_STV0288 if !DVB_FE_CUSTOMISE
select DVB_IX2505V if !DVB_FE_CUSTOMISE
help
Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .

View file

@ -88,6 +88,9 @@ obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
dvb-usb-az6027-objs = az6027.o
obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
dvb-usb-lmedm04-objs = lmedm04.o
obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
EXTRA_CFLAGS += -Idrivers/media/common/tuners

View file

@ -31,6 +31,8 @@
#include "tda18271.h"
#include "mxl5005s.h"
#include "mc44s803.h"
#include "tda18218.h"
#include "mxl5007t.h"
static int dvb_usb_af9015_debug;
module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
@ -205,10 +207,16 @@ static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
return af9015_write_regs(d, addr, &val, 1);
}
static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
{
struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
val};
return af9015_ctrl_msg(d, &req);
}
static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
{
struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val};
return af9015_ctrl_msg(d, &req);
return af9015_read_regs(d, addr, val, 1);
}
static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
@ -241,7 +249,7 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int ret = 0, i = 0;
u16 addr;
u8 mbox, addr_len;
u8 uninitialized_var(mbox), addr_len;
struct req_t req;
/* TODO: implement bus lock
@ -280,7 +288,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
} else {
addr = msg[i].buf[0];
addr_len = 1;
mbox = 0;
/* mbox is don't care in that case */
}
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
@ -494,7 +502,8 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
/* wait 2nd demodulator ready */
msleep(100);
ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val);
ret = af9015_read_reg_i2c(d,
af9015_af9013_config[1].demod_address, 0x98be, &val);
if (ret)
goto error;
else
@ -597,37 +606,6 @@ free:
return ret;
}
static int af9015_download_ir_table(struct dvb_usb_device *d)
{
int i, packets = 0, ret;
u16 addr = 0x9a56; /* ir-table start address */
struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL};
u8 *data = NULL;
deb_info("%s:\n", __func__);
data = af9015_config.ir_table;
packets = af9015_config.ir_table_size;
/* no remote */
if (!packets)
goto exit;
/* load remote ir-table */
for (i = 0; i < packets; i++) {
req.addr = addr + i;
req.data = &data[i];
ret = af9015_ctrl_msg(d, &req);
if (ret) {
err("ir-table download failed at packet %d with " \
"code %d", i, ret);
return ret;
}
}
exit:
return 0;
}
static int af9015_init(struct dvb_usb_device *d)
{
int ret;
@ -637,10 +615,6 @@ static int af9015_init(struct dvb_usb_device *d)
if (ret)
goto error;
ret = af9015_download_ir_table(d);
if (ret)
goto error;
error:
return ret;
}
@ -733,125 +707,102 @@ error:
return ret;
}
struct af9015_setup {
struct af9015_rc_setup {
unsigned int id;
struct ir_scancode *rc_key_map;
unsigned int rc_key_map_size;
u8 *ir_table;
unsigned int ir_table_size;
char *rc_codes;
};
static const struct af9015_setup *af9015_setup_match(unsigned int id,
const struct af9015_setup *table)
static char *af9015_rc_setup_match(unsigned int id,
const struct af9015_rc_setup *table)
{
for (; table->rc_key_map; table++)
for (; table->rc_codes; table++)
if (table->id == id)
return table;
return table->rc_codes;
return NULL;
}
static const struct af9015_setup af9015_setup_modparam[] = {
{ AF9015_REMOTE_A_LINK_DTU_M,
ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
{ AF9015_REMOTE_MYGICTV_U718,
ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
{ AF9015_REMOTE_DIGITTRADE_DVB_T,
ir_codes_af9015_table_digittrade, ARRAY_SIZE(ir_codes_af9015_table_digittrade),
af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
{ AF9015_REMOTE_AVERMEDIA_KS,
ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
{ AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
{ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
{ AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
{ AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
{ AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
{ }
};
/* don't add new entries here anymore, use hashes instead */
static const struct af9015_setup af9015_setup_usbids[] = {
{ USB_VID_LEADTEK,
ir_codes_af9015_table_leadtek, ARRAY_SIZE(ir_codes_af9015_table_leadtek),
af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
{ USB_VID_VISIONPLUS,
ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
{ USB_VID_KWORLD_2, /* TODO: use correct rc keys */
ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
{ USB_VID_AVERMEDIA,
ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
{ USB_VID_MSI_2,
ir_codes_af9015_table_msi_digivox_iii, ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii),
af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
{ 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
{ 0xa3703d00, RC_MAP_ALINK_DTU_M },
{ 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
{ }
};
static const struct af9015_setup af9015_setup_hashes[] = {
{ 0xb8feb708,
ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
{ 0xa3703d00,
ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
{ 0x9b7dc64e,
ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
{ (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
RC_MAP_TERRATEC_SLIM },
{ (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700,
RC_MAP_AZUREWAVE_AD_TU700 },
{ (USB_VID_VISIONPLUS << 16) + USB_PID_TINYTWIN,
RC_MAP_AZUREWAVE_AD_TU700 },
{ (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III,
RC_MAP_MSI_DIGIVOX_III },
{ (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD,
RC_MAP_LEADTEK_Y04G0051 },
{ (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X,
RC_MAP_AVERMEDIA_M135A },
{ (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT,
RC_MAP_TREKSTOR },
{ (USB_VID_KWORLD_2 << 16) + USB_PID_TINYTWIN_2,
RC_MAP_DIGITALNOW_TINYTWIN },
{ (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3,
RC_MAP_DIGITALNOW_TINYTWIN },
{ }
};
static void af9015_set_remote_config(struct usb_device *udev,
struct dvb_usb_device_properties *props)
{
const struct af9015_setup *table = NULL;
u16 vid = le16_to_cpu(udev->descriptor.idVendor);
u16 pid = le16_to_cpu(udev->descriptor.idProduct);
if (dvb_usb_af9015_remote) {
/* load remote defined as module param */
table = af9015_setup_match(dvb_usb_af9015_remote,
af9015_setup_modparam);
} else {
u16 vendor = le16_to_cpu(udev->descriptor.idVendor);
/* try to load remote based module param */
props->rc.core.rc_codes = af9015_rc_setup_match(
dvb_usb_af9015_remote, af9015_rc_setup_modparam);
table = af9015_setup_match(af9015_config.eeprom_sum,
af9015_setup_hashes);
/* try to load remote based eeprom hash */
if (!props->rc.core.rc_codes)
props->rc.core.rc_codes = af9015_rc_setup_match(
af9015_config.eeprom_sum, af9015_rc_setup_hashes);
if (!table && vendor == USB_VID_AFATECH) {
/* Check USB manufacturer and product strings and try
to determine correct remote in case of chip vendor
reference IDs are used.
DO NOT ADD ANYTHING NEW HERE. Use hashes instead.
*/
char manufacturer[10];
memset(manufacturer, 0, sizeof(manufacturer));
usb_string(udev, udev->descriptor.iManufacturer,
manufacturer, sizeof(manufacturer));
if (!strcmp("MSI", manufacturer)) {
/* iManufacturer 1 MSI
iProduct 2 MSI K-VOX */
table = af9015_setup_match(
AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
af9015_setup_modparam);
} else if (udev->descriptor.idProduct ==
cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
table = &(const struct af9015_setup){ 0,
ir_codes_af9015_table_trekstor,
ARRAY_SIZE(ir_codes_af9015_table_trekstor),
af9015_ir_table_trekstor,
ARRAY_SIZE(af9015_ir_table_trekstor)
};
}
} else if (!table)
table = af9015_setup_match(vendor, af9015_setup_usbids);
/* try to load remote based USB ID */
if (!props->rc.core.rc_codes)
props->rc.core.rc_codes = af9015_rc_setup_match(
(vid << 16) + pid, af9015_rc_setup_usbids);
/* try to load remote based USB iManufacturer string */
if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) {
/* Check USB manufacturer and product strings and try
to determine correct remote in case of chip vendor
reference IDs are used.
DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
char manufacturer[10];
memset(manufacturer, 0, sizeof(manufacturer));
usb_string(udev, udev->descriptor.iManufacturer,
manufacturer, sizeof(manufacturer));
if (!strcmp("MSI", manufacturer)) {
/* iManufacturer 1 MSI
iProduct 2 MSI K-VOX */
props->rc.core.rc_codes = af9015_rc_setup_match(
AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
af9015_rc_setup_modparam);
}
}
if (table) {
props->rc.legacy.rc_key_map = table->rc_key_map;
props->rc.legacy.rc_key_map_size = table->rc_key_map_size;
af9015_config.ir_table = table->ir_table;
af9015_config.ir_table_size = table->ir_table_size;
}
/* finally load "empty" just for leaving IR receiver enabled */
if (!props->rc.core.rc_codes)
props->rc.core.rc_codes = RC_MAP_EMPTY;
return;
}
static int af9015_read_config(struct usb_device *udev)
@ -877,10 +828,9 @@ static int af9015_read_config(struct usb_device *udev)
deb_info("%s: IR mode:%d\n", __func__, val);
for (i = 0; i < af9015_properties_count; i++) {
if (val == AF9015_IR_MODE_DISABLED) {
af9015_properties[i].rc.legacy.rc_key_map = NULL;
af9015_properties[i].rc.legacy.rc_key_map_size = 0;
} else
if (val == AF9015_IR_MODE_DISABLED)
af9015_properties[i].rc.core.rc_codes = NULL;
else
af9015_set_remote_config(udev, &af9015_properties[i]);
}
@ -992,20 +942,19 @@ static int af9015_read_config(struct usb_device *udev)
case AF9013_TUNER_MT2060_2:
case AF9013_TUNER_TDA18271:
case AF9013_TUNER_QT1010A:
case AF9013_TUNER_TDA18218:
af9015_af9013_config[i].rf_spec_inv = 1;
break;
case AF9013_TUNER_MXL5003D:
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
case AF9013_TUNER_MXL5007T:
af9015_af9013_config[i].rf_spec_inv = 0;
break;
case AF9013_TUNER_MC44S803:
af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
af9015_af9013_config[i].rf_spec_inv = 1;
break;
case AF9013_TUNER_TDA18218:
warn("tuner NXP TDA18218 not supported yet");
return -ENODEV;
default:
warn("tuner id:%d not supported, please report!", val);
return -ENODEV;
@ -1020,9 +969,13 @@ error:
err("eeprom read failed:%d", ret);
/* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
content :-( Override some wrong values here. */
content :-( Override some wrong values here. Ditto for the
AVerTV Red HD+ (A850T) device. */
if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
le16_to_cpu(udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) {
((le16_to_cpu(udev->descriptor.idProduct) ==
USB_PID_AVERMEDIA_A850) ||
(le16_to_cpu(udev->descriptor.idProduct) ==
USB_PID_AVERMEDIA_A850T))) {
deb_info("%s: AverMedia A850: overriding config\n", __func__);
/* disable dual mode */
af9015_config.dual_mode = 0;
@ -1059,36 +1012,53 @@ static int af9015_identify_state(struct usb_device *udev,
return ret;
}
static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
static int af9015_rc_query(struct dvb_usb_device *d)
{
u8 buf[8];
struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
int i, ret;
struct af9015_state *priv = d->priv;
int ret;
u8 buf[16];
memset(buf, 0, sizeof(buf));
ret = af9015_ctrl_msg(d, &req);
/* read registers needed to detect remote controller code */
ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
if (ret)
return ret;
goto error;
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
if (buf[14] || buf[15]) {
deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__,
buf[12], buf[13], buf[14], buf[15]);
for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
rc5_data(&keymap[i]) == buf[2]) {
*event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
break;
/* clean IR code from mem */
ret = af9015_write_regs(d, 0x98e5, "\x00\x00\x00\x00", 4);
if (ret)
goto error;
if (buf[14] == (u8) ~buf[15]) {
if (buf[12] == (u8) ~buf[13]) {
/* NEC */
priv->rc_keycode = buf[12] << 8 | buf[14];
} else {
/* NEC extended*/
priv->rc_keycode = buf[12] << 16 |
buf[13] << 8 | buf[14];
}
ir_keydown(d->rc_input_dev, priv->rc_keycode, 0);
} else {
priv->rc_keycode = 0; /* clear just for sure */
}
} else if (priv->rc_repeat != buf[6] || buf[0]) {
deb_rc("%s: key repeated\n", __func__);
ir_keydown(d->rc_input_dev, priv->rc_keycode, 0);
} else {
deb_rc("%s: no key press\n", __func__);
}
if (!buf[1])
deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
__func__, buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7]);
return 0;
priv->rc_repeat = buf[6];
error:
if (ret)
err("%s: failed:%d", __func__, ret);
return ret;
}
/* init 2nd I2C adapter */
@ -1100,11 +1070,6 @@ static int af9015_i2c_init(struct dvb_usb_device *d)
strncpy(state->i2c_adap.name, d->desc->name,
sizeof(state->i2c_adap.name));
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
state->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
#else
state->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
#endif
state->i2c_adap.algo = d->props.i2c_algo;
state->i2c_adap.algo_data = NULL;
state->i2c_adap.dev.parent = &d->udev->dev;
@ -1166,7 +1131,7 @@ static struct qt1010_config af9015_qt1010_config = {
static struct tda18271_config af9015_tda18271_config = {
.gate = TDA18271_GATE_DIGITAL,
.small_i2c = 1,
.small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
};
static struct mxl5005s_config af9015_mxl5003_config = {
@ -1208,12 +1173,22 @@ static struct mc44s803_config af9015_mc44s803_config = {
.dig_out = 1,
};
static struct tda18218_config af9015_tda18218_config = {
.i2c_address = 0xc0,
.i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
};
static struct mxl5007t_config af9015_mxl5007t_config = {
.xtal_freq_hz = MxL_XTAL_24_MHZ,
.if_freq_hz = MxL_IF_4_57_MHZ,
};
static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
{
struct af9015_state *state = adap->dev->priv;
struct i2c_adapter *i2c_adap;
int ret;
deb_info("%s: \n", __func__);
deb_info("%s:\n", __func__);
/* select I2C adapter */
if (adap->id == 0)
@ -1238,6 +1213,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap,
&af9015_tda18271_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_TDA18218:
ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap,
&af9015_tda18218_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MXL5003D:
ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
&af9015_mxl5003_config) == NULL ? -ENODEV : 0;
@ -1255,6 +1234,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
&af9015_mc44s803_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_MXL5007T:
ret = dvb_attach(mxl5007t_attach, adap->fe, i2c_adap,
0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_UNKNOWN:
default:
ret = -ENODEV;
@ -1300,10 +1283,16 @@ static struct usb_device_id af9015_usb_table[] = {
/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
{USB_DEVICE(USB_VID_TERRATEC,
USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
{USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
#define AF9015_RC_INTERVAL 500
static struct dvb_usb_device_properties af9015_properties[] = {
{
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@ -1354,14 +1343,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
.rc.legacy = {
.rc.core = {
.protocol = IR_TYPE_NEC,
.module_name = "af9015",
.rc_query = af9015_rc_query,
.rc_interval = 150,
.rc_interval = AF9015_RC_INTERVAL,
.rc_props = {
.allowed_protos = IR_TYPE_NEC,
},
},
.i2c_algo = &af9015_i2c_algo,
.num_device_descs = 9, /* max 9 */
.num_device_descs = 12, /* check max from dvb-usb.h */
.devices = {
{
.name = "Afatech AF9015 DVB-T USB2.0 stick",
@ -1389,7 +1383,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
{
.name = "DigitalNow TinyTwin DVB-T Receiver",
.cold_ids = {&af9015_usb_table[5],
&af9015_usb_table[28], NULL},
&af9015_usb_table[28],
&af9015_usb_table[36], NULL},
.warm_ids = {NULL},
},
{
@ -1413,6 +1408,21 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.cold_ids = {&af9015_usb_table[9], NULL},
.warm_ids = {NULL},
},
{
.name = "TerraTec Cinergy T Stick RC",
.cold_ids = {&af9015_usb_table[33], NULL},
.warm_ids = {NULL},
},
{
.name = "TerraTec Cinergy T Stick Dual RC",
.cold_ids = {&af9015_usb_table[34], NULL},
.warm_ids = {NULL},
},
{
.name = "AverMedia AVerTV Red HD+ (A850T)",
.cold_ids = {&af9015_usb_table[35], NULL},
.warm_ids = {NULL},
},
}
}, {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@ -1463,14 +1473,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
.rc.legacy = {
.rc.core = {
.protocol = IR_TYPE_NEC,
.module_name = "af9015",
.rc_query = af9015_rc_query,
.rc_interval = 150,
.rc_interval = AF9015_RC_INTERVAL,
.rc_props = {
.allowed_protos = IR_TYPE_NEC,
},
},
.i2c_algo = &af9015_i2c_algo,
.num_device_descs = 9, /* max 9 */
.num_device_descs = 9, /* check max from dvb-usb.h */
.devices = {
{
.name = "Xtensions XD-380",
@ -1572,14 +1587,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
.rc.legacy = {
.rc.core = {
.protocol = IR_TYPE_NEC,
.module_name = "af9015",
.rc_query = af9015_rc_query,
.rc_interval = 150,
.rc_interval = AF9015_RC_INTERVAL,
.rc_props = {
.allowed_protos = IR_TYPE_NEC,
},
},
.i2c_algo = &af9015_i2c_algo,
.num_device_descs = 9, /* max 9 */
.num_device_descs = 9, /* check max from dvb-usb.h */
.devices = {
{
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@ -1672,7 +1692,7 @@ static int af9015_usb_probe(struct usb_interface *intf,
static void af9015_i2c_exit(struct dvb_usb_device *d)
{
struct af9015_state *state = d->priv;
deb_info("%s: \n", __func__);
deb_info("%s:\n", __func__);
/* remove 2nd I2C adapter */
if (d->state & DVB_USB_STATE_I2C)
@ -1682,7 +1702,7 @@ static void af9015_i2c_exit(struct dvb_usb_device *d)
static void af9015_usb_device_exit(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
deb_info("%s: \n", __func__);
deb_info("%s:\n", __func__);
/* remove 2nd I2C adapter */
if (d != NULL && d->desc != NULL)

View file

@ -100,6 +100,8 @@ enum af9015_ir_mode {
struct af9015_state {
struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
u8 rc_repeat;
u32 rc_keycode;
};
struct af9015_config {
@ -108,8 +110,6 @@ struct af9015_config {
u16 firmware_size;
u16 firmware_checksum;
u32 eeprom_sum;
u8 *ir_table;
u16 ir_table_size;
};
enum af9015_remote {
@ -121,735 +121,4 @@ enum af9015_remote {
/* 5 */ AF9015_REMOTE_AVERMEDIA_KS,
};
/* LeadTek - Y04G0051 */
/* Leadtek WinFast DTV Dongle Gold */
static struct ir_scancode ir_codes_af9015_table_leadtek[] = {
{ 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_OK },
{ 0x004f, KEY_RIGHT },
{ 0x0050, KEY_LEFT },
{ 0x0051, KEY_DOWN },
{ 0x0052, KEY_UP },
{ 0x011a, KEY_POWER2 },
{ 0x04b4, KEY_TV },
{ 0x04b3, KEY_RED },
{ 0x04b2, KEY_GREEN },
{ 0x04b1, KEY_YELLOW },
{ 0x04b0, KEY_BLUE },
{ 0x003d, KEY_TEXT },
{ 0x0113, KEY_SLEEP },
{ 0x0010, KEY_MUTE },
{ 0x0105, KEY_ESC },
{ 0x0009, KEY_SCREEN },
{ 0x010f, KEY_MENU },
{ 0x003f, KEY_CHANNEL },
{ 0x0013, KEY_REWIND },
{ 0x0012, KEY_PLAY },
{ 0x0011, KEY_FASTFORWARD },
{ 0x0005, KEY_PREVIOUS },
{ 0x0029, KEY_STOP },
{ 0x002b, KEY_NEXT },
{ 0x0041, KEY_EPG },
{ 0x0019, KEY_VIDEO },
{ 0x0016, KEY_AUDIO },
{ 0x0037, KEY_DOT },
{ 0x002a, KEY_AGAIN },
{ 0x002c, KEY_CAMERA },
{ 0x003c, KEY_NEW },
{ 0x0115, KEY_RECORD },
{ 0x010b, KEY_TIME },
{ 0x0043, KEY_VOLUMEUP },
{ 0x0042, KEY_VOLUMEDOWN },
{ 0x004b, KEY_CHANNELUP },
{ 0x004e, KEY_CHANNELDOWN },
};
static u8 af9015_ir_table_leadtek[] = {
0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00, /* KEY_POWER2 */
0x03, 0xfc, 0x56, 0xa9, 0xb4, 0x04, 0x00, /* KEY_TV */
0x03, 0xfc, 0x4b, 0xb4, 0xb3, 0x04, 0x00, /* KEY_RED */
0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00, /* KEY_GREEN */
0x03, 0xfc, 0x4d, 0xb2, 0xb1, 0x04, 0x00, /* KEY_YELLOW */
0x03, 0xfc, 0x4e, 0xb1, 0xb0, 0x04, 0x00, /* KEY_BLUE */
0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00, /* KEY_TEXT */
0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00, /* KEY_SLEEP */
0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00, /* KEY_MUTE */
0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00, /* KEY_ESC */
0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00, /* KEY_STOP (1)*/
0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00, /* KEY_UP */
0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00, /* KEY_SCREEN */
0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00, /* KEY_LEFT */
0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00, /* KEY_OK (1) */
0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00, /* KEY_RIGHT */
0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00, /* KEY_MENU */
0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00, /* KEY_DOWN */
0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00, /* KEY_CHANNEL */
0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00, /* KEY_REWIND */
0x03, 0xfc, 0x43, 0xbc, 0x12, 0x00, 0x00, /* KEY_PLAY */
0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00, /* KEY_FASTFORWARD */
0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00, /* KEY_VIDEO (1) */
0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00, /* KEY_PREVIOUS */
0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00, /* KEY_STOP (2) */
0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00, /* KEY_NEXT */
0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00, /* KEY_EPG */
0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00, /* KEY_1 */
0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00, /* KEY_2 */
0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00, /* KEY_3 */
0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00, /* KEY_VIDEO (2) */
0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00, /* KEY_4 */
0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00, /* KEY_5 */
0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00, /* KEY_6 */
0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00, /* KEY_AUDIO */
0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00, /* KEY_7 */
0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00, /* KEY_8 */
0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00, /* KEY_9 */
0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* KEY_OK (2) */
0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00, /* KEY_DOT */
0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00, /* KEY_0 */
0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00, /* KEY_AGAIN */
0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00, /* KEY_CAMERA */
0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00, /* KEY_NEW */
0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00, /* KEY_RECORD */
0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00, /* KEY_TIME */
0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00, /* KEY_VOLUMEUP */
0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00, /* KEY_VOLUMEDOWN */
0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00, /* KEY_CHANNELUP */
0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00, /* KEY_CHANNELDOWN */
};
/* TwinHan AzureWave AD-TU700(704J) */
static struct ir_scancode ir_codes_af9015_table_twinhan[] = {
{ 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 */
{ 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[] = {
0x00, 0xff, 0x16, 0xe9, 0x3f, 0x05, 0x00,
0x00, 0xff, 0x07, 0xf8, 0x16, 0x01, 0x00,
0x00, 0xff, 0x14, 0xeb, 0x11, 0x01, 0x00,
0x00, 0xff, 0x1a, 0xe5, 0x4d, 0x00, 0x00,
0x00, 0xff, 0x4c, 0xb3, 0x17, 0x00, 0x00,
0x00, 0xff, 0x12, 0xed, 0x11, 0x00, 0x00,
0x00, 0xff, 0x40, 0xbf, 0x0c, 0x00, 0x00,
0x00, 0xff, 0x11, 0xee, 0x4a, 0x00, 0x00,
0x00, 0xff, 0x54, 0xab, 0x13, 0x00, 0x00,
0x00, 0xff, 0x41, 0xbe, 0x15, 0x01, 0x00,
0x00, 0xff, 0x42, 0xbd, 0x0e, 0x01, 0x00,
0x00, 0xff, 0x43, 0xbc, 0x17, 0x01, 0x00,
0x00, 0xff, 0x50, 0xaf, 0x0f, 0x01, 0x00,
0x00, 0xff, 0x4d, 0xb2, 0x1d, 0x00, 0x00,
0x00, 0xff, 0x47, 0xb8, 0x13, 0x01, 0x00,
0x00, 0xff, 0x05, 0xfa, 0x4b, 0x00, 0x00,
0x00, 0xff, 0x02, 0xfd, 0x4e, 0x00, 0x00,
0x00, 0xff, 0x0e, 0xf1, 0x06, 0x00, 0x00,
0x00, 0xff, 0x1e, 0xe1, 0x52, 0x02, 0x00,
0x00, 0xff, 0x0a, 0xf5, 0x51, 0x02, 0x00,
0x00, 0xff, 0x10, 0xef, 0x10, 0x00, 0x00,
0x00, 0xff, 0x49, 0xb6, 0x19, 0x01, 0x00,
0x00, 0xff, 0x15, 0xea, 0x27, 0x00, 0x00,
0x00, 0xff, 0x03, 0xfc, 0x1e, 0x00, 0x00,
0x00, 0xff, 0x01, 0xfe, 0x1f, 0x00, 0x00,
0x00, 0xff, 0x06, 0xf9, 0x20, 0x00, 0x00,
0x00, 0xff, 0x09, 0xf6, 0x21, 0x00, 0x00,
0x00, 0xff, 0x1d, 0xe2, 0x22, 0x00, 0x00,
0x00, 0xff, 0x1f, 0xe0, 0x23, 0x00, 0x00,
0x00, 0xff, 0x0d, 0xf2, 0x24, 0x00, 0x00,
0x00, 0xff, 0x19, 0xe6, 0x25, 0x00, 0x00,
0x00, 0xff, 0x1b, 0xe4, 0x26, 0x00, 0x00,
0x00, 0xff, 0x00, 0xff, 0x2b, 0x00, 0x00,
0x00, 0xff, 0x4a, 0xb5, 0x4c, 0x00, 0x00,
0x00, 0xff, 0x4b, 0xb4, 0x52, 0x00, 0x00,
0x00, 0xff, 0x51, 0xae, 0x51, 0x00, 0x00,
0x00, 0xff, 0x52, 0xad, 0x4f, 0x00, 0x00,
0x00, 0xff, 0x4e, 0xb1, 0x50, 0x00, 0x00,
0x00, 0xff, 0x0c, 0xf3, 0x29, 0x00, 0x00,
0x00, 0xff, 0x4f, 0xb0, 0x28, 0x00, 0x00,
0x00, 0xff, 0x13, 0xec, 0x2a, 0x00, 0x00,
0x00, 0xff, 0x17, 0xe8, 0x19, 0x00, 0x00,
0x00, 0xff, 0x04, 0xfb, 0x0f, 0x00, 0x00,
0x00, 0xff, 0x48, 0xb7, 0x0e, 0x00, 0x00,
0x00, 0xff, 0x0f, 0xf0, 0x04, 0x00, 0x00,
0x00, 0xff, 0x1c, 0xe3, 0x08, 0x00, 0x00,
0x00, 0xff, 0x18, 0xe7, 0x15, 0x02, 0x00,
0x00, 0xff, 0x53, 0xac, 0x0a, 0x02, 0x00,
0x00, 0xff, 0x5e, 0xa1, 0x1c, 0x02, 0x00,
0x00, 0xff, 0x5f, 0xa0, 0x05, 0x02, 0x00,
};
/* A-Link DTU(m) */
static struct ir_scancode ir_codes_af9015_table_a_link[] = {
{ 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[] = {
0x08, 0xf7, 0x12, 0xed, 0x45, 0x05, 0x00, /* power */
0x08, 0xf7, 0x1a, 0xe5, 0x41, 0x00, 0x00, /* mute */
0x08, 0xf7, 0x01, 0xfe, 0x1e, 0x00, 0x00, /* 1 */
0x08, 0xf7, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
0x08, 0xf7, 0x03, 0xfc, 0x24, 0x00, 0x00, /* 7 */
0x08, 0xf7, 0x05, 0xfa, 0x28, 0x04, 0x00, /* zoom */
0x08, 0xf7, 0x00, 0xff, 0x43, 0x00, 0x00, /* volume up */
0x08, 0xf7, 0x16, 0xe9, 0x42, 0x00, 0x00, /* volume down */
0x08, 0xf7, 0x0f, 0xf0, 0x1f, 0x00, 0x00, /* 2 */
0x08, 0xf7, 0x0d, 0xf2, 0x22, 0x00, 0x00, /* 5 */
0x08, 0xf7, 0x1b, 0xe4, 0x25, 0x00, 0x00, /* 8 */
0x08, 0xf7, 0x06, 0xf9, 0x27, 0x00, 0x00, /* 0 */
0x08, 0xf7, 0x14, 0xeb, 0x2e, 0x00, 0x00, /* channel up */
0x08, 0xf7, 0x1d, 0xe2, 0x2d, 0x00, 0x00, /* channel down */
0x08, 0xf7, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
0x08, 0xf7, 0x18, 0xe7, 0x23, 0x00, 0x00, /* 6 */
0x08, 0xf7, 0x04, 0xfb, 0x26, 0x00, 0x00, /* 9 */
0x08, 0xf7, 0x07, 0xf8, 0x44, 0x00, 0x00, /* jump */
};
/* MSI DIGIVOX mini II V3.0 */
static struct ir_scancode ir_codes_af9015_table_msi[] = {
{ 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[] = {
0x03, 0xfc, 0x17, 0xe8, 0x45, 0x05, 0x00, /* power */
0x03, 0xfc, 0x0d, 0xf2, 0x51, 0x00, 0x00, /* down */
0x03, 0xfc, 0x03, 0xfc, 0x52, 0x00, 0x00, /* up */
0x03, 0xfc, 0x1a, 0xe5, 0x1e, 0x00, 0x00, /* 1 */
0x03, 0xfc, 0x02, 0xfd, 0x1f, 0x00, 0x00, /* 2 */
0x03, 0xfc, 0x04, 0xfb, 0x20, 0x00, 0x00, /* 3 */
0x03, 0xfc, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
0x03, 0xfc, 0x08, 0xf7, 0x22, 0x00, 0x00, /* 5 */
0x03, 0xfc, 0x1d, 0xe2, 0x23, 0x00, 0x00, /* 6 */
0x03, 0xfc, 0x11, 0xee, 0x24, 0x00, 0x00, /* 7 */
0x03, 0xfc, 0x0b, 0xf4, 0x25, 0x00, 0x00, /* 8 */
0x03, 0xfc, 0x10, 0xef, 0x26, 0x00, 0x00, /* 9 */
0x03, 0xfc, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
0x03, 0xfc, 0x14, 0xeb, 0x43, 0x00, 0x00, /* volume up */
0x03, 0xfc, 0x1f, 0xe0, 0x42, 0x00, 0x00, /* volume down */
0x03, 0xfc, 0x15, 0xea, 0x0f, 0x03, 0x00, /* channel up */
0x03, 0xfc, 0x05, 0xfa, 0x0e, 0x03, 0x00, /* channel down */
0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* enter */
};
/* MYGICTV U718 */
static struct ir_scancode ir_codes_af9015_table_mygictv[] = {
{ 0x003d, KEY_SWITCHVIDEOMODE },
/* TV / AV */
{ 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[] = {
0x02, 0xbd, 0x0c, 0xf3, 0x3d, 0x00, 0x00, /* TV / AV */
0x02, 0xbd, 0x14, 0xeb, 0x45, 0x05, 0x00, /* power */
0x02, 0xbd, 0x00, 0xff, 0x1e, 0x00, 0x00, /* 1 */
0x02, 0xbd, 0x01, 0xfe, 0x1f, 0x00, 0x00, /* 2 */
0x02, 0xbd, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
0x02, 0xbd, 0x03, 0xfc, 0x21, 0x00, 0x00, /* 4 */
0x02, 0xbd, 0x04, 0xfb, 0x22, 0x00, 0x00, /* 5 */
0x02, 0xbd, 0x05, 0xfa, 0x23, 0x00, 0x00, /* 6 */
0x02, 0xbd, 0x06, 0xf9, 0x24, 0x00, 0x00, /* 7 */
0x02, 0xbd, 0x07, 0xf8, 0x25, 0x00, 0x00, /* 8 */
0x02, 0xbd, 0x08, 0xf7, 0x26, 0x00, 0x00, /* 9 */
0x02, 0xbd, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
0x02, 0xbd, 0x0a, 0xf5, 0x41, 0x00, 0x00, /* mute */
0x02, 0xbd, 0x1c, 0xe3, 0x2a, 0x00, 0x00, /* esc */
0x02, 0xbd, 0x1f, 0xe0, 0x43, 0x00, 0x00, /* volume up */
0x02, 0xbd, 0x12, 0xed, 0x52, 0x00, 0x00, /* up arrow */
0x02, 0xbd, 0x11, 0xee, 0x50, 0x00, 0x00, /* left arrow */
0x02, 0xbd, 0x15, 0xea, 0x28, 0x00, 0x00, /* ok */
0x02, 0xbd, 0x10, 0xef, 0x4f, 0x00, 0x00, /* right arrow */
0x02, 0xbd, 0x13, 0xec, 0x51, 0x00, 0x00, /* down arrow */
0x02, 0xbd, 0x0e, 0xf1, 0x42, 0x00, 0x00, /* volume down */
0x02, 0xbd, 0x19, 0xe6, 0x15, 0x01, 0x00, /* record */
0x02, 0xbd, 0x1e, 0xe1, 0x13, 0x03, 0x00, /* play */
0x02, 0xbd, 0x16, 0xe9, 0x16, 0x01, 0x00, /* stop */
0x02, 0xbd, 0x0b, 0xf4, 0x28, 0x04, 0x00, /* yellow, min / max */
0x02, 0xbd, 0x0f, 0xf0, 0x3b, 0x00, 0x00, /* time shift */
0x02, 0xbd, 0x18, 0xe7, 0x2e, 0x00, 0x00, /* channel up */
0x02, 0xbd, 0x1a, 0xe5, 0x2d, 0x00, 0x00, /* channel down */
0x02, 0xbd, 0x17, 0xe8, 0x3e, 0x00, 0x00, /* snapshot */
0x02, 0xbd, 0x40, 0xbf, 0x13, 0x01, 0x00, /* pause */
0x02, 0xbd, 0x41, 0xbe, 0x09, 0x03, 0x00, /* FF >> */
0x02, 0xbd, 0x42, 0xbd, 0x07, 0x03, 0x00, /* FR << */
0x02, 0xbd, 0x43, 0xbc, 0x00, 0x00, 0x00, /* 'select' (?) */
0x02, 0xbd, 0x44, 0xbb, 0x16, 0x03, 0x00, /* shuffle */
0x02, 0xbd, 0x45, 0xba, 0x45, 0x03, 0x00, /* power */
};
/* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */
static u8 af9015_ir_table_kworld[] = {
0x86, 0x6b, 0x0c, 0xf3, 0x2e, 0x07, 0x00,
0x86, 0x6b, 0x16, 0xe9, 0x2d, 0x07, 0x00,
0x86, 0x6b, 0x1d, 0xe2, 0x37, 0x07, 0x00,
0x86, 0x6b, 0x00, 0xff, 0x1e, 0x07, 0x00,
0x86, 0x6b, 0x01, 0xfe, 0x1f, 0x07, 0x00,
0x86, 0x6b, 0x02, 0xfd, 0x20, 0x07, 0x00,
0x86, 0x6b, 0x03, 0xfc, 0x21, 0x07, 0x00,
0x86, 0x6b, 0x04, 0xfb, 0x22, 0x07, 0x00,
0x86, 0x6b, 0x05, 0xfa, 0x23, 0x07, 0x00,
0x86, 0x6b, 0x06, 0xf9, 0x24, 0x07, 0x00,
0x86, 0x6b, 0x07, 0xf8, 0x25, 0x07, 0x00,
0x86, 0x6b, 0x08, 0xf7, 0x26, 0x07, 0x00,
0x86, 0x6b, 0x09, 0xf6, 0x4d, 0x07, 0x00,
0x86, 0x6b, 0x0a, 0xf5, 0x4e, 0x07, 0x00,
0x86, 0x6b, 0x14, 0xeb, 0x4f, 0x07, 0x00,
0x86, 0x6b, 0x1e, 0xe1, 0x50, 0x07, 0x00,
0x86, 0x6b, 0x17, 0xe8, 0x52, 0x07, 0x00,
0x86, 0x6b, 0x1f, 0xe0, 0x51, 0x07, 0x00,
0x86, 0x6b, 0x0e, 0xf1, 0x0b, 0x07, 0x00,
0x86, 0x6b, 0x20, 0xdf, 0x0c, 0x07, 0x00,
0x86, 0x6b, 0x42, 0xbd, 0x0d, 0x07, 0x00,
0x86, 0x6b, 0x0b, 0xf4, 0x0e, 0x07, 0x00,
0x86, 0x6b, 0x43, 0xbc, 0x0f, 0x07, 0x00,
0x86, 0x6b, 0x10, 0xef, 0x10, 0x07, 0x00,
0x86, 0x6b, 0x21, 0xde, 0x11, 0x07, 0x00,
0x86, 0x6b, 0x13, 0xec, 0x12, 0x07, 0x00,
0x86, 0x6b, 0x11, 0xee, 0x13, 0x07, 0x00,
0x86, 0x6b, 0x12, 0xed, 0x14, 0x07, 0x00,
0x86, 0x6b, 0x19, 0xe6, 0x15, 0x07, 0x00,
0x86, 0x6b, 0x1a, 0xe5, 0x16, 0x07, 0x00,
0x86, 0x6b, 0x1b, 0xe4, 0x17, 0x07, 0x00,
0x86, 0x6b, 0x4b, 0xb4, 0x18, 0x07, 0x00,
0x86, 0x6b, 0x40, 0xbf, 0x19, 0x07, 0x00,
0x86, 0x6b, 0x44, 0xbb, 0x1a, 0x07, 0x00,
0x86, 0x6b, 0x41, 0xbe, 0x1b, 0x07, 0x00,
0x86, 0x6b, 0x22, 0xdd, 0x1c, 0x07, 0x00,
0x86, 0x6b, 0x15, 0xea, 0x1d, 0x07, 0x00,
0x86, 0x6b, 0x0f, 0xf0, 0x3f, 0x07, 0x00,
0x86, 0x6b, 0x1c, 0xe3, 0x40, 0x07, 0x00,
0x86, 0x6b, 0x4a, 0xb5, 0x41, 0x07, 0x00,
0x86, 0x6b, 0x48, 0xb7, 0x42, 0x07, 0x00,
0x86, 0x6b, 0x49, 0xb6, 0x43, 0x07, 0x00,
0x86, 0x6b, 0x18, 0xe7, 0x44, 0x07, 0x00,
0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
};
/* AverMedia Volar X */
static struct ir_scancode ir_codes_af9015_table_avermedia[] = {
{ 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 */
{ 0x050e, KEY_CHANNELUP }, /* CH UP */
{ 0x050d, KEY_CHANNELDOWN }, /* CH DOWN */
{ 0x0519, KEY_FIRST }, /* |<< / GREEN */
{ 0x0508, KEY_LAST }, /* >>| / BLUE */
};
static u8 af9015_ir_table_avermedia[] = {
0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00,
0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00,
0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00,
0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00,
0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00,
0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00,
0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00,
0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00,
0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00,
0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00,
0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00,
0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00,
0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00,
0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00,
0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00,
0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00,
0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00,
0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00,
0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00,
0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00,
0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00,
0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00,
0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00,
0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00,
0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00,
0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00,
0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00,
0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00,
0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00,
0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00,
0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00,
0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00,
0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00,
0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
};
static u8 af9015_ir_table_avermedia_ks[] = {
0x05, 0xfa, 0x01, 0xfe, 0x12, 0x05, 0x00,
0x05, 0xfa, 0x02, 0xfd, 0x0e, 0x05, 0x00,
0x05, 0xfa, 0x03, 0xfc, 0x0d, 0x05, 0x00,
0x05, 0xfa, 0x04, 0xfb, 0x2e, 0x05, 0x00,
0x05, 0xfa, 0x05, 0xfa, 0x2d, 0x05, 0x00,
0x05, 0xfa, 0x06, 0xf9, 0x10, 0x05, 0x00,
0x05, 0xfa, 0x07, 0xf8, 0x0f, 0x05, 0x00,
0x05, 0xfa, 0x08, 0xf7, 0x3d, 0x05, 0x00,
0x05, 0xfa, 0x09, 0xf6, 0x1e, 0x05, 0x00,
0x05, 0xfa, 0x0a, 0xf5, 0x1f, 0x05, 0x00,
0x05, 0xfa, 0x0b, 0xf4, 0x20, 0x05, 0x00,
0x05, 0xfa, 0x0c, 0xf3, 0x21, 0x05, 0x00,
0x05, 0xfa, 0x0d, 0xf2, 0x22, 0x05, 0x00,
0x05, 0xfa, 0x0e, 0xf1, 0x23, 0x05, 0x00,
0x05, 0xfa, 0x0f, 0xf0, 0x24, 0x05, 0x00,
0x05, 0xfa, 0x10, 0xef, 0x25, 0x05, 0x00,
0x05, 0xfa, 0x11, 0xee, 0x26, 0x05, 0x00,
0x05, 0xfa, 0x12, 0xed, 0x27, 0x05, 0x00,
0x05, 0xfa, 0x13, 0xec, 0x04, 0x05, 0x00,
0x05, 0xfa, 0x15, 0xea, 0x0a, 0x05, 0x00,
0x05, 0xfa, 0x16, 0xe9, 0x11, 0x05, 0x00,
0x05, 0xfa, 0x17, 0xe8, 0x15, 0x05, 0x00,
0x05, 0xfa, 0x18, 0xe7, 0x16, 0x05, 0x00,
0x05, 0xfa, 0x1c, 0xe3, 0x05, 0x05, 0x00,
0x05, 0xfa, 0x1d, 0xe2, 0x09, 0x05, 0x00,
0x05, 0xfa, 0x4d, 0xb2, 0x3f, 0x05, 0x00,
0x05, 0xfa, 0x56, 0xa9, 0x3e, 0x05, 0x00
};
/* Digittrade DVB-T USB Stick */
static struct ir_scancode ir_codes_af9015_table_digittrade[] = {
{ 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[] = {
0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00,
0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00,
0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00,
0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00,
0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00,
0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00,
0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00,
0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00,
0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00,
0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00,
0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00,
0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00,
0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00,
0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00,
0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00,
0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00,
0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00,
0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00,
0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00,
0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00,
0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00,
0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00,
0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00,
0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00,
0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00,
0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00,
0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00,
0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
};
/* TREKSTOR DVB-T USB Stick */
static struct ir_scancode ir_codes_af9015_table_trekstor[] = {
{ 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[] = {
0x00, 0xff, 0x86, 0x79, 0x04, 0x07, 0x00,
0x00, 0xff, 0x85, 0x7a, 0x05, 0x07, 0x00,
0x00, 0xff, 0x87, 0x78, 0x06, 0x07, 0x00,
0x00, 0xff, 0x8c, 0x73, 0x07, 0x07, 0x00,
0x00, 0xff, 0x89, 0x76, 0x09, 0x07, 0x00,
0x00, 0xff, 0x88, 0x77, 0x0a, 0x07, 0x00,
0x00, 0xff, 0x8a, 0x75, 0x0b, 0x07, 0x00,
0x00, 0xff, 0x9e, 0x61, 0x0c, 0x07, 0x00,
0x00, 0xff, 0x8d, 0x72, 0x0d, 0x07, 0x00,
0x00, 0xff, 0x8b, 0x74, 0x0e, 0x07, 0x00,
0x00, 0xff, 0x9b, 0x64, 0x0f, 0x07, 0x00,
0x00, 0xff, 0x9d, 0x62, 0x10, 0x07, 0x00,
0x00, 0xff, 0x8e, 0x71, 0x11, 0x07, 0x00,
0x00, 0xff, 0x9c, 0x63, 0x12, 0x07, 0x00,
0x00, 0xff, 0x8f, 0x70, 0x13, 0x07, 0x00,
0x00, 0xff, 0x93, 0x6c, 0x14, 0x07, 0x00,
0x00, 0xff, 0x97, 0x68, 0x15, 0x07, 0x00,
0x00, 0xff, 0x92, 0x6d, 0x1e, 0x07, 0x00,
0x00, 0xff, 0x96, 0x69, 0x1f, 0x07, 0x00,
0x00, 0xff, 0x9a, 0x65, 0x20, 0x07, 0x00,
0x00, 0xff, 0x91, 0x6e, 0x21, 0x07, 0x00,
0x00, 0xff, 0x95, 0x6a, 0x22, 0x07, 0x00,
0x00, 0xff, 0x99, 0x66, 0x23, 0x07, 0x00,
0x00, 0xff, 0x90, 0x6f, 0x24, 0x07, 0x00,
0x00, 0xff, 0x94, 0x6b, 0x25, 0x07, 0x00,
0x00, 0xff, 0x98, 0x67, 0x26, 0x07, 0x00,
0x00, 0xff, 0x9f, 0x60, 0x08, 0x07, 0x00,
0x00, 0xff, 0x84, 0x7b, 0x27, 0x07, 0x00,
};
/* MSI DIGIVOX mini III */
static struct ir_scancode ir_codes_af9015_table_msi_digivox_iii[] = {
{ 0x0713, KEY_POWER }, /* [red power button] */
{ 0x073b, KEY_VIDEO }, /* Source */
{ 0x073e, KEY_ZOOM }, /* Zoom */
{ 0x070b, KEY_POWER2 }, /* ShutDown */
{ 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 },
{ 0x0727, KEY_0 },
{ 0x0752, KEY_CHANNELUP }, /* CH+ */
{ 0x0751, KEY_CHANNELDOWN }, /* CH- */
{ 0x0750, KEY_VOLUMEUP }, /* Vol+ */
{ 0x074f, KEY_VOLUMEDOWN }, /* Vol- */
{ 0x0705, KEY_ESC }, /* [back up arrow] */
{ 0x0708, KEY_OK }, /* [enter arrow] */
{ 0x073f, KEY_RECORD }, /* Rec */
{ 0x0716, KEY_STOP }, /* Stop */
{ 0x072a, KEY_PLAY }, /* Play */
{ 0x073c, KEY_MUTE }, /* Mute */
{ 0x0718, KEY_UP },
{ 0x0707, KEY_DOWN },
{ 0x070f, KEY_LEFT },
{ 0x0715, KEY_RIGHT },
{ 0x0736, KEY_RED },
{ 0x0737, KEY_GREEN },
{ 0x072d, KEY_YELLOW },
{ 0x072e, KEY_BLUE },
};
static u8 af9015_ir_table_msi_digivox_iii[] = {
0x61, 0xd6, 0x43, 0xbc, 0x13, 0x07, 0x00, /* KEY_POWER */
0x61, 0xd6, 0x01, 0xfe, 0x3b, 0x07, 0x00, /* KEY_VIDEO */
0x61, 0xd6, 0x0b, 0xf4, 0x3e, 0x07, 0x00, /* KEY_ZOOM */
0x61, 0xd6, 0x03, 0xfc, 0x0b, 0x07, 0x00, /* KEY_POWER2 */
0x61, 0xd6, 0x04, 0xfb, 0x1e, 0x07, 0x00, /* KEY_1 */
0x61, 0xd6, 0x08, 0xf7, 0x1f, 0x07, 0x00, /* KEY_2 */
0x61, 0xd6, 0x02, 0xfd, 0x20, 0x07, 0x00, /* KEY_3 */
0x61, 0xd6, 0x0f, 0xf0, 0x21, 0x07, 0x00, /* KEY_4 */
0x61, 0xd6, 0x05, 0xfa, 0x22, 0x07, 0x00, /* KEY_5 */
0x61, 0xd6, 0x06, 0xf9, 0x23, 0x07, 0x00, /* KEY_6 */
0x61, 0xd6, 0x0c, 0xf3, 0x24, 0x07, 0x00, /* KEY_7 */
0x61, 0xd6, 0x0d, 0xf2, 0x25, 0x07, 0x00, /* KEY_8 */
0x61, 0xd6, 0x0a, 0xf5, 0x26, 0x07, 0x00, /* KEY_9 */
0x61, 0xd6, 0x11, 0xee, 0x27, 0x07, 0x00, /* KEY_0 */
0x61, 0xd6, 0x09, 0xf6, 0x52, 0x07, 0x00, /* KEY_CHANNELUP */
0x61, 0xd6, 0x07, 0xf8, 0x51, 0x07, 0x00, /* KEY_CHANNELDOWN */
0x61, 0xd6, 0x0e, 0xf1, 0x50, 0x07, 0x00, /* KEY_VOLUMEUP */
0x61, 0xd6, 0x13, 0xec, 0x4f, 0x07, 0x00, /* KEY_VOLUMEDOWN */
0x61, 0xd6, 0x10, 0xef, 0x05, 0x07, 0x00, /* KEY_ESC */
0x61, 0xd6, 0x12, 0xed, 0x08, 0x07, 0x00, /* KEY_OK */
0x61, 0xd6, 0x14, 0xeb, 0x3f, 0x07, 0x00, /* KEY_RECORD */
0x61, 0xd6, 0x15, 0xea, 0x16, 0x07, 0x00, /* KEY_STOP */
0x61, 0xd6, 0x16, 0xe9, 0x2a, 0x07, 0x00, /* KEY_PLAY */
0x61, 0xd6, 0x17, 0xe8, 0x3c, 0x07, 0x00, /* KEY_MUTE */
0x61, 0xd6, 0x18, 0xe7, 0x18, 0x07, 0x00, /* KEY_UP */
0x61, 0xd6, 0x19, 0xe6, 0x07, 0x07, 0x00, /* KEY_DOWN */
0x61, 0xd6, 0x1a, 0xe5, 0x0f, 0x07, 0x00, /* KEY_LEFT */
0x61, 0xd6, 0x1b, 0xe4, 0x15, 0x07, 0x00, /* KEY_RIGHT */
0x61, 0xd6, 0x1c, 0xe3, 0x36, 0x07, 0x00, /* KEY_RED */
0x61, 0xd6, 0x1d, 0xe2, 0x37, 0x07, 0x00, /* KEY_GREEN */
0x61, 0xd6, 0x1e, 0xe1, 0x2d, 0x07, 0x00, /* KEY_YELLOW */
0x61, 0xd6, 0x1f, 0xe0, 0x2e, 0x07, 0x00, /* KEY_BLUE */
};
#endif

View file

@ -354,7 +354,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
{
struct anysee_state *state = adap->dev->priv;
deb_info("%s: \n", __func__);
deb_info("%s:\n", __func__);
switch (state->tuner) {
case DVB_PLL_THOMSON_DTT7579:
@ -374,78 +374,32 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
static int anysee_rc_query(struct dvb_usb_device *d)
{
u8 buf[] = {CMD_GET_IR_CODE};
struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
u8 ircode[2];
int i, ret;
int ret;
ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2);
/* Remote controller is basic NEC using address byte 0x08.
Anysee device RC query returns only two bytes, status and code,
address byte is dropped. Also it does not return any value for
NEC RCs having address byte other than 0x08. Due to that, we
cannot use that device as standard NEC receiver.
It could be possible make hack which reads whole code directly
from device memory... */
ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode));
if (ret)
return ret;
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[0] &&
rc5_data(&keymap[i]) == ircode[1]) {
*event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
}
if (ircode[0]) {
deb_rc("%s: key pressed %02x\n", __func__, ircode[1]);
ir_keydown(d->rc_input_dev, 0x08 << 8 | ircode[1], 0);
}
return 0;
}
static struct ir_scancode ir_codes_anysee_table[] = {
{ 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 */
static struct dvb_usb_device_properties anysee_properties;
@ -520,11 +474,12 @@ static struct dvb_usb_device_properties anysee_properties = {
}
},
.rc.legacy = {
.rc_key_map = ir_codes_anysee_table,
.rc_key_map_size = ARRAY_SIZE(ir_codes_anysee_table),
.rc.core = {
.rc_codes = RC_MAP_ANYSEE,
.protocol = IR_TYPE_OTHER,
.module_name = "anysee",
.rc_query = anysee_rc_query,
.rc_interval = 200, /* windows driver uses 500ms */
.rc_interval = 250, /* windows driver uses 500ms */
},
.i2c_algo = &anysee_i2c_algo,

View file

@ -20,7 +20,6 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
}
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;
d->i2c_adap.dev.parent = &d->udev->dev;

View file

@ -32,6 +32,7 @@
#define USB_VID_EMPIA 0xeb1a
#define USB_VID_GENPIX 0x09c0
#define USB_VID_GRANDTEC 0x5032
#define USB_VID_GTEK 0x1f4d
#define USB_VID_HANFTEK 0x15f4
#define USB_VID_HAUPPAUGE 0x2040
#define USB_VID_HYPER_PALTEK 0x1025
@ -133,6 +134,8 @@
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069
#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097
#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
@ -143,6 +146,7 @@
#define USB_PID_TWINHAN_VP7021_WARM 0x3208
#define USB_PID_TINYTWIN 0x3226
#define USB_PID_TINYTWIN_2 0xe402
#define USB_PID_TINYTWIN_3 0x9016
#define USB_PID_DNTV_TINYUSB2_COLD 0x3223
#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
@ -196,6 +200,7 @@
#define USB_PID_AVERMEDIA_A309 0xa309
#define USB_PID_AVERMEDIA_A310 0xa310
#define USB_PID_AVERMEDIA_A850 0x850a
#define USB_PID_AVERMEDIA_A850T 0x850b
#define USB_PID_AVERMEDIA_A805 0xa805
#define USB_PID_AVERMEDIA_A815M 0x815a
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
@ -268,6 +273,7 @@
#define USB_PID_GENPIX_8PSK_REV_2 0x0202
#define USB_PID_GENPIX_SKYWALKER_1 0x0203
#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204
#define USB_PID_GENPIX_SKYWALKER_2 0x0206
#define USB_PID_SIGMATEK_DVB_110 0x6610
#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513
#define USB_PID_MSI_DIGIVOX_DUO 0x8801

View file

@ -75,7 +75,7 @@ static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
return 0;
}
static int _jdvbt90502_write(struct dvb_frontend *fe, u8 *buf, int len)
static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct jdvbt90502_state *state = fe->demodulator_priv;
int err, i;

View file

@ -109,7 +109,7 @@ static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength
static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 200;
tune->min_delay_ms = 800;
return 0;
}
@ -334,7 +334,7 @@ success:
static struct dvb_frontend_ops gp8psk_fe_ops = {
.info = {
.name = "Genpix 8psk-to-USB2 DVB-S",
.name = "Genpix DVB-S",
.type = FE_QPSK,
.frequency_min = 800000,
.frequency_max = 2250000,

View file

@ -227,6 +227,7 @@ static struct usb_device_id gp8psk_usb_table [] = {
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) },
/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
{ 0 },
};
@ -258,7 +259,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 3,
.num_device_descs = 4,
.devices = {
{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
.cold_ids = { &gp8psk_usb_table[0], NULL },
@ -272,6 +273,10 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.cold_ids = { NULL },
.warm_ids = { &gp8psk_usb_table[3], NULL },
},
{ .name = "Genpix SkyWalker-2 DVB-S receiver",
.cold_ids = { NULL },
.warm_ids = { &gp8psk_usb_table[4], NULL },
},
{ NULL },
}
};
@ -306,6 +311,6 @@ module_init(gp8psk_usb_module_init);
module_exit(gp8psk_usb_module_exit);
MODULE_AUTHOR("Alan Nisota <[email protected]>");
MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S");
MODULE_DESCRIPTION("Driver for Genpix DVB-S");
MODULE_VERSION("1.1");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,173 @@
/* DVB USB compliant linux driver for
*
* DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
* LME2510C + LG TDQY-P001F
* LME2510 + LG TDQY-P001F
*
* MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
* SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
*
* MVB001F (LME2510+LGTDQT-P001F)
* LG TDQY - P001F =(TDA8263 + TDA10086H)
*
* MVB0001F (LME2510C+LGTDQT-P001F)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
* *
* see Documentation/dvb/README.dvb-usb for more information
*/
#ifndef _DVB_USB_LME2510_H_
#define _DVB_USB_LME2510_H_
/* Streamer & PID
*
* Note: These commands do not actually stop the streaming
* but form some kind of packet filtering/stream count
* or tuning related functions.
* 06 XX
* offset 1 = 00 Enable Streaming
*
*
* PID
* 03 XX XX ----> reg number ---> setting....20 XX
* offset 1 = length
* offset 2 = start of data
* end byte -1 = 20
* end byte = clear pid always a0, other wise 9c, 9a ??
*
*/
#define LME_ST_ON_W {0x06, 0x00}
#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0}
/* LNB Voltage
* 07 XX XX
* offset 1 = 01
* offset 2 = 00=Voltage low 01=Voltage high
*
* LNB Power
* 03 01 XX
* offset 2 = 00=ON 01=OFF
*/
#define LME_VOLTAGE_L {0x07, 0x01, 0x00}
#define LME_VOLTAGE_H {0x07, 0x01, 0x01}
#define LNB_ON {0x3a, 0x01, 0x00}
#define LNB_OFF {0x3a, 0x01, 0x01}
/* Initial stv0288 settings for 7395 Frontend */
static u8 s7395_inittab[] = {
0x01, 0x15,
0x02, 0x20,
0x03, 0xa0,
0x04, 0xa0,
0x05, 0x12,
0x06, 0x00,
0x09, 0x00,
0x0a, 0x04,
0x0b, 0x00,
0x0c, 0x00,
0x0d, 0x00,
0x0e, 0xc1,
0x0f, 0x54,
0x11, 0x7a,
0x12, 0x03,
0x13, 0x48,
0x14, 0x84,
0x15, 0xc5,
0x16, 0xb8,
0x17, 0x9c,
0x18, 0x00,
0x19, 0xa6,
0x1a, 0x88,
0x1b, 0x8f,
0x1c, 0xf0,
0x20, 0x0b,
0x21, 0x54,
0x22, 0xff,
0x23, 0x01,
0x28, 0x46,
0x29, 0x66,
0x2a, 0x90,
0x2b, 0xfa,
0x2c, 0xd9,
0x30, 0x0,
0x31, 0x1e,
0x32, 0x14,
0x33, 0x0f,
0x34, 0x09,
0x35, 0x0c,
0x36, 0x05,
0x37, 0x2f,
0x38, 0x16,
0x39, 0xbd,
0x3a, 0x0,
0x3b, 0x13,
0x3c, 0x11,
0x3d, 0x30,
0x40, 0x63,
0x41, 0x04,
0x42, 0x60,
0x43, 0x00,
0x44, 0x00,
0x45, 0x00,
0x46, 0x00,
0x47, 0x00,
0x4a, 0x00,
0x50, 0x12,
0x51, 0x36,
0x52, 0x21,
0x53, 0x94,
0x54, 0xb2,
0x55, 0x29,
0x56, 0x64,
0x57, 0x2b,
0x58, 0x54,
0x59, 0x86,
0x5a, 0x00,
0x5b, 0x9b,
0x5c, 0x08,
0x5d, 0x7f,
0x5e, 0xff,
0x5f, 0x8d,
0x70, 0x0,
0x71, 0x0,
0x72, 0x0,
0x74, 0x0,
0x75, 0x0,
0x76, 0x0,
0x81, 0x0,
0x82, 0x3f,
0x83, 0x3f,
0x84, 0x0,
0x85, 0x0,
0x88, 0x0,
0x89, 0x0,
0x8a, 0x0,
0x8b, 0x0,
0x8c, 0x0,
0x90, 0x0,
0x91, 0x0,
0x92, 0x0,
0x93, 0x0,
0x94, 0x1c,
0x97, 0x0,
0xa0, 0x48,
0xa1, 0x0,
0xb0, 0xb8,
0xb1, 0x3a,
0xb2, 0x10,
0xb3, 0x82,
0xb4, 0x80,
0xb5, 0x82,
0xb6, 0x82,
0xb7, 0x82,
0xb8, 0x20,
0xb9, 0x0,
0xf0, 0x0,
0xf1, 0x0,
0xf2, 0xc0,
0xff, 0xff,
};
#endif

View file

@ -24,6 +24,8 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <dvb_frontend.h>
#include "firedtv.h"
#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL
@ -130,6 +132,20 @@ MODULE_PARM_DESC(debug, "Verbose logging (none = 0"
", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS)
", or a combination, or all = -1)");
/*
* This is a workaround since there is no vendor specific command to retrieve
* ca_info using AVC. If this parameter is not used, ca_system_id will be
* filled with application_manufacturer from ca_app_info.
* Digital Everywhere have said that adding ca_info is on their TODO list.
*/
static unsigned int num_fake_ca_system_ids;
static int fake_ca_system_ids[4] = { -1, -1, -1, -1 };
module_param_array(fake_ca_system_ids, int, &num_fake_ca_system_ids, 0644);
MODULE_PARM_DESC(fake_ca_system_ids, "If your CAM application manufacturer "
"does not have the same ca_system_id as your CAS, you can "
"override what ca_system_ids are presented to the "
"application by setting this field to an array of ids.");
static const char *debug_fcp_ctype(unsigned int ctype)
{
static const char *ctypes[] = {
@ -368,10 +384,30 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
c->operand[12] = 0;
if (fdtv->type == FIREDTV_DVB_S2) {
c->operand[13] = 0x1;
c->operand[14] = 0xff;
c->operand[15] = 0xff;
if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) {
switch (fdtv->fe.dtv_property_cache.modulation) {
case QAM_16: c->operand[13] = 0x1; break;
case QPSK: c->operand[13] = 0x2; break;
case PSK_8: c->operand[13] = 0x3; break;
default: c->operand[13] = 0x2; break;
}
switch (fdtv->fe.dtv_property_cache.rolloff) {
case ROLLOFF_AUTO: c->operand[14] = 0x2; break;
case ROLLOFF_35: c->operand[14] = 0x2; break;
case ROLLOFF_20: c->operand[14] = 0x0; break;
case ROLLOFF_25: c->operand[14] = 0x1; break;
/* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */
}
switch (fdtv->fe.dtv_property_cache.pilot) {
case PILOT_AUTO: c->operand[15] = 0x0; break;
case PILOT_OFF: c->operand[15] = 0x0; break;
case PILOT_ON: c->operand[15] = 0x1; break;
}
} else {
c->operand[13] = 0x1; /* auto modulation */
c->operand[14] = 0xff; /* disable rolloff */
c->operand[15] = 0xff; /* disable pilot */
}
return 16;
} else {
return 13;
@ -977,7 +1013,7 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
{
struct avc_command_frame *c = (void *)fdtv->avc_data;
struct avc_response_frame *r = (void *)fdtv->avc_data;
int pos, ret;
int i, pos, ret;
mutex_lock(&fdtv->avc_mutex);
@ -1004,9 +1040,18 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
app_info[1] = (EN50221_TAG_CA_INFO >> 8) & 0xff;
app_info[2] = (EN50221_TAG_CA_INFO >> 0) & 0xff;
app_info[3] = 2;
app_info[4] = r->operand[pos + 0];
app_info[5] = r->operand[pos + 1];
if (num_fake_ca_system_ids == 0) {
app_info[3] = 2;
app_info[4] = r->operand[pos + 0];
app_info[5] = r->operand[pos + 1];
} else {
app_info[3] = num_fake_ca_system_ids * 2;
for (i = 0; i < num_fake_ca_system_ids; i++) {
app_info[4 + i * 2] =
(fake_ca_system_ids[i] >> 8) & 0xff;
app_info[5 + i * 2] = fake_ca_system_ids[i] & 0xff;
}
}
*len = app_info[3] + 4;
out:
mutex_unlock(&fdtv->avc_mutex);

View file

@ -155,6 +155,16 @@ static int fdtv_get_frontend(struct dvb_frontend *fe,
return -EOPNOTSUPP;
}
static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp)
{
return 0;
}
static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp)
{
return 0;
}
void fdtv_frontend_init(struct firedtv *fdtv)
{
struct dvb_frontend_ops *ops = &fdtv->fe.ops;
@ -166,6 +176,9 @@ void fdtv_frontend_init(struct firedtv *fdtv)
ops->set_frontend = fdtv_set_frontend;
ops->get_frontend = fdtv_get_frontend;
ops->get_property = fdtv_get_property;
ops->set_property = fdtv_set_property;
ops->read_status = fdtv_read_status;
ops->read_ber = fdtv_read_ber;
ops->read_signal_strength = fdtv_read_signal_strength;
@ -179,6 +192,24 @@ void fdtv_frontend_init(struct firedtv *fdtv)
switch (fdtv->type) {
case FIREDTV_DVB_S:
fi->type = FE_QPSK;
fi->frequency_min = 950000;
fi->frequency_max = 2150000;
fi->frequency_stepsize = 125;
fi->symbol_rate_min = 1000000;
fi->symbol_rate_max = 40000000;
fi->caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 |
FE_CAN_FEC_7_8 |
FE_CAN_FEC_AUTO |
FE_CAN_QPSK;
break;
case FIREDTV_DVB_S2:
fi->type = FE_QPSK;
@ -188,14 +219,15 @@ void fdtv_frontend_init(struct firedtv *fdtv)
fi->symbol_rate_min = 1000000;
fi->symbol_rate_max = 40000000;
fi->caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 |
FE_CAN_FEC_7_8 |
FE_CAN_FEC_AUTO |
FE_CAN_QPSK;
fi->caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 |
FE_CAN_FEC_7_8 |
FE_CAN_FEC_AUTO |
FE_CAN_QPSK |
FE_CAN_2G_MODULATION;
break;
case FIREDTV_DVB_C:

View file

@ -257,6 +257,13 @@ config DVB_CX22702
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_S5H1432
tristate "Samsung s5h1432 demodulator (OFDM)"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_DRX397XD
tristate "Micronas DRX3975D/DRX3977D based"
depends on DVB_CORE && I2C
@ -455,16 +462,8 @@ config DVB_LGDT330X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
config DVB_LGDT3304
tristate "LG Electronics LGDT3304"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
config DVB_LGDT3305
tristate "LG Electronics LGDT3305 based"
tristate "LG Electronics LGDT3304 and LGDT3305 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
@ -607,6 +606,13 @@ config DVB_TDA665x
Currently supported tuners:
* Panasonic ENV57H12D5 (ET-50DT)
config DVB_IX2505V
tristate "Sharp IX2505V 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.
comment "Tools to develop new frontends"
config DVB_DUMMY_FE

View file

@ -16,6 +16,7 @@ obj-$(CONFIG_DVB_STB0899) += stb0899.o
obj-$(CONFIG_DVB_STB6100) += stb6100.o
obj-$(CONFIG_DVB_SP8870) += sp8870.o
obj-$(CONFIG_DVB_CX22700) += cx22700.o
obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
obj-$(CONFIG_DVB_TDA8083) += tda8083.o
obj-$(CONFIG_DVB_L64781) += l64781.o
@ -45,7 +46,6 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
@ -82,3 +82,4 @@ obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o

View file

@ -42,6 +42,8 @@ struct af9013_state {
struct af9013_config config;
/* tuner/demod RF and IF AGC limits used for signal strength calc */
u8 signal_strength_en, rf_50, rf_80, if_50, if_80;
u16 signal_strength;
u32 ber;
u32 ucblocks;
@ -220,184 +222,37 @@ static u32 af913_div(u32 a, u32 b, u32 x)
static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
{
int ret = 0;
u8 i = 0;
u8 buf[24];
u32 uninitialized_var(ns_coeff1_2048nu);
u32 uninitialized_var(ns_coeff1_8191nu);
u32 uninitialized_var(ns_coeff1_8192nu);
u32 uninitialized_var(ns_coeff1_8193nu);
u32 uninitialized_var(ns_coeff2_2k);
u32 uninitialized_var(ns_coeff2_8k);
int ret, i, j, found;
deb_info("%s: adc_clock:%d bw:%d\n", __func__,
state->config.adc_clock, bw);
switch (state->config.adc_clock) {
case 28800: /* 28.800 MHz */
switch (bw) {
case BANDWIDTH_6_MHZ:
ns_coeff1_2048nu = 0x01e79e7a;
ns_coeff1_8191nu = 0x0079eb6e;
ns_coeff1_8192nu = 0x0079e79e;
ns_coeff1_8193nu = 0x0079e3cf;
ns_coeff2_2k = 0x00f3cf3d;
ns_coeff2_8k = 0x003cf3cf;
/* lookup coeff from table */
for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) {
if (coeff_table[i].adc_clock == state->config.adc_clock &&
coeff_table[i].bw == bw) {
found = 1;
break;
case BANDWIDTH_7_MHZ:
ns_coeff1_2048nu = 0x0238e38e;
ns_coeff1_8191nu = 0x008e3d55;
ns_coeff1_8192nu = 0x008e38e4;
ns_coeff1_8193nu = 0x008e3472;
ns_coeff2_2k = 0x011c71c7;
ns_coeff2_8k = 0x00471c72;
break;
case BANDWIDTH_8_MHZ:
ns_coeff1_2048nu = 0x028a28a3;
ns_coeff1_8191nu = 0x00a28f3d;
ns_coeff1_8192nu = 0x00a28a29;
ns_coeff1_8193nu = 0x00a28514;
ns_coeff2_2k = 0x01451451;
ns_coeff2_8k = 0x00514514;
break;
default:
ret = -EINVAL;
}
break;
case 20480: /* 20.480 MHz */
switch (bw) {
case BANDWIDTH_6_MHZ:
ns_coeff1_2048nu = 0x02adb6dc;
ns_coeff1_8191nu = 0x00ab7313;
ns_coeff1_8192nu = 0x00ab6db7;
ns_coeff1_8193nu = 0x00ab685c;
ns_coeff2_2k = 0x0156db6e;
ns_coeff2_8k = 0x0055b6dc;
break;
case BANDWIDTH_7_MHZ:
ns_coeff1_2048nu = 0x03200001;
ns_coeff1_8191nu = 0x00c80640;
ns_coeff1_8192nu = 0x00c80000;
ns_coeff1_8193nu = 0x00c7f9c0;
ns_coeff2_2k = 0x01900000;
ns_coeff2_8k = 0x00640000;
break;
case BANDWIDTH_8_MHZ:
ns_coeff1_2048nu = 0x03924926;
ns_coeff1_8191nu = 0x00e4996e;
ns_coeff1_8192nu = 0x00e49249;
ns_coeff1_8193nu = 0x00e48b25;
ns_coeff2_2k = 0x01c92493;
ns_coeff2_8k = 0x00724925;
break;
default:
ret = -EINVAL;
}
break;
case 28000: /* 28.000 MHz */
switch (bw) {
case BANDWIDTH_6_MHZ:
ns_coeff1_2048nu = 0x01f58d10;
ns_coeff1_8191nu = 0x007d672f;
ns_coeff1_8192nu = 0x007d6344;
ns_coeff1_8193nu = 0x007d5f59;
ns_coeff2_2k = 0x00fac688;
ns_coeff2_8k = 0x003eb1a2;
break;
case BANDWIDTH_7_MHZ:
ns_coeff1_2048nu = 0x02492492;
ns_coeff1_8191nu = 0x00924db7;
ns_coeff1_8192nu = 0x00924925;
ns_coeff1_8193nu = 0x00924492;
ns_coeff2_2k = 0x01249249;
ns_coeff2_8k = 0x00492492;
break;
case BANDWIDTH_8_MHZ:
ns_coeff1_2048nu = 0x029cbc15;
ns_coeff1_8191nu = 0x00a7343f;
ns_coeff1_8192nu = 0x00a72f05;
ns_coeff1_8193nu = 0x00a729cc;
ns_coeff2_2k = 0x014e5e0a;
ns_coeff2_8k = 0x00539783;
break;
default:
ret = -EINVAL;
}
break;
case 25000: /* 25.000 MHz */
switch (bw) {
case BANDWIDTH_6_MHZ:
ns_coeff1_2048nu = 0x0231bcb5;
ns_coeff1_8191nu = 0x008c7391;
ns_coeff1_8192nu = 0x008c6f2d;
ns_coeff1_8193nu = 0x008c6aca;
ns_coeff2_2k = 0x0118de5b;
ns_coeff2_8k = 0x00463797;
break;
case BANDWIDTH_7_MHZ:
ns_coeff1_2048nu = 0x028f5c29;
ns_coeff1_8191nu = 0x00a3dc29;
ns_coeff1_8192nu = 0x00a3d70a;
ns_coeff1_8193nu = 0x00a3d1ec;
ns_coeff2_2k = 0x0147ae14;
ns_coeff2_8k = 0x0051eb85;
break;
case BANDWIDTH_8_MHZ:
ns_coeff1_2048nu = 0x02ecfb9d;
ns_coeff1_8191nu = 0x00bb44c1;
ns_coeff1_8192nu = 0x00bb3ee7;
ns_coeff1_8193nu = 0x00bb390d;
ns_coeff2_2k = 0x01767dce;
ns_coeff2_8k = 0x005d9f74;
break;
default:
ret = -EINVAL;
}
break;
default:
err("invalid xtal");
return -EINVAL;
}
if (ret) {
err("invalid bandwidth");
return ret;
}
buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24);
buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16);
buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8);
buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff));
buf[i++] = (u8) ((ns_coeff2_2k & 0x01c00000) >> 22);
buf[i++] = (u8) ((ns_coeff2_2k & 0x003fc000) >> 14);
buf[i++] = (u8) ((ns_coeff2_2k & 0x00003fc0) >> 6);
buf[i++] = (u8) ((ns_coeff2_2k & 0x0000003f));
buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24);
buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16);
buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8);
buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff));
buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24);
buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16);
buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8);
buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff));
buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24);
buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16);
buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8);
buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff));
buf[i++] = (u8) ((ns_coeff2_8k & 0x01c00000) >> 22);
buf[i++] = (u8) ((ns_coeff2_8k & 0x003fc000) >> 14);
buf[i++] = (u8) ((ns_coeff2_8k & 0x00003fc0) >> 6);
buf[i++] = (u8) ((ns_coeff2_8k & 0x0000003f));
if (!found) {
err("invalid bw or clock");
ret = -EINVAL;
goto error;
}
deb_info("%s: coeff:", __func__);
debug_dump(buf, sizeof(buf), deb_info);
deb_info("%s: coeff: ", __func__);
debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info);
/* program */
for (i = 0; i < sizeof(buf); i++) {
ret = af9013_write_reg(state, 0xae00 + i, buf[i]);
for (j = 0; j < sizeof(coeff_table[i].val); j++) {
ret = af9013_write_reg(state, 0xae00 + j,
coeff_table[i].val[j]);
if (ret)
break;
}
error:
return ret;
}
@ -486,6 +341,19 @@ static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
if_sample_freq = 4300000; /* 4.3 MHz */
break;
}
} else if (state->config.tuner == AF9013_TUNER_TDA18218) {
switch (bw) {
case BANDWIDTH_6_MHZ:
if_sample_freq = 3000000; /* 3 MHz */
break;
case BANDWIDTH_7_MHZ:
if_sample_freq = 3500000; /* 3.5 MHz */
break;
case BANDWIDTH_8_MHZ:
default:
if_sample_freq = 4000000; /* 4 MHz */
break;
}
}
while (if_sample_freq > (adc_freq / 2))
@ -1097,45 +965,31 @@ static int af9013_update_signal_strength(struct dvb_frontend *fe)
{
struct af9013_state *state = fe->demodulator_priv;
int ret;
u8 tmp0;
u8 rf_gain, rf_50, rf_80, if_gain, if_50, if_80;
u8 rf_gain, if_gain;
int signal_strength;
deb_info("%s\n", __func__);
state->signal_strength = 0;
ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, &tmp0);
if (ret)
goto error;
if (tmp0) {
ret = af9013_read_reg(state, 0x9bbd, &rf_50);
if (ret)
goto error;
ret = af9013_read_reg(state, 0x9bd0, &rf_80);
if (ret)
goto error;
ret = af9013_read_reg(state, 0x9be2, &if_50);
if (ret)
goto error;
ret = af9013_read_reg(state, 0x9be4, &if_80);
if (ret)
goto error;
if (state->signal_strength_en) {
ret = af9013_read_reg(state, 0xd07c, &rf_gain);
if (ret)
goto error;
ret = af9013_read_reg(state, 0xd07d, &if_gain);
if (ret)
goto error;
signal_strength = (0xffff / (9 * (rf_50 + if_50) - \
11 * (rf_80 + if_80))) * (10 * (rf_gain + if_gain) - \
11 * (rf_80 + if_80));
signal_strength = (0xffff / \
(9 * (state->rf_50 + state->if_50) - \
11 * (state->rf_80 + state->if_80))) * \
(10 * (rf_gain + if_gain) - \
11 * (state->rf_80 + state->if_80));
if (signal_strength < 0)
signal_strength = 0;
else if (signal_strength > 0xffff)
signal_strength = 0xffff;
state->signal_strength = signal_strength;
} else {
state->signal_strength = 0;
}
error:
@ -1368,6 +1222,7 @@ static int af9013_init(struct dvb_frontend *fe)
break;
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
case AF9013_TUNER_MXL5007T:
len = ARRAY_SIZE(tuner_init_mxl5005);
init = tuner_init_mxl5005;
break;
@ -1393,6 +1248,7 @@ static int af9013_init(struct dvb_frontend *fe)
init = tuner_init_mt2060_2;
break;
case AF9013_TUNER_TDA18271:
case AF9013_TUNER_TDA18218:
len = ARRAY_SIZE(tuner_init_tda18271);
init = tuner_init_tda18271;
break;
@ -1438,6 +1294,27 @@ static int af9013_init(struct dvb_frontend *fe)
if (ret)
goto error;
/* read values needed for signal strength calculation */
ret = af9013_read_reg_bits(state, 0x9bee, 0, 1,
&state->signal_strength_en);
if (ret)
goto error;
if (state->signal_strength_en) {
ret = af9013_read_reg(state, 0x9bbd, &state->rf_50);
if (ret)
goto error;
ret = af9013_read_reg(state, 0x9bd0, &state->rf_80);
if (ret)
goto error;
ret = af9013_read_reg(state, 0x9be2, &state->if_50);
if (ret)
goto error;
ret = af9013_read_reg(state, 0x9be4, &state->if_80);
if (ret)
goto error;
}
error:
return ret;
}

View file

@ -44,6 +44,7 @@ enum af9013_tuner {
AF9013_TUNER_MT2060_2 = 147, /* Microtune */
AF9013_TUNER_TDA18271 = 156, /* NXP */
AF9013_TUNER_QT1010A = 162, /* Quantek */
AF9013_TUNER_MXL5007T = 177, /* MaxLinear */
AF9013_TUNER_TDA18218 = 179, /* NXP */
};

View file

@ -60,6 +60,56 @@ struct snr_table {
u8 snr;
};
struct coeff {
u32 adc_clock;
fe_bandwidth_t bw;
u8 val[24];
};
/* pre-calculated coeff lookup table */
static struct coeff coeff_table[] = {
/* 28.800 MHz */
{ 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a,
0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } },
{ 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38,
0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } },
{ 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7,
0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } },
/* 20.480 MHz */
{ 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92,
0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } },
{ 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00,
0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } },
{ 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d,
0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } },
/* 28.000 MHz */
{ 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f,
0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } },
{ 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49,
0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } },
{ 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63,
0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } },
/* 25.000 MHz */
{ 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e,
0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } },
{ 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7,
0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } },
{ 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f,
0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
};
/* QPSK SNR lookup table */
static struct snr_table qpsk_snr_table[] = {
{ 0x0b4771, 0 },
@ -480,9 +530,10 @@ static struct regdesc tuner_init_mxl5003d[] = {
{ 0x9bd9, 0, 8, 0x08 },
};
/* MaxLinear MXL5005 tuner init
/* MaxLinear MXL5005S & MXL5007T tuner init
AF9013_TUNER_MXL5005D = 13
AF9013_TUNER_MXL5005R = 30 */
AF9013_TUNER_MXL5005R = 30
AF9013_TUNER_MXL5007T = 177 */
static struct regdesc tuner_init_mxl5005[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x07 },
@ -791,8 +842,9 @@ static struct regdesc tuner_init_unknown[] = {
{ 0x9bd9, 0, 8, 0x08 },
};
/* NXP TDA18271 tuner init
AF9013_TUNER_TDA18271 = 156 */
/* NXP TDA18271 & TDA18218 tuner init
AF9013_TUNER_TDA18271 = 156
AF9013_TUNER_TDA18218 = 179 */
static struct regdesc tuner_init_tda18271[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x04 },

View file

@ -36,7 +36,6 @@
#include <linux/delay.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-i2c-drv.h>
#include <media/v4l2-device.h>
#include "au8522.h"
#include "au8522_priv.h"
@ -831,9 +830,25 @@ static const struct i2c_device_id au8522_id[] = {
MODULE_DEVICE_TABLE(i2c, au8522_id);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "au8522",
.probe = au8522_probe,
.remove = au8522_remove,
.id_table = au8522_id,
static struct i2c_driver au8522_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "au8522",
},
.probe = au8522_probe,
.remove = au8522_remove,
.id_table = au8522_id,
};
static __init int init_au8522(void)
{
return i2c_add_driver(&au8522_driver);
}
static __exit void exit_au8522(void)
{
i2c_del_driver(&au8522_driver);
}
module_init(init_au8522);
module_exit(exit_au8522);

View file

@ -54,7 +54,7 @@ MODULE_PARM_DESC(debug, "Enable verbose debug messages");
#define dprintk if (debug) printk
/* Register values to initialise the demod */
static u8 init_tab[] = {
static const u8 init_tab[] = {
0x00, 0x00, /* Stop aquisition */
0x0B, 0x06,
0x09, 0x01,
@ -92,52 +92,56 @@ static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
if (unlikely(ret != 1)) {
printk(KERN_ERR
"%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
__func__, reg, data, ret);
return -1;
}
return (ret != 1) ? -1 : 0;
return 0;
}
static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
u8 data;
struct i2c_msg msg[] = {
{ .addr = state->config->demod_address, .flags = 0,
.buf = b0, .len = 1 },
.buf = &reg, .len = 1 },
{ .addr = state->config->demod_address, .flags = I2C_M_RD,
.buf = b1, .len = 1 } };
.buf = &data, .len = 1 } };
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2)
printk(KERN_ERR "%s: readreg error (ret == %i)\n",
__func__, ret);
if (unlikely(ret != 2)) {
printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n",
__func__, reg, ret);
return 0;
}
return b1[0];
return data;
}
static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
{
u8 val;
val = cx22702_readreg(state, 0x0C);
switch (inversion) {
case INVERSION_AUTO:
return -EOPNOTSUPP;
case INVERSION_ON:
val = cx22702_readreg(state, 0x0C);
return cx22702_writereg(state, 0x0C, val | 0x01);
val |= 0x01;
break;
case INVERSION_OFF:
val = cx22702_readreg(state, 0x0C);
return cx22702_writereg(state, 0x0C, val & 0xfe);
val &= 0xfe;
break;
default:
return -EINVAL;
}
return cx22702_writereg(state, 0x0C, val);
}
/* Retrieve the demod settings */
@ -244,13 +248,15 @@ static int cx22702_get_tps(struct cx22702_state *state,
static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct cx22702_state *state = fe->demodulator_priv;
u8 val;
dprintk("%s(%d)\n", __func__, enable);
val = cx22702_readreg(state, 0x0D);
if (enable)
return cx22702_writereg(state, 0x0D,
cx22702_readreg(state, 0x0D) & 0xfe);
val &= 0xfe;
else
return cx22702_writereg(state, 0x0D,
cx22702_readreg(state, 0x0D) | 1);
val |= 0x01;
return cx22702_writereg(state, 0x0D, val);
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
@ -270,23 +276,21 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
cx22702_set_inversion(state, p->inversion);
/* set bandwidth */
val = cx22702_readreg(state, 0x0C) & 0xcf;
switch (p->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
cx22702_writereg(state, 0x0C,
(cx22702_readreg(state, 0x0C) & 0xcf) | 0x20);
val |= 0x20;
break;
case BANDWIDTH_7_MHZ:
cx22702_writereg(state, 0x0C,
(cx22702_readreg(state, 0x0C) & 0xcf) | 0x10);
val |= 0x10;
break;
case BANDWIDTH_8_MHZ:
cx22702_writereg(state, 0x0C,
cx22702_readreg(state, 0x0C) & 0xcf);
break;
default:
dprintk("%s: invalid bandwidth\n", __func__);
return -EINVAL;
}
cx22702_writereg(state, 0x0C, val);
p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
@ -312,33 +316,31 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
/* manually programmed values */
val = 0;
switch (p->u.ofdm.constellation) {
switch (p->u.ofdm.constellation) { /* mask 0x18 */
case QPSK:
val = (val & 0xe7);
val = 0x00;
break;
case QAM_16:
val = (val & 0xe7) | 0x08;
val = 0x08;
break;
case QAM_64:
val = (val & 0xe7) | 0x10;
val = 0x10;
break;
default:
dprintk("%s: invalid constellation\n", __func__);
return -EINVAL;
}
switch (p->u.ofdm.hierarchy_information) {
switch (p->u.ofdm.hierarchy_information) { /* mask 0x07 */
case HIERARCHY_NONE:
val = (val & 0xf8);
break;
case HIERARCHY_1:
val = (val & 0xf8) | 1;
val |= 0x01;
break;
case HIERARCHY_2:
val = (val & 0xf8) | 2;
val |= 0x02;
break;
case HIERARCHY_4:
val = (val & 0xf8) | 3;
val |= 0x03;
break;
default:
dprintk("%s: invalid hierarchy\n", __func__);
@ -346,44 +348,42 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
cx22702_writereg(state, 0x06, val);
val = 0;
switch (p->u.ofdm.code_rate_HP) {
switch (p->u.ofdm.code_rate_HP) { /* mask 0x38 */
case FEC_NONE:
case FEC_1_2:
val = (val & 0xc7);
val = 0x00;
break;
case FEC_2_3:
val = (val & 0xc7) | 0x08;
val = 0x08;
break;
case FEC_3_4:
val = (val & 0xc7) | 0x10;
val = 0x10;
break;
case FEC_5_6:
val = (val & 0xc7) | 0x18;
val = 0x18;
break;
case FEC_7_8:
val = (val & 0xc7) | 0x20;
val = 0x20;
break;
default:
dprintk("%s: invalid code_rate_HP\n", __func__);
return -EINVAL;
}
switch (p->u.ofdm.code_rate_LP) {
switch (p->u.ofdm.code_rate_LP) { /* mask 0x07 */
case FEC_NONE:
case FEC_1_2:
val = (val & 0xf8);
break;
case FEC_2_3:
val = (val & 0xf8) | 1;
val |= 0x01;
break;
case FEC_3_4:
val = (val & 0xf8) | 2;
val |= 0x02;
break;
case FEC_5_6:
val = (val & 0xf8) | 3;
val |= 0x03;
break;
case FEC_7_8:
val = (val & 0xf8) | 4;
val |= 0x04;
break;
default:
dprintk("%s: invalid code_rate_LP\n", __func__);
@ -391,30 +391,28 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
cx22702_writereg(state, 0x07, val);
val = 0;
switch (p->u.ofdm.guard_interval) {
switch (p->u.ofdm.guard_interval) { /* mask 0x0c */
case GUARD_INTERVAL_1_32:
val = (val & 0xf3);
val = 0x00;
break;
case GUARD_INTERVAL_1_16:
val = (val & 0xf3) | 0x04;
val = 0x04;
break;
case GUARD_INTERVAL_1_8:
val = (val & 0xf3) | 0x08;
val = 0x08;
break;
case GUARD_INTERVAL_1_4:
val = (val & 0xf3) | 0x0c;
val = 0x0c;
break;
default:
dprintk("%s: invalid guard_interval\n", __func__);
return -EINVAL;
}
switch (p->u.ofdm.transmission_mode) {
switch (p->u.ofdm.transmission_mode) { /* mask 0x03 */
case TRANSMISSION_MODE_2K:
val = (val & 0xfc);
break;
case TRANSMISSION_MODE_8K:
val = (val & 0xfc) | 1;
val |= 0x1;
break;
default:
dprintk("%s: invalid transmission_mode\n", __func__);
@ -505,7 +503,7 @@ static int cx22702_read_signal_strength(struct dvb_frontend *fe,
{
struct cx22702_state *state = fe->demodulator_priv;
u16 rs_ber = 0;
u16 rs_ber;
rs_ber = cx22702_readreg(state, 0x23);
*signal_strength = (rs_ber << 8) | rs_ber;
@ -516,7 +514,7 @@ static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct cx22702_state *state = fe->demodulator_priv;
u16 rs_ber = 0;
u16 rs_ber;
if (cx22702_readreg(state, 0xE4) & 0x02) {
/* Realtime statistics */
rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
@ -572,7 +570,7 @@ static void cx22702_release(struct dvb_frontend *fe)
kfree(state);
}
static struct dvb_frontend_ops cx22702_ops;
static const struct dvb_frontend_ops cx22702_ops;
struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
struct i2c_adapter *i2c)
@ -587,7 +585,6 @@ struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
/* setup the state */
state->config = config;
state->i2c = i2c;
state->prevUCBlocks = 0;
/* check if the demod is there */
if (cx22702_readreg(state, 0x1f) != 0x3)
@ -605,7 +602,7 @@ error:
}
EXPORT_SYMBOL(cx22702_attach);
static struct dvb_frontend_ops cx22702_ops = {
static const struct dvb_frontend_ops cx22702_ops = {
.info = {
.name = "Conexant CX22702 DVB-T",

View file

@ -310,7 +310,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
}
static int _cx24110_pll_write (struct dvb_frontend* fe, u8 *buf, int len)
static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len)
{
struct cx24110_state *state = fe->demodulator_priv;

View file

@ -1108,7 +1108,6 @@ struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
i2c_set_adapdata(&state->tuner_i2c_adapter, state);

View file

@ -130,7 +130,6 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
struct dibx000_i2c_master *mst)
{
strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo;
i2c_adap->algo_data = NULL;
i2c_set_adapdata(i2c_adap, mst);
if (i2c_add_adapter(i2c_adap) < 0)

View file

@ -232,7 +232,7 @@ static int write_fw(struct drx397xD_state *s, enum blob_ix ix)
exit_rc:
read_unlock(&fw[s->chip_rev].lock);
return 0;
return rc;
}
/* Function is not endian safe, use the RD16 wrapper below */

View file

@ -0,0 +1,323 @@
/**
* Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
*
* Copyright (C) 2010 Malcolm Priestley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 2, as
* published by the Free Software Foundation.
*
* 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/dvb/frontend.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "ix2505v.h"
static int ix2505v_debug;
#define dprintk(level, args...) do { \
if (ix2505v_debug & level) \
printk(KERN_DEBUG "ix2505v: " args); \
} while (0)
#define deb_info(args...) dprintk(0x01, args)
#define deb_i2c(args...) dprintk(0x02, args)
struct ix2505v_state {
struct i2c_adapter *i2c;
const struct ix2505v_config *config;
u32 frequency;
};
/**
* Data read format of the Sharp IX2505V B0017
*
* byte1: 1 | 1 | 0 | 0 | 0 | MA1 | MA0 | 1
* byte2: POR | FL | RD2 | RD1 | RD0 | X | X | X
*
* byte1 = address
* byte2;
* POR = Power on Reset (VCC H=<2.2v L=>2.2v)
* FL = Phase Lock (H=lock L=unlock)
* RD0-2 = Reserved internal operations
*
* Only POR can be used to check the tuner is present
*
* Caution: after byte2 the I2C reverts to write mode continuing to read
* may corrupt tuning data.
*
*/
static int ix2505v_read_status_reg(struct ix2505v_state *state)
{
u8 addr = state->config->tuner_address;
u8 b2[] = {0};
int ret;
struct i2c_msg msg[1] = {
{ .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 }
};
ret = i2c_transfer(state->i2c, msg, 1);
deb_i2c("Read %s ", __func__);
return (ret = 1) ? (int) b2[0] : -1;
}
static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count)
{
struct i2c_msg msg[1] = {
{ .addr = state->config->tuner_address, .flags = 0,
.buf = buf, .len = count },
};
int ret;
ret = i2c_transfer(state->i2c, msg, 1);
if (ret != 1) {
deb_i2c("%s: i2c error, ret=%d\n", __func__, ret);
return -EIO;
}
return 0;
}
static int ix2505v_release(struct dvb_frontend *fe)
{
struct ix2505v_state *state = fe->tuner_priv;
fe->tuner_priv = NULL;
kfree(state);
return 0;
}
/**
* Data write format of the Sharp IX2505V B0017
*
* byte1: 1 | 1 | 0 | 0 | 0 | 0(MA1)| 0(MA0)| 0
* byte2: 0 | BG1 | BG2 | N8 | N7 | N6 | N5 | N4
* byte3: N3 | N2 | N1 | A5 | A4 | A3 | A2 | A1
* byte4: 1 | 1(C1) | 1(C0) | PD5 | PD4 | TM | 0(RTS)| 1(REF)
* byte5: BA2 | BA1 | BA0 | PSC | PD3 |PD2/TS2|DIV/TS1|PD0/TS0
*
* byte1 = address
*
* Write order
* 1) byte1 -> byte2 -> byte3 -> byte4 -> byte5
* 2) byte1 -> byte4 -> byte5 -> byte2 -> byte3
* 3) byte1 -> byte2 -> byte3 -> byte4
* 4) byte1 -> byte4 -> byte5 -> byte2
* 5) byte1 -> byte2 -> byte3
* 6) byte1 -> byte4 -> byte5
* 7) byte1 -> byte2
* 8) byte1 -> byte4
*
* Recommended Setup
* 1 -> 8 -> 6
*/
static int ix2505v_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
struct ix2505v_state *state = fe->tuner_priv;
u32 frequency = params->frequency;
u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000;
u32 div_factor, N , A, x;
int ret = 0, len;
u8 gain, cc, ref, psc, local_osc, lpf;
u8 data[4] = {0};
if ((frequency < fe->ops.info.frequency_min)
|| (frequency > fe->ops.info.frequency_max))
return -EINVAL;
if (state->config->tuner_gain)
gain = (state->config->tuner_gain < 4)
? state->config->tuner_gain : 0;
else
gain = 0x0;
if (state->config->tuner_chargepump)
cc = state->config->tuner_chargepump;
else
cc = 0x3;
ref = 8; /* REF =1 */
psc = 32; /* PSC = 0 */
div_factor = (frequency * ref) / 40; /* local osc = 4Mhz */
x = div_factor / psc;
N = x/100;
A = ((x - (N * 100)) * psc) / 100;
data[0] = ((gain & 0x3) << 5) | (N >> 3);
data[1] = (N << 5) | (A & 0x1f);
data[2] = 0x81 | ((cc & 0x3) << 5) ; /*PD5,PD4 & TM = 0|C1,C0|REF=1*/
deb_info("Frq=%d x=%d N=%d A=%d\n", frequency, x, N, A);
if (frequency <= 1065000)
local_osc = (6 << 5) | 2;
else if (frequency <= 1170000)
local_osc = (7 << 5) | 2;
else if (frequency <= 1300000)
local_osc = (1 << 5);
else if (frequency <= 1445000)
local_osc = (2 << 5);
else if (frequency <= 1607000)
local_osc = (3 << 5);
else if (frequency <= 1778000)
local_osc = (4 << 5);
else if (frequency <= 1942000)
local_osc = (5 << 5);
else /*frequency up to 2150000*/
local_osc = (6 << 5);
data[3] = local_osc; /* all other bits set 0 */
if (b_w <= 10000)
lpf = 0xc;
else if (b_w <= 12000)
lpf = 0x2;
else if (b_w <= 14000)
lpf = 0xa;
else if (b_w <= 16000)
lpf = 0x6;
else if (b_w <= 18000)
lpf = 0xe;
else if (b_w <= 20000)
lpf = 0x1;
else if (b_w <= 22000)
lpf = 0x9;
else if (b_w <= 24000)
lpf = 0x5;
else if (b_w <= 26000)
lpf = 0xd;
else if (b_w <= 28000)
lpf = 0x3;
else
lpf = 0xb;
deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf);
deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
len = sizeof(data);
ret |= ix2505v_write(state, data, len);
data[2] |= 0x4; /* set TM = 1 other bits same */
len = 1;
ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */
msleep(10);
data[2] |= ((lpf >> 2) & 0x3) << 3; /* lpf */
data[3] |= (lpf & 0x3) << 2;
deb_info("Data 2=[%x%x]\n", data[2], data[3]);
len = 2;
ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
if (state->config->min_delay_ms)
msleep(state->config->min_delay_ms);
state->frequency = frequency;
return ret;
}
static int ix2505v_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct ix2505v_state *state = fe->tuner_priv;
*frequency = state->frequency;
return 0;
}
static struct dvb_tuner_ops ix2505v_tuner_ops = {
.info = {
.name = "Sharp IX2505V (B0017)",
.frequency_min = 950000,
.frequency_max = 2175000
},
.release = ix2505v_release,
.set_params = ix2505v_set_params,
.get_frequency = ix2505v_get_frequency,
};
struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
const struct ix2505v_config *config,
struct i2c_adapter *i2c)
{
struct ix2505v_state *state = NULL;
int ret;
if (NULL == config) {
deb_i2c("%s: no config ", __func__);
goto error;
}
state = kzalloc(sizeof(struct ix2505v_state), GFP_KERNEL);
if (NULL == state)
return NULL;
state->config = config;
state->i2c = i2c;
if (state->config->tuner_write_only) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
ret = ix2505v_read_status_reg(state);
if (ret & 0x80) {
deb_i2c("%s: No IX2505V found\n", __func__);
goto error;
}
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
fe->tuner_priv = state;
memcpy(&fe->ops.tuner_ops, &ix2505v_tuner_ops,
sizeof(struct dvb_tuner_ops));
deb_i2c("%s: initialization (%s addr=0x%02x) ok\n",
__func__, fe->ops.tuner_ops.info.name, config->tuner_address);
return fe;
error:
ix2505v_release(fe);
return NULL;
}
EXPORT_SYMBOL(ix2505v_attach);
module_param_named(debug, ix2505v_debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
MODULE_DESCRIPTION("DVB IX2505V tuner driver");
MODULE_AUTHOR("Malcolm Priestley");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,64 @@
/**
* Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
*
* Copyright (C) 2010 Malcolm Priestley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef DVB_IX2505V_H
#define DVB_IX2505V_H
#include <linux/i2c.h>
#include "dvb_frontend.h"
/**
* Attach a ix2505v tuner to the supplied frontend structure.
*
* @param fe Frontend to attach to.
* @param config ix2505v_config structure
* @return FE pointer on success, NULL on failure.
*/
struct ix2505v_config {
u8 tuner_address;
/*Baseband AMP gain control 0/1=0dB(default) 2=-2bB 3=-4dB */
u8 tuner_gain;
/*Charge pump output +/- 0=120 1=260 2=555 3=1200(default) */
u8 tuner_chargepump;
/* delay after tune */
int min_delay_ms;
/* disables reads*/
u8 tuner_write_only;
};
#if defined(CONFIG_DVB_IX2505V) || \
(defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE))
extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
const struct ix2505v_config *config, struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
const struct ix2505v_config *config, struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
#endif /* DVB_IX2505V_H */

View file

@ -1,380 +0,0 @@
/*
* Driver for LG ATSC lgdt3304 driver
*
* Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "lgdt3304.h"
static unsigned int debug = 0;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
#define dprintk(fmt, args...) if (debug) do {\
printk("lgdt3304 debug: " fmt, ##args); } while (0)
struct lgdt3304_state
{
struct dvb_frontend frontend;
fe_modulation_t current_modulation;
__u32 snr;
__u32 current_frequency;
__u8 addr;
struct i2c_adapter *i2c;
};
static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
{
struct lgdt3304_state *state = fe->demodulator_priv;
struct i2c_msg i2cmsgs = {
.addr = state->addr,
.flags = 0,
.len = 3,
.buf = buf
};
int i;
int err;
for (i=0; i<len-1; i+=3){
if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
printk("%s i2c_transfer error %d\n", __func__, err);
if (err < 0)
return err;
else
return -EREMOTEIO;
}
i2cmsgs.buf += 3;
}
return 0;
}
static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
{
struct lgdt3304_state *state = fe->demodulator_priv;
struct i2c_msg i2cmsgs[2];
int ret;
__u8 buf;
__u8 regbuf[2] = { reg>>8, reg&0xff };
i2cmsgs[0].addr = state->addr;
i2cmsgs[0].flags = 0;
i2cmsgs[0].len = 2;
i2cmsgs[0].buf = regbuf;
i2cmsgs[1].addr = state->addr;
i2cmsgs[1].flags = I2C_M_RD;
i2cmsgs[1].len = 1;
i2cmsgs[1].buf = &buf;
if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
printk("%s i2c_transfer error %d\n", __func__, ret);
return ret;
}
return buf;
}
static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
{
struct lgdt3304_state *state = fe->demodulator_priv;
char buffer[3] = { reg>>8, reg&0xff, val };
int ret;
struct i2c_msg i2cmsgs = {
.addr = state->addr,
.flags = 0,
.len = 3,
.buf=buffer
};
ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
if (ret != 1) {
printk("%s i2c_transfer error %d\n", __func__, ret);
return ret;
}
return 0;
}
static int lgdt3304_soft_Reset(struct dvb_frontend *fe)
{
lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a);
lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b);
mdelay(200);
return 0;
}
static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
int err = 0;
static __u8 lgdt3304_vsb8_data[] = {
/* 16bit , 8bit */
/* regs , val */
0x00, 0x00, 0x02,
0x00, 0x00, 0x13,
0x00, 0x0d, 0x02,
0x00, 0x0e, 0x02,
0x00, 0x12, 0x32,
0x00, 0x13, 0xc4,
0x01, 0x12, 0x17,
0x01, 0x13, 0x15,
0x01, 0x14, 0x18,
0x01, 0x15, 0xff,
0x01, 0x16, 0x2c,
0x02, 0x14, 0x67,
0x02, 0x24, 0x8d,
0x04, 0x27, 0x12,
0x04, 0x28, 0x4f,
0x03, 0x08, 0x80,
0x03, 0x09, 0x00,
0x03, 0x0d, 0x00,
0x03, 0x0e, 0x1c,
0x03, 0x14, 0xe1,
0x05, 0x0e, 0x5b,
};
/* not yet tested .. */
static __u8 lgdt3304_qam64_data[] = {
/* 16bit , 8bit */
/* regs , val */
0x00, 0x00, 0x18,
0x00, 0x0d, 0x02,
//0x00, 0x0e, 0x02,
0x00, 0x12, 0x2a,
0x00, 0x13, 0x00,
0x03, 0x14, 0xe3,
0x03, 0x0e, 0x1c,
0x03, 0x08, 0x66,
0x03, 0x09, 0x66,
0x03, 0x0a, 0x08,
0x03, 0x0b, 0x9b,
0x05, 0x0e, 0x5b,
};
/* tested with KWorld a340 */
static __u8 lgdt3304_qam256_data[] = {
/* 16bit , 8bit */
/* regs , val */
0x00, 0x00, 0x01, //0x19,
0x00, 0x12, 0x2a,
0x00, 0x13, 0x80,
0x00, 0x0d, 0x02,
0x03, 0x14, 0xe3,
0x03, 0x0e, 0x1c,
0x03, 0x08, 0x66,
0x03, 0x09, 0x66,
0x03, 0x0a, 0x08,
0x03, 0x0b, 0x9b,
0x03, 0x0d, 0x14,
//0x05, 0x0e, 0x5b,
0x01, 0x06, 0x4a,
0x01, 0x07, 0x3d,
0x01, 0x08, 0x70,
0x01, 0x09, 0xa3,
0x05, 0x04, 0xfd,
0x00, 0x0d, 0x82,
0x05, 0x0e, 0x5b,
0x05, 0x0e, 0x5b,
0x00, 0x02, 0x9a,
0x00, 0x02, 0x9b,
0x00, 0x00, 0x01,
0x00, 0x12, 0x2a,
0x00, 0x13, 0x80,
0x00, 0x0d, 0x02,
0x03, 0x14, 0xe3,
0x03, 0x0e, 0x1c,
0x03, 0x08, 0x66,
0x03, 0x09, 0x66,
0x03, 0x0a, 0x08,
0x03, 0x0b, 0x9b,
0x03, 0x0d, 0x14,
0x01, 0x06, 0x4a,
0x01, 0x07, 0x3d,
0x01, 0x08, 0x70,
0x01, 0x09, 0xa3,
0x05, 0x04, 0xfd,
0x00, 0x0d, 0x82,
0x05, 0x0e, 0x5b,
};
struct lgdt3304_state *state = fe->demodulator_priv;
if (state->current_modulation != param->u.vsb.modulation) {
switch(param->u.vsb.modulation) {
case VSB_8:
err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data,
sizeof(lgdt3304_vsb8_data));
break;
case QAM_64:
err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data,
sizeof(lgdt3304_qam64_data));
break;
case QAM_256:
err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data,
sizeof(lgdt3304_qam256_data));
break;
default:
break;
}
if (err) {
printk("%s error setting modulation\n", __func__);
} else {
state->current_modulation = param->u.vsb.modulation;
}
}
state->current_frequency = param->frequency;
lgdt3304_soft_Reset(fe);
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, param);
return 0;
}
static int lgdt3304_init(struct dvb_frontend *fe) {
return 0;
}
static int lgdt3304_sleep(struct dvb_frontend *fe) {
return 0;
}
static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct lgdt3304_state *state = fe->demodulator_priv;
int r011d;
int qam_lck;
*status = 0;
dprintk("lgdt read status\n");
r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
dprintk("%02x\n", r011d);
switch(state->current_modulation) {
case VSB_8:
if (r011d & 0x80) {
dprintk("VSB Locked\n");
*status |= FE_HAS_CARRIER;
*status |= FE_HAS_LOCK;
*status |= FE_HAS_SYNC;
*status |= FE_HAS_SIGNAL;
}
break;
case QAM_64:
case QAM_256:
qam_lck = r011d & 0x7;
switch(qam_lck) {
case 0x0: dprintk("Unlock\n");
break;
case 0x4: dprintk("1st Lock in acquisition state\n");
break;
case 0x6: dprintk("2nd Lock in acquisition state\n");
break;
case 0x7: dprintk("Final Lock in good reception state\n");
*status |= FE_HAS_CARRIER;
*status |= FE_HAS_LOCK;
*status |= FE_HAS_SYNC;
*status |= FE_HAS_SIGNAL;
break;
}
break;
default:
printk("%s unhandled modulation\n", __func__);
}
return 0;
}
static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
{
dprintk("read ber\n");
return 0;
}
static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
{
dprintk("read snr\n");
return 0;
}
static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
{
dprintk("read ucblocks\n");
return 0;
}
static void lgdt3304_release(struct dvb_frontend *fe)
{
struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops demod_lgdt3304={
.info = {
.name = "LG 3304",
.type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
.symbol_rate_min = 5056941,
.symbol_rate_max = 10762000,
.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
},
.init = lgdt3304_init,
.sleep = lgdt3304_sleep,
.set_frontend = lgdt3304_set_parameters,
.read_snr = lgdt3304_read_snr,
.read_ber = lgdt3304_read_ber,
.read_status = lgdt3304_read_status,
.read_ucblocks = lgdt3304_read_ucblocks,
.release = lgdt3304_release,
};
struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
struct i2c_adapter *i2c)
{
struct lgdt3304_state *state;
state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
if (state == NULL)
return NULL;
state->addr = config->i2c_address;
state->i2c = i2c;
memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
EXPORT_SYMBOL_GPL(lgdt3304_attach);
MODULE_AUTHOR("Markus Rechberger <[email protected]>");
MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver");
MODULE_LICENSE("GPL");

View file

@ -1,45 +0,0 @@
/*
* Driver for DVB-T lgdt3304 demodulator
*
* Copyright (C) 2008 Markus Rechberger <mrechberger@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.=
*/
#ifndef LGDT3304_H
#define LGDT3304_H
#include <linux/dvb/frontend.h>
struct lgdt3304_config
{
/* demodulator's I2C address */
u8 i2c_address;
};
#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE))
extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_LGDT */
#endif /* LGDT3304_H */

View file

@ -662,7 +662,7 @@ static void lgs8gxx_release(struct dvb_frontend *fe)
}
static int lgs8gxx_write(struct dvb_frontend *fe, u8 *buf, int len)
static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;

View file

@ -69,7 +69,7 @@ static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
return 0;
}
static int _mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
static int _mt352_write(struct dvb_frontend* fe, const u8 ibuf[], int ilen)
{
int err,i;
for (i=0; i < ilen-1; i++)

View file

@ -63,7 +63,7 @@ static inline struct dvb_frontend* mt352_attach(const struct mt352_config* confi
}
#endif // CONFIG_DVB_MT352
static inline int mt352_write(struct dvb_frontend *fe, u8 *buf, int len) {
static inline int mt352_write(struct dvb_frontend *fe, const u8 buf[], int len) {
int r = 0;
if (fe->ops.write)
r = fe->ops.write(fe, buf, len);

View file

@ -920,7 +920,6 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
/* create tuner i2c adapter */
strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
i2c_set_adapdata(&state->tuner_i2c_adapter, state);

View file

@ -0,0 +1,415 @@
/*
* Samsung s5h1432 DVB-T demodulator driver
*
* Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
#include "s5h1432.h"
struct s5h1432_state {
struct i2c_adapter *i2c;
/* configuration settings */
const struct s5h1432_config *config;
struct dvb_frontend frontend;
fe_modulation_t current_modulation;
unsigned int first_tune:1;
u32 current_frequency;
int if_freq;
u8 inversion;
};
static int debug;
#define dprintk(arg...) do { \
if (debug) \
printk(arg); \
} while (0)
static int s5h1432_writereg(struct s5h1432_state *state,
u8 addr, u8 reg, u8 data)
{
int ret;
u8 buf[] = { reg, data };
struct i2c_msg msg = {.addr = addr, .flags = 0, .buf = buf, .len = 2 };
ret = i2c_transfer(state->i2c, &msg, 1);
if (ret != 1)
printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
"ret == %i)\n", __func__, addr, reg, data, ret);
return (ret != 1) ? -1 : 0;
}
static u8 s5h1432_readreg(struct s5h1432_state *state, u8 addr, u8 reg)
{
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
struct i2c_msg msg[] = {
{.addr = addr, .flags = 0, .buf = b0, .len = 1},
{.addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1}
};
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2)
printk(KERN_ERR "%s: readreg error (ret == %i)\n",
__func__, ret);
return b1[0];
}
static int s5h1432_sleep(struct dvb_frontend *fe)
{
return 0;
}
static int s5h1432_set_channel_bandwidth(struct dvb_frontend *fe,
u32 bandwidth)
{
struct s5h1432_state *state = fe->demodulator_priv;
u8 reg = 0;
/* Register [0x2E] bit 3:2 : 8MHz = 0; 7MHz = 1; 6MHz = 2 */
reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x2E);
reg &= ~(0x0C);
switch (bandwidth) {
case 6:
reg |= 0x08;
break;
case 7:
reg |= 0x04;
break;
case 8:
reg |= 0x00;
break;
default:
return 0;
}
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2E, reg);
return 1;
}
static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz)
{
struct s5h1432_state *state = fe->demodulator_priv;
switch (ifFreqHz) {
case TAIWAN_HI_IF_FREQ_44_MHZ:
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x15);
break;
case EUROPE_HI_IF_FREQ_36_MHZ:
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x40);
break;
case IF_FREQ_6_MHZ:
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xe0);
break;
case IF_FREQ_3point3_MHZ:
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
break;
case IF_FREQ_3point5_MHZ:
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xED);
break;
case IF_FREQ_4_MHZ:
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0xAA);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0xAA);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEA);
break;
default:
{
u32 value = 0;
value = (u32) (((48000 - (ifFreqHz / 1000)) * 512 *
(u32) 32768) / (48 * 1000));
printk(KERN_INFO
"Default IFFreq %d :reg value = 0x%x\n",
ifFreqHz, value);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4,
(u8) value & 0xFF);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5,
(u8) (value >> 8) & 0xFF);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7,
(u8) (value >> 16) & 0xFF);
break;
}
}
return 1;
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
static int s5h1432_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
u32 dvb_bandwidth = 8;
struct s5h1432_state *state = fe->demodulator_priv;
if (p->frequency == state->current_frequency) {
/*current_frequency = p->frequency; */
/*state->current_frequency = p->frequency; */
} else {
fe->ops.tuner_ops.set_params(fe, p);
msleep(300);
s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
switch (p->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
dvb_bandwidth = 6;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
case BANDWIDTH_7_MHZ:
dvb_bandwidth = 7;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
case BANDWIDTH_8_MHZ:
dvb_bandwidth = 8;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
default:
return 0;
}
/*fe->ops.tuner_ops.set_params(fe, p); */
/*Soft Reset chip*/
msleep(30);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
msleep(30);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
switch (p->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
dvb_bandwidth = 6;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
case BANDWIDTH_7_MHZ:
dvb_bandwidth = 7;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
case BANDWIDTH_8_MHZ:
dvb_bandwidth = 8;
s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
break;
default:
return 0;
}
/*fe->ops.tuner_ops.set_params(fe,p); */
/*Soft Reset chip*/
msleep(30);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
msleep(30);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
}
state->current_frequency = p->frequency;
return 0;
}
static int s5h1432_init(struct dvb_frontend *fe)
{
struct s5h1432_state *state = fe->demodulator_priv;
u8 reg = 0;
state->current_frequency = 0;
printk(KERN_INFO " s5h1432_init().\n");
/*Set VSB mode as default, this also does a soft reset */
/*Initialize registers */
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x04, 0xa8);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x05, 0x01);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x07, 0x70);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x19, 0x80);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1b, 0x9D);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1c, 0x30);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1d, 0x20);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x1B);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2e, 0x40);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, 0x84);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x50, 0x5a);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x5a, 0xd3);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x68, 0x50);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xb8, 0x3c);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xc4, 0x10);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xcc, 0x9c);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xDA, 0x00);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe1, 0x94);
/* s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf4, 0xa1); */
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf9, 0x00);
/*For NXP tuner*/
/*Set 3.3MHz as default IF frequency */
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
/* Set reg 0x1E to get the full dynamic range */
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x31);
/* Mode setting in demod */
reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x42);
reg |= 0x80;
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, reg);
/* Serial mode */
/* Soft Reset chip */
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
msleep(30);
s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
return 0;
}
static int s5h1432_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
return 0;
}
static int s5h1432_read_signal_strength(struct dvb_frontend *fe,
u16 *signal_strength)
{
return 0;
}
static int s5h1432_read_snr(struct dvb_frontend *fe, u16 *snr)
{
return 0;
}
static int s5h1432_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
return 0;
}
static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber)
{
return 0;
}
static int s5h1432_get_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
return 0;
}
static int s5h1432_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *tune)
{
return 0;
}
static void s5h1432_release(struct dvb_frontend *fe)
{
struct s5h1432_state *state = fe->demodulator_priv;
kfree(state);
}
static struct dvb_frontend_ops s5h1432_ops;
struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
struct i2c_adapter *i2c)
{
struct s5h1432_state *state = NULL;
printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n");
/* allocate memory for the internal state */
state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL);
if (state == NULL)
goto error;
/* setup the state */
state->config = config;
state->i2c = i2c;
state->current_modulation = QAM_16;
state->inversion = state->config->inversion;
/* create dvb_frontend */
memcpy(&state->frontend.ops, &s5h1432_ops,
sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
error:
kfree(state);
return NULL;
}
EXPORT_SYMBOL(s5h1432_attach);
static struct dvb_frontend_ops s5h1432_ops = {
.info = {
.name = "Samsung s5h1432 DVB-T Frontend",
.type = FE_OFDM,
.frequency_min = 177000000,
.frequency_max = 858000000,
.frequency_stepsize = 166666,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER},
.init = s5h1432_init,
.sleep = s5h1432_sleep,
.set_frontend = s5h1432_set_frontend,
.get_frontend = s5h1432_get_frontend,
.get_tune_settings = s5h1432_get_tune_settings,
.read_status = s5h1432_read_status,
.read_ber = s5h1432_read_ber,
.read_signal_strength = s5h1432_read_signal_strength,
.read_snr = s5h1432_read_snr,
.read_ucblocks = s5h1432_read_ucblocks,
.release = s5h1432_release,
};
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
MODULE_DESCRIPTION("Samsung s5h1432 DVB-T Demodulator driver");
MODULE_AUTHOR("Bill Liu");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,91 @@
/*
* Samsung s5h1432 VSB/QAM demodulator driver
*
* Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __S5H1432_H__
#define __S5H1432_H__
#include <linux/dvb/frontend.h>
#define S5H1432_I2C_TOP_ADDR (0x02 >> 1)
#define TAIWAN_HI_IF_FREQ_44_MHZ 44000000
#define EUROPE_HI_IF_FREQ_36_MHZ 36000000
#define IF_FREQ_6_MHZ 6000000
#define IF_FREQ_3point3_MHZ 3300000
#define IF_FREQ_3point5_MHZ 3500000
#define IF_FREQ_4_MHZ 4000000
struct s5h1432_config {
/* serial/parallel output */
#define S5H1432_PARALLEL_OUTPUT 0
#define S5H1432_SERIAL_OUTPUT 1
u8 output_mode;
/* GPIO Setting */
#define S5H1432_GPIO_OFF 0
#define S5H1432_GPIO_ON 1
u8 gpio;
/* MPEG signal timing */
#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
u16 mpeg_timing;
/* IF Freq for QAM and VSB in KHz */
#define S5H1432_IF_3250 3250
#define S5H1432_IF_3500 3500
#define S5H1432_IF_4000 4000
#define S5H1432_IF_5380 5380
#define S5H1432_IF_44000 44000
#define S5H1432_VSB_IF_DEFAULT s5h1432_IF_44000
#define S5H1432_QAM_IF_DEFAULT s5h1432_IF_44000
u16 qam_if;
u16 vsb_if;
/* Spectral Inversion */
#define S5H1432_INVERSION_OFF 0
#define S5H1432_INVERSION_ON 1
u8 inversion;
/* Return lock status based on tuner lock, or demod lock */
#define S5H1432_TUNERLOCKING 0
#define S5H1432_DEMODLOCKING 1
u8 status_mode;
};
#if defined(CONFIG_DVB_S5H1432) || \
(defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE))
extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *s5h1432_attach(const struct s5h1432_config
*config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_s5h1432 */
#endif /* __s5h1432_H__ */

View file

@ -268,7 +268,7 @@ static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
static int si21_write(struct dvb_frontend *fe, u8 *buf, int len)
static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct si21xx_state *state = fe->demodulator_priv;

View file

@ -506,7 +506,7 @@ static struct dvb_tuner_ops stb6100_ops = {
};
struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
struct stb6100_config *config,
const struct stb6100_config *config,
struct i2c_adapter *i2c)
{
struct stb6100_state *state = NULL;

View file

@ -97,13 +97,13 @@ struct stb6100_state {
#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
struct stb6100_config *config,
const struct stb6100_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
struct stb6100_config *config,
const struct stb6100_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);

View file

@ -6,6 +6,8 @@
Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
Removed stb6000 specific tuner code and revised some
procedures.
2010-09-01 Josef Pavlik <josef@pavlik.it>
Fixed diseqc_msg, diseqc_burst and set_tone problems
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
@ -78,7 +80,7 @@ static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len)
static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct stv0288_state *state = fe->demodulator_priv;
@ -156,14 +158,13 @@ static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
stv0288_writeregI(state, 0x09, 0);
msleep(30);
stv0288_writeregI(state, 0x05, 0x16);
stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */
for (i = 0; i < m->msg_len; i++) {
if (stv0288_writeregI(state, 0x06, m->msg[i]))
return -EREMOTEIO;
msleep(12);
}
msleep(m->msg_len*12);
return 0;
}
@ -174,13 +175,14 @@ static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
dprintk("%s\n", __func__);
if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */
if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */
return -EREMOTEIO;
if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
return -EREMOTEIO;
if (stv0288_writeregI(state, 0x06, 0x12))
msleep(15);
if (stv0288_writeregI(state, 0x05, 0x12))
return -EREMOTEIO;
return 0;
@ -192,18 +194,19 @@ static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
switch (tone) {
case SEC_TONE_ON:
if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */
if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */
return -EREMOTEIO;
return stv0288_writeregI(state, 0x06, 0xff);
break;
case SEC_TONE_OFF:
if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */
if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/
return -EREMOTEIO;
return stv0288_writeregI(state, 0x06, 0x00);
break;
default:
return -EINVAL;
}
return 0;
}
static u8 stv0288_inittab[] = {
@ -486,7 +489,7 @@ static int stv0288_set_frontend(struct dvb_frontend *fe,
tda[2] = 0x0; /* CFRL */
for (tm = -6; tm < 7;) {
/* Viterbi status */
if (stv0288_readreg(state, 0x24) & 0x80)
if (stv0288_readreg(state, 0x24) & 0x8)
break;
tda[2] += 40;

View file

@ -92,7 +92,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
static int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len)
{
struct stv0299_state* state = fe->demodulator_priv;

View file

@ -65,7 +65,7 @@ struct stv0299_config
* First of each pair is the register, second is the value.
* List should be terminated with an 0xff, 0xff pair.
*/
u8* inittab;
const u8* inittab;
/* master clock to use */
u32 mclk;

View file

@ -598,7 +598,7 @@ static int tda1004x_decode_fec(int tdafec)
return -1;
}
static int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len)
{
struct tda1004x_state* state = fe->demodulator_priv;

Some files were not shown because too many files have changed in this diff Show more