diff options
Diffstat (limited to 'drivers')
95 files changed, 11971 insertions, 5026 deletions
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig index 999a8250b3c..30e04915a25 100644 --- a/drivers/media/IR/Kconfig +++ b/drivers/media/IR/Kconfig @@ -1,8 +1,10 @@ -config IR_CORE - tristate +menuconfig IR_CORE + tristate "Infrared remote controller adapters" depends on INPUT default INPUT +if IR_CORE + config VIDEO_IR tristate depends on IR_CORE @@ -16,7 +18,7 @@ config LIRC Enable this option to build the Linux Infrared Remote Control (LIRC) core device interface driver. The LIRC interface passes raw IR to and from userspace, where the - LIRC daemon handles protocol decoding for IR reception ann + LIRC daemon handles protocol decoding for IR reception and encoding for IR transmitting (aka "blasting"). source "drivers/media/IR/keymaps/Kconfig" @@ -103,3 +105,31 @@ 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)" + 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. + + To compile this driver as a module, choose M here: the + module will be called ene_ir. + +config IR_STREAMZAP + tristate "Streamzap PC Remote IR Receiver" + depends on USB_ARCH_HAS_HCD + depends on IR_CORE + select USB + ---help--- + Say Y here if you want to use a Streamzap PC Remote + Infrared Receiver. + + To compile this driver as a module, choose M here: the + module will be called streamzap. + +endif #IR_CORE diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile index 2ae4f3abfdb..53676838fe9 100644 --- a/drivers/media/IR/Makefile +++ b/drivers/media/IR/Makefile @@ -16,3 +16,5 @@ 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_ENE) += ene_ir.o +obj-$(CONFIG_IR_STREAMZAP) += streamzap.o diff --git a/drivers/media/IR/ene_ir.c b/drivers/media/IR/ene_ir.c new file mode 100644 index 00000000000..5447750f5e3 --- /dev/null +++ b/drivers/media/IR/ene_ir.c @@ -0,0 +1,1023 @@ +/* + * driver for ENE KB3926 B/C/D CIR (pnp id: ENE0XXX) + * + * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pnp.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <media/ir-core.h> +#include <media/ir-common.h> +#include "ene_ir.h" + + +static int sample_period = -1; +static int enable_idle = 1; +static int input = 1; +static int debug; +static int txsim; + +static int ene_irq_status(struct ene_device *dev); + +/* read a hardware register */ +static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) +{ + u8 retval; + outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); + outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); + retval = inb(dev->hw_io + ENE_IO); + + ene_dbg_verbose("reg %04x == %02x", reg, retval); + return retval; +} + +/* write a hardware register */ +static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value) +{ + outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); + outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); + outb(value, dev->hw_io + ENE_IO); + + ene_dbg_verbose("reg %04x <- %02x", reg, value); +} + +/* change specific bits in hardware register */ +static void ene_hw_write_reg_mask(struct ene_device *dev, + u16 reg, u8 value, u8 mask) +{ + u8 regvalue; + + outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); + outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); + + regvalue = inb(dev->hw_io + ENE_IO) & ~mask; + regvalue |= (value & mask); + outb(regvalue, dev->hw_io + ENE_IO); + + ene_dbg_verbose("reg %04x <- %02x (mask=%02x)", reg, value, mask); +} + +/* detect hardware features */ +static int ene_hw_detect(struct ene_device *dev) +{ + u8 chip_major, chip_minor; + u8 hw_revision, old_ver; + u8 tmp; + u8 fw_capabilities; + int pll_freq; + + tmp = ene_hw_read_reg(dev, ENE_HW_UNK); + ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR); + + chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR); + chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR); + + ene_hw_write_reg(dev, ENE_HW_UNK, tmp); + hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION); + old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD); + + pll_freq = (ene_hw_read_reg(dev, ENE_PLLFRH) << 4) + + (ene_hw_read_reg(dev, ENE_PLLFRL) >> 4); + + if (pll_freq != 1000) + dev->rx_period_adjust = 4; + else + dev->rx_period_adjust = 2; + + + ene_printk(KERN_NOTICE, "PLL freq = %d\n", pll_freq); + + if (hw_revision == 0xFF) { + + ene_printk(KERN_WARNING, "device seems to be disabled\n"); + ene_printk(KERN_WARNING, + "send a mail to lirc-list@lists.sourceforge.net\n"); + ene_printk(KERN_WARNING, "please attach output of acpidump\n"); + return -ENODEV; + } + + if (chip_major == 0x33) { + ene_printk(KERN_WARNING, "chips 0x33xx aren't supported\n"); + return -ENODEV; + } + + if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { + dev->hw_revision = ENE_HW_C; + } else if (old_ver == 0x24 && hw_revision == 0xC0) { + dev->hw_revision = ENE_HW_B; + ene_printk(KERN_NOTICE, "KB3926B detected\n"); + } else { + dev->hw_revision = ENE_HW_D; + ene_printk(KERN_WARNING, + "unknown ENE chip detected, assuming KB3926D\n"); + ene_printk(KERN_WARNING, + "driver support might be not complete"); + + } + + ene_printk(KERN_DEBUG, + "chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x\n", + chip_major, chip_minor, old_ver, hw_revision); + + /* detect features hardware supports */ + if (dev->hw_revision < ENE_HW_C) + return 0; + + fw_capabilities = ene_hw_read_reg(dev, ENE_FW2); + ene_dbg("Firmware capabilities: %02x", fw_capabilities); + + dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN; + dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING; + + dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable && + (fw_capabilities & ENE_FW2_FAN_AS_NRML_IN); + + ene_printk(KERN_NOTICE, "hardware features:\n"); + ene_printk(KERN_NOTICE, + "learning and transmit %s, gpio40_learn %s, fan_in %s\n", + dev->hw_learning_and_tx_capable ? "on" : "off", + dev->hw_gpio40_learning ? "on" : "off", + dev->hw_fan_as_normal_input ? "on" : "off"); + + if (dev->hw_learning_and_tx_capable) { + ene_printk(KERN_WARNING, + "Device supports transmitting, but that support is\n"); + ene_printk(KERN_WARNING, + "lightly tested. Please test it and mail\n"); + ene_printk(KERN_WARNING, + "lirc-list@lists.sourceforge.net\n"); + } + return 0; +} + +/* this enables/disables IR input via gpio40*/ +static void ene_enable_gpio40_receive(struct ene_device *dev, int enable) +{ + ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, enable ? + 0 : ENE_CIR_CONF2_GPIO40DIS, + ENE_CIR_CONF2_GPIO40DIS); +} + +/* this enables/disables IR via standard input */ +static void ene_enable_normal_receive(struct ene_device *dev, int enable) +{ + ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_RX_ON : 0); +} + +/* this enables/disables IR input via unused fan tachtometer input */ +static void ene_enable_fan_receive(struct ene_device *dev, int enable) +{ + if (!enable) + ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0); + else { + ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); + ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); + } + dev->rx_fan_input_inuse = enable; +} + + +/* Sense current received carrier */ +static int ene_rx_sense_carrier(struct ene_device *dev) +{ + int period = ene_hw_read_reg(dev, ENE_RX_CARRIER); + int carrier; + ene_dbg("RX: hardware carrier period = %02x", period); + + if (!(period & ENE_RX_CARRIER_VALID)) + return 0; + + period &= ~ENE_RX_CARRIER_VALID; + + if (!period) + return 0; + + carrier = 2000000 / period; + ene_dbg("RX: sensed carrier = %d Hz", carrier); + return carrier; +} + +/* determine which input to use*/ +static void ene_rx_set_inputs(struct ene_device *dev) +{ + int learning_mode = dev->learning_enabled; + + ene_dbg("RX: setup receiver, learning mode = %d", learning_mode); + + ene_enable_normal_receive(dev, 1); + + /* old hardware doesn't support learning mode for sure */ + if (dev->hw_revision <= ENE_HW_B) + return; + + /* receiver not learning capable, still set gpio40 correctly */ + if (!dev->hw_learning_and_tx_capable) { + ene_enable_gpio40_receive(dev, !dev->hw_gpio40_learning); + return; + } + + /* enable learning mode */ + if (learning_mode) { + ene_enable_gpio40_receive(dev, dev->hw_gpio40_learning); + + /* fan input is not used for learning */ + if (dev->hw_fan_as_normal_input) + ene_enable_fan_receive(dev, 0); + + /* disable learning mode */ + } else { + if (dev->hw_fan_as_normal_input) { + ene_enable_fan_receive(dev, 1); + ene_enable_normal_receive(dev, 0); + } else + ene_enable_gpio40_receive(dev, + !dev->hw_gpio40_learning); + } + + /* set few additional settings for this mode */ + ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_mode ? + ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1); + + ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_mode ? + ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); + + if (dev->rx_fan_input_inuse) { + dev->props->rx_resolution = ENE_SAMPLE_PERIOD_FAN * 1000; + + dev->props->timeout = + ENE_FAN_VALUE_MASK * ENE_SAMPLE_PERIOD_FAN * 1000; + } else { + dev->props->rx_resolution = sample_period * 1000; + dev->props->timeout = ENE_MAXGAP * 1000; + } +} + +/* Enable the device for receive */ +static void ene_rx_enable(struct ene_device *dev) +{ + u8 reg_value; + + if |