From b632d1b397075d71b59bca414854fe06523d9be6 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Thu, 29 Jul 2010 19:34:44 +0200 Subject: [PATCH] linux: update to linux-2.6.35-rc6, add backported lirc drivers from upcoming 2.6.36 Signed-off-by: Stephan Raue --- packages/linux/build | 3 - packages/linux/install | 5 - packages/linux/meta | 14 + ...2.6.33-02-add_lirc_driver_nct667x-0.5.diff | 3700 --------- ...ff => 021-linux-2.6.35-squashfs_lzma.diff} | 107 +- .../036-linux-2.6-cantiga-iommu-gfx.diff | 26 - .../linux-2.6-v4l-dvb-ir-core-update.diff | 6741 +++++++++++++++++ ...0407-0.1.diff => lirc-staging-2.6.36.diff} | 5753 +------------- packages/linux/url | 1 - 9 files changed, 7114 insertions(+), 9236 deletions(-) create mode 100644 packages/linux/meta delete mode 100644 packages/linux/patches/015-linux-2.6.33-02-add_lirc_driver_nct667x-0.5.diff rename packages/linux/patches/{021-linux-2.6.34-squashfs_lzma.diff => 021-linux-2.6.35-squashfs_lzma.diff} (77%) delete mode 100644 packages/linux/patches/036-linux-2.6-cantiga-iommu-gfx.diff create mode 100644 packages/linux/patches/linux-2.6-v4l-dvb-ir-core-update.diff rename packages/linux/patches/{014-linux-2.6.33-01-add_lirc_drivers-20100407-0.1.diff => lirc-staging-2.6.36.diff} (65%) delete mode 100644 packages/linux/url diff --git a/packages/linux/build b/packages/linux/build index 6eea11d0e6..d994901cf2 100755 --- a/packages/linux/build +++ b/packages/linux/build @@ -2,9 +2,6 @@ . config/options $1 -$SCRIPTS/build toolchain -$SCRIPTS/build busybox-hosttools - export INSTALL=$(kernel_path) $SCRIPTS/install busybox-initramfs diff --git a/packages/linux/install b/packages/linux/install index e79bce2041..60441c9823 100755 --- a/packages/linux/install +++ b/packages/linux/install @@ -2,9 +2,6 @@ . config/options $1 -$SCRIPTS/build busybox-hosttools -$SCRIPTS/install busybox - RAMFS_DRV_SUBSYSTEMS="ata ide scsi" VER=`ls $PKG_BUILD/modules/lib/modules` @@ -28,5 +25,3 @@ mkdir -p $INSTALL/etc cp $PKG_DIR/config/modules $INSTALL/etc mkdir -p $INSTALL/etc/modprobe.d - -$SCRIPTS/install linux-firmware diff --git a/packages/linux/meta b/packages/linux/meta new file mode 100644 index 0000000000..652994f3ac --- /dev/null +++ b/packages/linux/meta @@ -0,0 +1,14 @@ +PKG_NAME="linux" +PKG_VERSION="2.6.35-rc6" +PKG_REV="1" +PKG_ARCH="any" +PKG_LICENSE="GPL" +PKG_SITE="http://www.kernel.org" +PKG_URL="http://www.kernel.org/pub/linux/kernel/v2.6/testing/$PKG_NAME-$PKG_VERSION.tar.bz2" +PKG_DEPENDS="busybox linux-firmware" +PKG_BUILD_DEPENDS="toolchain busybox-hosttools" +PKG_PRIORITY="optional" +PKG_SECTION="linux" +PKG_SHORTDESC="linux26: The Linux kernel 2.6 precompiled kernel binary image and modules" +PKG_LONGDESC="This package contains a precompiled kernel image and the modules." +PKG_IS_ADDON="no" diff --git a/packages/linux/patches/015-linux-2.6.33-02-add_lirc_driver_nct667x-0.5.diff b/packages/linux/patches/015-linux-2.6.33-02-add_lirc_driver_nct667x-0.5.diff deleted file mode 100644 index 44fb32e0ce..0000000000 --- a/packages/linux/patches/015-linux-2.6.33-02-add_lirc_driver_nct667x-0.5.diff +++ /dev/null @@ -1,3700 +0,0 @@ -diff -Naur linux-2.6.33.2/drivers/input/lirc/Kconfig linux-2.6.33.2.patch/drivers/input/lirc/Kconfig ---- linux-2.6.33.2/drivers/input/lirc/Kconfig 2010-04-03 18:40:52.365577611 +0200 -+++ linux-2.6.33.2.patch/drivers/input/lirc/Kconfig 2010-04-03 18:42:04.203701785 +0200 -@@ -64,6 +64,12 @@ - help - Driver for Windows Media Center Ed. USB IR Transceivers - -+config LIRC_NCT667X -+ tristate "Nuvolo (Winbond) 667x IR Transeiver" -+ depends on INPUT_LIRC && PNP -+ help -+ Driver for Nuvolo (Winbond) 667x IR Transeiver IR Transceivers -+ - config LIRC_PARALLEL - tristate "Homebrew Parallel Port Receiver" - depends on INPUT_LIRC && !SMP -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_wb677_common_extern.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677_common_extern.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_wb677_common_extern.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677_common_extern.h 2010-04-03 18:46:59.068576829 +0200 -@@ -0,0 +1,118 @@ -+#ifndef __LIRC_WB677_COMMON_EXTERN_HEADER__ -+#define __LIRC_WB677_COMMON_EXTERN_HEADER__ -+ -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+extern char *DRVNAME; -+ -+/* chip id string, at most 7 characters */ -+extern char *chip_id; -+ -+ -+ -+ -+/* allow show debug messages -+ * without additional debug setting, only show current IRQ number, I/O port and final decode output */ -+/*//#define IR_667_DEBUG*/ -+ -+/* show debug message while decode mce keyboard and mouse signals */ -+#ifdef IR_667_DEBUG -+/*//#define ALLOW_DEBUG_DECODE*/ -+#endif -+ -+/* show incoming interrupt signals -+ * may block machine, mask it if sure interrupt signal is good */ -+#ifdef IR_667_DEBUG -+/*//#define ALLOW_DEBUG_INTERRUPT*/ -+#endif -+ -+/* show received infrared pulse and cancel decode functions, mask it in stable version -+ * it will stop decode MCE controller, keyboard and mouse -+ * mask it if want to decode incoming signals -+ */ -+#ifdef IR_667_DEBUG -+/*//#define ALLOW_DEBUG_PRINT_PULSE*/ -+#endif -+ -+/* show debug message while set WAKE UP key -+ * it will print cir_wake buf message while setting wake up key -+ * mask it in stable version -+ */ -+#ifdef IR_667_DEBUG -+#define ALLOW_DEBUG_WAKE -+#endif -+ -+/* show STUDY debug messages */ -+#ifdef IR_667_DEBUG -+#define ALLOW_DEBUG_STUDY -+#endif -+ -+/* show ioctl debug messages */ -+#ifdef IR_667_DEBUG -+#define ALLOW_DEBUG_IOCTL -+#endif -+ -+/* step debug */ -+#ifdef IR_667_DEBUG -+#define ALLOW_DEBUG_STEP -+#endif -+ -+#ifdef ALLOW_DEBUG_STEP -+#define STEP_DBG \ -+ do { \ -+ printk("w83667hg_ir step debug: %s, %d\n", __FILE__, __LINE__); \ -+ } while (0); -+#else -+#define STEP_DBG -+#endif -+ -+#ifdef ALLOW_DEBUG_PRINT_PULSE -+/* print current received ir pulse -+ * it will output all data, clean CIR_IRSTS so make all following irq_handler ignore -+ */ -+void debug_print_pulse(void); -+ -+void debug_print_wake_pulse(void); -+#endif -+ -+ -+ -+ -+/* register lirc device & buffer */ -+ -+/* mininum value 76, recommend 256 */ -+#define IRCTL_BUF_LIMIT 2048 -+ -+ -+struct irctl { -+ struct input_dev *input_dev; /* allocate by input_init */ -+ struct lirc_buffer *lirc_buffer; -+ struct lirc_driver *lirc_plugin; -+ spinlock_t lock; -+ /* for controller */ -+ int lircdata; -+ u8 ctrl_fix_head; /* fix controller not sync problem*/ -+ /* for keyboard */ -+ u8 pressed_keycode; /* initialize as 0*/ -+ u8 pressed_shiftmask; /* initialize as 0*/ -+ /* for decode */ -+ u8 buf[IRCTL_BUF_LIMIT]; -+ unsigned int buf_count; /* init as 0, reset 0 after decode*/ -+ unsigned int cur_buf_num; /* init as 0, set as 0 while clean*/ -+ /* for study */ -+#define ST_STUDY_NONE 0x0 -+#define ST_STUDY_START 0x01 -+#define ST_STUDY_CARRIER 0x02 -+#define ST_STUDY_ALL_RECV 0x04 -+ u8 study_state; -+ /* carrier period = 1 / frequency */ -+ unsigned int carrier; -+ wait_queue_head_t queue; -+}; -+ -+extern unsigned int usb_kbd_keycode[256]; -+ -+#endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_wb677.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_wb677.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677.h 2010-04-03 18:47:28.580576601 +0200 -@@ -0,0 +1,683 @@ -+/* -+* LIRC driver for Nuvoton w83667hg/w83677hg-i -+* -+* Copyright (C) 2009 Nuvoton PS Team -+* -+* 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/*//#include */ -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+ -+ -+#include "lirc_wb677_common_extern.h" -+ -+ -+ -+/* 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 -+ -+/* 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 -+ -+/* 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 -+ -+/* select RX trigger level as 1 */ -+#define CIR_FIFOCON_RX_TRIGGER_LEV CIR_FIFOCON_RX_TRIGGER_LEV_1 -+ -+/* 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 -+ -+/* select a same sample period like cir register */ -+#define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50 -+ -+/* CIR WAKE UP IRSTS settings */ -+#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 settings */ -+#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 -+ -+/* 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 -+ -+ -+ -+ -+/* Config Regs */ -+ -+/* Chip Control Regs */ -+#define cr_cfg_idx 0x2e -+#define cr_cfg_dat 0x2f -+ -+#define cr_cfg_idx2 0x4e -+#define cr_cfg_dat2 0x4f -+ -+static u8 CFG_idx = cr_cfg_idx; -+static u8 CFG_dat = cr_cfg_dat; -+ -+#define CHIP_ID_HIGH_ADDR 0x20 -+#define CHIP_ID_LOW_ADDR 0x21 -+ -+#define CHIP_ID_HIGH 0xB4 -+#define CHIP_ID_LOW 0x73 -+ -+#define ACTIVE_LOG_DEV 0x01 -+#define DEACTIVE_LOG_DEV 0x0 -+ -+#define CIR_LOG_DEV 0x06 -+ -+#define ACPI_LOG_DEV 0x0A -+ -+#define ENABLE_CIR_WAKE 0x08 -+#define DISABLE_CIR_WAKE 0xF7 -+ -+#define ENABLE_CIR_INTR_OF_MOUSE_IRQ 0x80 -+#define DISABLE_CIR_INTR_OF_MOUSE_IRQ 0x7F -+ -+#define ENABLE_PME_INTR_OF_CIR_PASS 0x08 -+#define DISABLE_PME_INTR_OF_CIR_PASS 0xF7 -+ -+#define CIR_WAKE_LOG_DEV 0x0E -+ -+ -+/* read/update registers functions */ -+ -+/* enter extended function mode */ -+static inline void cr_enter_ext(void); -+ -+/* exit extended function mode */ -+static inline void cr_exit_ext(void); -+ -+/* select logical device */ -+static inline void cr_select_log_dev(int cr); -+ -+static inline void cr_update(int dat, int cr); -+ -+static inline u8 cr_read(int cr); -+ -+/* update cr register without change other bits */ -+static inline void cr_safe_update(u8 dat, int cr); -+ -+/* clear cr register without change other bits */ -+static inline void cr_safe_clear(u8 dat, int cr); -+ -+ -+ -+/* read/write cir registers */ -+ -+static inline void cir_update(u8 dat, int cir); -+ -+static u8 cir_read(int cir); -+ -+/* read/write cir wake registers */ -+ -+static inline void cir_wake_update(u8 dat, int cir); -+ -+static u8 cir_wake_read(int cir); -+ -+ -+/* dump current cir registers */ -+static void cir_dump_reg(void); -+ -+/* dump current cir wake up registers */ -+static void cir_wake_dump_reg(void); -+ -+ -+ -+ -+ -+/* driver module load/unload functions */ -+ -+/* Config Registers init */ -+/* -+ * initialize cr, cir, apci, cir wake logical devices -+ * open these devices and irq -+ */ -+static int w83667hg_cr_init(void); -+ -+/* Config Registers uninit */ -+/* -+ * close cir and cir wake logical devices -+ */ -+static void w83667hg_cr_uninit(void); -+ -+ -+/* register input device (keyboard and mouse) -+ * -+ */ -+ -+/* Define it for decoding keyboard and mouse in driver */ -+#define DECODE_KEYBOARD_MOUSE -+ -+/* this is the keycode table of US-EN layout keyboard -+ * modify it to support other layout keyboard -+ */ -+unsigned int usb_kbd_keycode[256] = { -+ 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, -+ 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, -+ 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, -+ 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, -+ 65, 66, 67, 68, 87, 88, 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, -+ 105, 108, 103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, -+ 72, 73, 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190, -+ 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, 136, 113, -+ 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94, 95, 0, 0, 0, -+ 122, 123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, 114, 113, -+ 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140 -+}; -+ -+/* input device name, locate in /sys/input/inputNUM/name */ -+static char *INPUTNAME = "MCE Remote Keyboard"; -+ -+static struct input_id w83667hg_input_id = { -+ .bustype = BUS_HOST, /* comunicate 667 by HOST, or I2C ? */ -+ .vendor = 0x1050, /* Winbond PCI VENDOR ID */ -+ .product = 1, /* for basic devices, like keyboard & mouse */ -+ .version = 0, /* ignore it */ -+}; -+ -+ -+static int w83667hg_input_open(struct input_dev *cur_input_dev); -+ -+static void w83667hg_input_close(struct input_dev *cur_input_dev); -+ -+static struct input_dev *w83667hg_input_init(void); -+ -+static void w83667hg_input_uninit(struct input_dev *cur_input_dev); -+ -+/* internal call for register lirc */ -+static int lirc_set_use_inc(void *data); -+ -+static void lirc_set_use_dec(void *data); -+ -+ -+ -+static struct ir_recv_t { -+ spinlock_t lock; -+ u8 buf[IRCTL_BUF_LIMIT]; -+ unsigned int buf_count; -+ wait_queue_head_t queue; -+ /* for wake */ -+#define ST_WAKE_NONE 0x0 -+#define ST_WAKE_START 0x01 -+#define ST_WAKE_FINISH 0x02 -+ u8 wake_state; -+ /* for recv */ -+#define ST_RECV_WAIT_7F 0x01 -+#define ST_RECV_WAIT_HEAD 0x02 -+#define ST_RECV_WAIT_SILENT_END 0x04 -+ u8 recv_state; -+} w83667hg_ir_recv; -+ -+static struct ir_send_t { -+ spinlock_t lock; -+ u8 buf[IRCTL_BUF_LIMIT]; -+ unsigned int buf_count; -+ unsigned int cur_buf_num; -+ wait_queue_head_t queue; -+ /* for send */ -+#define ST_SEND_NONE 0x0 -+#define ST_SEND_REQUEST 0x02 -+#define ST_SEND_REPLY 0x04 -+ u8 send_state; -+} w83667hg_ir_send; -+ -+/* We initialise it at lirc_wb667_init() becuase of lirc group does not allow to initialise static varialbe to null.*/ -+static struct input_dev *w83667hg_input_dev; -+ -+/* We initialise it at lirc_wb667_init() becuase of lirc group does not allow to initialise static varialbe to null.*/ -+static struct lirc_driver *w83667hg_lirc_plugin; -+ -+#define LIRCBUF_SIZE 256 -+ -+/* We initialise it at lirc_wb667_init() becuase of lirc group does not allow to initialise static varialbe to null.*/ -+static struct lirc_buffer *w83667hg_lirc_buffer; -+ -+static void w83667hg_ir_recv_init(struct ir_recv_t *ir_recv); -+ -+static void w83667hg_ir_send_init(struct ir_send_t *ir_send); -+ -+static int w83667hg_irctl_init(struct irctl *ir); -+ -+static void w83667hg_irctl_uninit(struct irctl *ir); -+ -+ -+ -+ -+/* 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 -+ -+ -+/* fops */ -+/* set carrier frequency by ioctl IR_IOSETCARRIER -+ * -+ * that value can be get by ioctl value IR_IOGETCARRIER -+ * on 667, set carrier on 2 registers: CP & CC -+ * always set CP as 0x81 -+ * set CC by SPEC, CC = 3MHz/carrier - 1 -+ */ -+static int w83667hg_set_carrier(unsigned int *carrier); -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg); -+ -+/* lirc_write -+ * -+ * 1) clean TX fifo first (handled by AP) -+ * 2) copy data from user space -+ * 3) open TX interrupt: TTR & TFU -+ * 4) send 9 pulses to open TTR -+ * in interrupt_handler: -+ * 5) send all data out -+ * go back to write(): -+ * 6) close TX interrupt -+ * -+ * The key problem of this function is user space data may larger than -+ * driver's data buf length. So lirc_wirte() only copy IRCTL_BUF_LIMIT data to -+ * buf. And keep current copied data buf num in cur_buf_num. But driver's buf -+ * number may larger than TXFCONT (0xFF). So in interrupt_handler, it has to -+ * set TXFCONT as 0xff, until buf_count less than 0xff. -+ * The confustion is cur_buf_num in decode, study and send is designed on -+ * different meaning. -+ * -+ */ -+static ssize_t lirc_write(struct file *file, const char *buf, size_t n, loff_t * ppos); -+ -+ -+ -+/* 1) clean lircdata and buf_count in irctl struct -+ * 2) clean RX and TX fifo -+ */ -+static void w83667hg_clean_data(struct ir_recv_t *ir_recv, struct irctl *ir); -+ -+ -+ -+ -+/* send 1 recorded controller signal to lirc */ -+static void w83667hg_send_packet_to_lirc_1(struct irctl *ir, int *val); -+ -+/* this value copy from lirc_mod_mce */ -+#if CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_100 -+ #define MCE_TIME_UNIT 100 -+#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_50 -+ #define MCE_TIME_UNIT 50 -+#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_25 -+ #define MCE_TIME_UNIT 25 -+#else -+ #define MCE_TIME_UNIT 1 -+#endif -+ -+/* recode mce controller signal and send to lirc -+ * -+ * recode steps: -+ * 1) high pulse, +128 -+ * 2) low pulse, do nothing -+ * 3) keycode = pulse * 50 -+ * 4) sync head: PULSE_MASK (0xFF FFFF) -+ * 5) 1, |PULSE_BIT (0x100 0000) -+ * 0, +keycode -+ * -+ * function steps: -+ * 0) clean lircdata[] -+ * 1) jump head, put PULSE_BIT in lircdata[0] -+ * 2) normal decode, "10"=>1 |PULSE_BIT -+ * save in lircdata[] -+ * 3) send lircdata[] to lirc -+ */ -+static void w83667hg_submit_controller(struct irctl *ir); -+ -+ -+/* copy data from hardware fifo to driver buf -+ * -+ * 1. initial state is WAIT_7F -+ * 2. if data is not 0x7f, copy data from hardware fifo to struct ir_recv buf -+ * 3. if data is 0x7f, set recv_state as WAIT_HEAD, copy data from ir_recv to irctl -+ * 4. depend on received buf length to select submit_ function -+ * 5. set irctl buf len as 0 -+ * 5. receive data until data is not 0x7f, drop received 0x7f data, set recv_state as WAIT_7F again -+ * -+ * in normal, there are 3 parts in one infrared signal: -+ * 1. not silent pulse (ST_WAIT_7F) -+ * 2. 0x7f silent pulse (ST_WAIT_HEAD) -+ * 3. silent pulse shorter than 0x7f (ST_WAIT_HEAD) -+ * -+ * so this function copy signal part 1 and a 0x7f (for decode) to submit_() functions. -+ * when receive 0x7f, this function copy data from ir_recv to irctl, and wait for next high pulse. -+ */ -+static void w83667hg_recv(struct ir_recv_t *ir_recv, struct irctl *ir); -+ -+ -+/* as VISTA MCE definition, valid carrier value */ -+#define MAX_CARRIER 60000 -+#define MIN_CARRIER 30000 -+ -+/* receive function for STUDY -+ * -+ * 0. not receive 0x80, copy received data to ir_recv buf -+ * when get 0x80, it means user released controller, and only need process received data -+ * 1. get carrier -+ * 2. get pulse -+ */ -+static void w83667hg_study_recv(struct ir_recv_t *ir_recv, struct irctl *ir); -+ -+static irqreturn_t w83667hg_wake_interrupt_handler(int irq, void *dev); -+ -+static irqreturn_t w83667hg_interrupt_handler(int irq, void *dev); -+ -+ -+/* pnp device */ -+#ifdef CONFIG_PNP -+ -+ -+/* CIR and CIR WAKE */ -+static const struct pnp_device_id pnp_dev_table[] = { -+ { "WEC0530", 0 }, /* CIR */ -+ { "NTN0530", 0 }, /* CIR for new chip's pnp id*/ -+ { "", 0 }, -+}; -+ -+ -+MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -+ -+static int __devinit lirc_wb667_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id); -+ -+static void __devexit lirc_wb667_pnp_remove(struct pnp_dev *dev); -+ -+/* before suspend -+ * 1. set all states as NONE -+ * 2. close CIR and WAKE interrupt -+ * 3. close CIR and WAKE cr -+ * 4. close input -+ */ -+static int lirc_wb667_pnp_suspend(struct pnp_dev *dev, pm_message_t state); -+ -+/* resume all register and input device -+ */ -+static int lirc_wb667_pnp_resume(struct pnp_dev *dev); -+ -+/* We initialise it as lirc_wb667_init because lirc group does not allow us to initialise static vaiable as 0 here. */ -+static unsigned int nopnp; -+ -+#else -+ -+/* We initialise it as lirc_lirc_wb667_init because lirc group does not allow us to initialise static vaiable as 0 here. */ -+static unsigned int nopnp; -+ -+#endif -+ -+ -+/* create io region for cir and cir wake -+ * create irq handler -+ * create dev and data struct -+ */ -+static int w83667hg_cir_probe(void); -+ -+/* uninit cir, cir wake, dev and data struct, release irq and io port */ -+static void w83667hg_cir_remove(void); -+ -+ -+static int lirc_wb667_init(void); -+ -+void lirc_wb667_uninit(void); -+ -+ -+/* -+ * 1. init cr -+ * 2. init input -+ * 3. init lirc buffer, register, irctl -+ * 4. init 667 cir dev, req_region, req_irq -+ */ -+/*int init_module(void); -+void cleanup_module(void);*/ -+int init_module_wb667(void); -+void cleanup_module_wb667(void); -+ -+MODULE_DESCRIPTION("LIRC driver for Nuvoton W83667HG-A & W83677HG CIR"); -+MODULE_AUTHOR("Nuvoton PS Team"); -+MODULE_LICENSE("GPL"); -+ -+/* device file name, locate in /dev/ directory */ -+/*//static char *DRVNAME = "w83667hg_ir";*/ -+/* FIXME, stable name*/ -+char *DRVNAME = "lirc_wb677"; -+module_param(DRVNAME, charp, S_IRUGO); -+MODULE_PARM_DESC(DRVNAME, "Device file name in /dev/ and /sys/class/."); -+ -+/* platform driver name to register */ -+#define PLATNAME "lirc_wb677_cir" -+#define PLATNAME_W "lirc_wb667_wake" -+ -+/* device file major number */ -+#define CIR_MAJOR 229 -+ -+/* cir device base address */ -+static u16 CIR_BASE = 0x240; -+module_param(CIR_BASE, ushort, S_IRUGO); -+MODULE_PARM_DESC(CIR_BASE, "Base IO port address of 667/677 CIR device."); -+ -+/* cir base i/o address */ -+static unsigned int cir_address; -+ -+/* cir irq */ -+static ushort CIR_IRQ_NUM = 5; -+module_param(CIR_IRQ_NUM, ushort, S_IRUGO); -+MODULE_PARM_DESC(CIR_IRQ_NUM, "IRQ number for 667/677 CIR device."); -+ -+/* handle cir wake up request in driver or not */ -+#define ENABLE_CIR_WAKE_IRQ -+ -+/* cir wake up device base address */ -+static u16 CIR_WAKE_BASE = 0x250; -+module_param(CIR_WAKE_BASE, ushort, S_IRUGO); -+MODULE_PARM_DESC(CIR_WAKE_BASE, "Base IO port address of 667/677 CIR WAKE device."); -+ -+/* cir wake up base i/o address */ -+static unsigned int cir_wake_address; -+ -+/* cir wake up irq */ -+static ushort CIR_WAKE_IRQ_NUM = 5; -+module_param(CIR_WAKE_IRQ_NUM, ushort, S_IRUGO); -+MODULE_PARM_DESC(CIR_WAKE_IRQ_NUM, "IRQ number for 667/677 CIR WAKE device."); -+ -+/* nopnp option */ -+#ifdef CONFIG_PNP -+module_param(nopnp, uint, S_IRUGO); -+MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)"); -+#endif -+ -+/*//EXPORT_NO_SYMBOLS;*/ -+ -+ -+ -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_wb677_main.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677_main.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_wb677_main.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677_main.c 2010-04-04 00:13:44.035576247 +0200 -@@ -0,0 +1,1723 @@ -+#define _GNU_SOURCE -+#include -+#include -+ -+#define MOD_INC_USE_COUNT -+#define MOD_DEC_USE_COUNT -+ -+#include "lirc_wb677.h" -+#include "lirc_wb677_mouse_kbd.h" -+#include "wb83677hg_ir.h" -+ -+struct irctl w83667hg_irctl; -+ -+/* chip id string, at most 7 characters */ -+char *chip_id = "w677hga"; -+ -+ -+ -+ -+/* enter extended function mode */ -+static inline void cr_enter_ext(void) -+{ -+ outb(0x87, CFG_idx); -+ outb(0x87, CFG_idx); -+ -+ if (0xff == cr_read(0x20)) { -+ CFG_idx = cr_cfg_idx2; -+ CFG_dat = cr_cfg_dat2; -+ outb(0x87, CFG_idx); -+ outb(0x87, CFG_idx); -+ } -+} -+ -+ -+/* exit extended function mode */ -+static inline void cr_exit_ext(void) -+{ -+ outb(0xaa, CFG_idx); -+} -+ -+/* select logical device */ -+static inline void cr_select_log_dev(int cr) -+{ -+ outb(0x07, CFG_idx); -+ outb(cr, CFG_dat); -+} -+ -+static inline void cr_update(int dat, int cr) -+{ -+ outb(cr, CFG_idx); -+ outb(dat, CFG_dat); -+} -+ -+static inline u8 cr_read(int cr) -+{ -+ outb(cr, CFG_idx); -+ return inb(CFG_dat); -+} -+ -+static inline void cr_safe_update(u8 dat, int cr) -+{ -+ cr_update(cr_read(cr) | dat, cr); -+} -+ -+static inline void cr_safe_clear(u8 dat, int cr) -+{ -+ cr_update(cr_read(cr) & dat, cr); -+} -+ -+ -+/* read/write cir registers */ -+ -+static inline void cir_update(u8 dat, int cir) -+{ -+ outb(dat, cir_address + (cir & 0xff)); -+} -+ -+static u8 cir_read(int cir) -+{ -+ u8 val; -+ -+ val = inb(cir_address + (cir & 0xff)); -+ -+ return val; -+} -+ -+static inline void cir_wake_update(u8 dat, int cir) -+{ -+ -+ outb(dat, cir_wake_address + (cir & 0xff)); -+ -+} -+ -+static u8 cir_wake_read(int cir) -+{ -+ u8 val; -+ -+ val = inb(cir_wake_address + (cir & 0xff)); -+ -+ return val; -+} -+ -+static void cir_dump_reg(void) -+{ -+ cr_enter_ext(); -+ printk("Dump CIR CR logical device:\n"); -+ cr_select_log_dev(CIR_LOG_DEV); -+ printk("CR CIR ACTIVE : 0x%x\n", cr_read(0x30)); -+ printk("CR CIR BASE ADDR: 0x%x\n", (cr_read(0x61) << 8)|cr_read(0x60)); -+ printk("CR CIR IRQ NUM: 0x%x\n", cr_read(0x70)); -+ cr_exit_ext(); -+ -+ printk("Dump CIR Registers\n"); -+ printk("CIR IRCON: 0x%x\n", cir_read(CIR_IRCON)); -+ printk("CIR IRSTS: 0x%x\n", cir_read(CIR_IRSTS)); -+ printk("CIR IREN: 0x%x\n", cir_read(CIR_IREN)); -+ printk("CIR RXFCONT: 0x%x\n", cir_read(CIR_RXFCONT)); -+ printk("CIR CP: 0x%x\n", cir_read(CIR_CP)); -+ printk("CIR CC: 0x%x\n", cir_read(CIR_CC)); -+ printk("CIR SLCH: 0x%x\n", cir_read(CIR_SLCH)); -+ printk("CIR SLCL: 0x%x\n", cir_read(CIR_SLCL)); -+ printk("CIR FIFOCON: 0x%x\n", cir_read(CIR_FIFOCON)); -+ printk("CIR IRFIFOSTS: 0x%x\n", cir_read(CIR_IRFIFOSTS)); -+ printk("CIR SRXFIFO: 0x%x\n", cir_read(CIR_SRXFIFO)); -+ printk("CIR TXFCONT: 0x%x\n", cir_read(CIR_TXFCONT)); -+ printk("CIR STXFIFO: 0x%x\n", cir_read(CIR_STXFIFO)); -+ printk("CIR FCCH: 0x%x\n", cir_read(CIR_FCCH)); -+ printk("CIR FCCL: 0x%x\n", cir_read(CIR_FCCL)); -+ printk("CIR IRFSM: 0x%x\n", cir_read(CIR_IRFSM)); -+ -+} -+ -+static void cir_wake_dump_reg(void) -+{ -+ u8 i = 0; -+ -+ cr_enter_ext(); -+ printk("Dump CIR WKAE CR logical device:\n"); -+ cr_select_log_dev(CIR_WAKE_LOG_DEV); -+ printk("CR CIR WAKE ACTIVE : 0x%x \n", cr_read(0x30)); -+ printk("CR CIR WAKE BASE ADDR: 0x%x\n", (cr_read(0x61) << 8)|cr_read(0x60)); -+ printk("CR CIR WAKE IRQ NUM: 0x%x\n", cr_read(0x70)); -+ cr_exit_ext(); -+ -+ printk("Dump CIR WAKE Registers\n"); -+ printk("CIR WAKE IRCON: 0x%x\n", cir_wake_read(CIR_WAKE_IRCON)); -+ printk("CIR IRSTS: 0x%x\n", cir_wake_read(CIR_WAKE_IRSTS)); -+ printk("CIR IREN: 0x%x\n", cir_wake_read(CIR_WAKE_IREN)); -+ printk("CIR WAKE FIFO CMP DEEP: 0x%x\n", cir_wake_read(CIR_WAKE_FIFO_CMP_DEEP)); -+ printk("CIR WAKE FIFO CMP TOL: 0x%x\n", cir_wake_read(CIR_WAKE_FIFO_CMP_TOL)); -+ printk("CIR WAKE FIFO COUNT: 0x%x\n", cir_wake_read(CIR_WAKE_FIFO_COUNT)); -+ printk("CIR WAKE SLCH: 0x%x\n", cir_wake_read(CIR_WAKE_SLCH)); -+ printk("CIR WAKE SLCL: 0x%x\n", cir_wake_read(CIR_WAKE_SLCL)); -+ printk("CIR WAKE FIFOCON: 0x%x\n", cir_wake_read(CIR_WAKE_FIFOCON)); -+ printk("CIR WAKE SRXFSTS: 0x%x\n", cir_wake_read(CIR_WAKE_SRXFSTS)); -+ printk("CIR WAKE SAMPLE RX FIFO: 0x%x\n", cir_wake_read(CIR_WAKE_SAMPLE_RX_FIFO)); -+ printk("CIR WAKE WR FIFO DATA: 0x%x\n", cir_wake_read(CIR_WAKE_WR_FIFO_DATA)); -+ printk("CIR WAKE RD FIFO ONLY: 0x%x\n", cir_wake_read(CIR_WAKE_RD_FIFO_ONLY)); -+ printk("CIR WAKE RD FIFO ONLY IDX: 0x%x\n", cir_wake_read(CIR_WAKE_RD_FIFO_ONLY_IDX)); -+ printk("CIR WAKE FIFO IGNORE: 0x%x\n", cir_wake_read(CIR_WAKE_FIFO_IGNORE)); -+ printk("CIR WAKE IRFSM: 0x%x\n", cir_wake_read(CIR_WAKE_IRFSM)); -+ -+ printk("Dump CIR WAKE keys\n"); -+ printk("%s FIFO count len = %d\n", DRVNAME, cir_wake_read(CIR_WAKE_FIFO_COUNT)); -+ i = 0; -+ for (; i < 67; i++) { -+ printk("%s FIFO = 0x%x\n", DRVNAME, cir_wake_read(CIR_WAKE_RD_FIFO_ONLY)); -+ } -+ -+} -+ -+ -+/* 1. */ -+/* 677HG Config Registers init */ -+static int w83667hg_cr_init(void) -+{ -+ int val = 0; -+ -+ cr_enter_ext(); -+ -+ /* Check 677 CHIP ID first */ -+ val = cr_read(CHIP_ID_HIGH_ADDR); -+ if (val != CHIP_ID_HIGH) { -+ printk("%s %s: chip id high: 0x%x expect:0x%x\n", DRVNAME, chip_id, val, CHIP_ID_HIGH); -+ /*// cr_exit_ext(); -+ // return -ENODEV;*/ -+ } -+ else{ -+ printk("%s %s: chip id high: 0x%x\n", DRVNAME, chip_id, val); -+ } -+ -+ /* now check chip id, LSB */ -+ val = cr_read(CHIP_ID_LOW_ADDR); -+ if (CHIP_ID_LOW == (val & CHIP_ID_LOW)) { -+ printk("%s %s: chip id low: 0x%x expect:0x%x\n", DRVNAME, chip_id, val, CHIP_ID_LOW); -+ /*// cr_exit_ext(); -+ // return -ENODEV;*/ -+ } else{ -+ printk("%s %s: chip id low: 0x%x\n", DRVNAME, chip_id, val); -+ } -+ -+ /* for multi-function pin selection */ -+ val = cr_read(0x27); -+ val = (val&0xbc) | 0x41; -+ cr_update(val, 0x27); /*For W83677, CIR TX,RX, CIRWB pin selection*/ -+ -+ -+ -+ /* FIXME*/ -+ /* set Logical Dev 1: LPT */ -+ /* not sure really need it or not, find it in 667 wake up windows driver */ -+ cr_select_log_dev(0x01); -+ cr_update(DEACTIVE_LOG_DEV, 0x30); -+ cr_update(0, 0x70); -+ -+ /* Then set Logical Dev 6: CIR */ -+ cr_select_log_dev(CIR_LOG_DEV); -+ cr_update(ACTIVE_LOG_DEV, 0x30); -+ -+ cir_address = CIR_BASE; -+ cr_update(((CIR_BASE & 0xff00) >> 8), 0x60); -+ cr_update((CIR_BASE & 0xff), 0x61); -+#ifdef IR_667_DEBUG -+ printk("%s base io port address: 0x%x\n", DRVNAME, cir_address); -+#endif -+ -+ cr_update(CIR_IRQ_NUM, 0x70); -+#ifdef IR_667_DEBUG -+ printk("%s irq number: %d\n", DRVNAME, CIR_IRQ_NUM); -+#endif -+ -+ -+ /* Then set Logical Dev A: ACPI */ -+ cr_select_log_dev(ACPI_LOG_DEV); -+ -+ cr_update(ACTIVE_LOG_DEV, 0x30); -+ -+ /* enable cir wake up via PSOUT# (pin 60) */ -+ cr_safe_update(ENABLE_CIR_WAKE, 0xe0); -+ -+ /* enable cir interrupt of mouse IRQ event */ -+ /*//cr_safe_update(ENABLE_CIR_INTR_OF_MOUSE_IRQ, 0xf6);*/ -+ -+ /* enable pme interrupt of cir password event */ -+ /*//cr_safe_update(ENABLE_PME_INTR_OF_CIR_PASS, 0xf7);*/ -+ -+ -+ /* Then set Logical Dev E: CIR WAKE */ -+ cr_select_log_dev(CIR_WAKE_LOG_DEV); -+ cr_update(ACTIVE_LOG_DEV, 0x30); -+ -+ cir_wake_address = CIR_WAKE_BASE; -+ cr_update(((CIR_WAKE_BASE & 0xff00) >> 8), 0x60); -+ cr_update((CIR_WAKE_BASE & 0xff), 0x61); -+#ifdef IR_667_DEBUG -+ printk("%s cir wake up base io port address: 0x%x\n", DRVNAME, cir_wake_address); -+#endif -+ -+#ifdef ENABLE_CIR_WAKE_IRQ -+ cr_update(CIR_WAKE_IRQ_NUM, 0x70); -+#ifdef IR_667_DEBUG -+ printk("%s cir wake up irq number: %d\n", DRVNAME, CIR_WAKE_IRQ_NUM); -+#endif -+#endif -+ -+ cr_exit_ext(); -+ -+ return 0; -+} -+ -+static void w83667hg_cr_uninit(void) -+{ -+ cr_enter_ext(); -+ -+ /* close CIR */ -+ /* Don't close CIR Wake. When wake-up at power-on, it needs the function. 20091224 -+ cr_select_log_dev(CIR_WAKE_LOG_DEV); -+ cr_update(DEACTIVE_LOG_DEV, 0x30); -+ */ -+ -+ -+ /* Close Logical Dev A: ACPI */ -+ /*//cr_select_log_dev(ACPI_LOG_DEV);*/ -+ -+ /* enable cir wake up via PSOUT# (pin 60) */ -+ /*//cr_safe_clear(DISABLE_CIR_WAKE, 0xe0);*/ -+ -+ /* enable cir interrupt of mouse IRQ event */ -+ /*//cr_safe_clear(DISABLE_CIR_INTR_OF_MOUSE_IRQ, 0xf6);*/ -+ -+ /* enable pme interrupt of cir password event */ -+ /*//cr_safe_clear(DISABLE_PME_INTR_OF_CIR_PASS, 0xf7);*/ -+ -+ -+ /* close CIR wake up XXX */ -+ /*//cr_select_log_dev(CIR_WAKE_LOG_DEV); -+ //cr_update(DEACTIVE_LOG_DEV, 0x30);*/ -+ -+ cr_exit_ext(); -+} -+ -+static int w83667hg_input_open(struct input_dev *cur_input_dev) -+{ -+ return 0; -+} -+ -+static void w83667hg_input_close(struct input_dev *cur_input_dev) -+{ -+} -+ -+/* 2. */ -+/* init linux input structure */ -+static struct input_dev *w83667hg_input_init(void) -+{ -+ int i; -+ struct input_dev *cur_input_dev = NULL; -+ -+ cur_input_dev = input_allocate_device(); -+ if (NULL == cur_input_dev) { -+ printk("alloc input device error\n"); -+ return NULL; -+ } -+ -+ cur_input_dev->name = INPUTNAME; -+ cur_input_dev->phys = DRVNAME; -+ memcpy(&cur_input_dev->id, &w83667hg_input_id, sizeof(struct input_id)); -+ -+ cur_input_dev->open = w83667hg_input_open; -+ cur_input_dev->close = w83667hg_input_close; -+ -+ /*//cur_input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); -+ //cur_input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);*/ -+ cur_input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); -+ cur_input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); -+ for (i = 0; i < 256; i++) { -+ set_bit(usb_kbd_keycode[i], cur_input_dev->keybit); -+ } -+ clear_bit(0, cur_input_dev->keybit); -+/*// cur_input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);*/ -+ cur_input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); -+ -+ -+ if (input_register_device(cur_input_dev)) { -+ printk("register input device error\n"); -+ return NULL; -+ } -+ -+ return cur_input_dev; -+} -+ -+static void w83667hg_input_uninit(struct input_dev *cur_input_dev) -+{ -+ input_get_device(cur_input_dev); -+ input_unregister_device(cur_input_dev); -+ input_free_device(cur_input_dev); -+ cur_input_dev = NULL; -+} -+ -+ -+/* internal call for register lirc */ -+static int lirc_set_use_inc(void *data) -+{ -+ struct irctl *ir = data; -+ -+ if (!ir) { -+ printk("%s: set_use_inc called with no context\n", DRVNAME); -+ return -EIO; -+ } -+#ifdef IR_667_DEBUG -+ printk("%s : set use inc\n", DRVNAME); -+#endif -+ spin_lock(&ir->lock); -+ ir->ctrl_fix_head = 1; -+ spin_unlock(&ir->lock); -+ -+ -+ MOD_INC_USE_COUNT; -+ -+ return 0; -+} -+ -+static void lirc_set_use_dec(void *data) -+{ -+ struct irctl *ir = data; -+ -+ if (!ir) { -+ printk("%s: set_use_dec called with no context\n", DRVNAME); -+ return; -+ } -+#ifdef IR_667_DEBUG -+ printk("%s : set use dec\n", DRVNAME); -+#endif -+ -+ MOD_DEC_USE_COUNT; -+} -+ -+ -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ int ret = 0; -+ void __user *uptr = (void __user *)arg; -+ -+ int mode = 0; -+ struct irctl *ir = &w83667hg_irctl; -+ struct ir_recv_t *ir_recv = &w83667hg_ir_recv; -+ -+#ifdef ALLOW_DEBUG_IOCTL -+ printk("%s: IO Ctrl Code:%d\n", DRVNAME, cmd); -+#endif -+ -+ switch (cmd) { -+ /* lirc ioctl commands */ -+ case LIRC_GET_FEATURES: -+ ret = put_user(w83667hg_lirc_plugin->features, (unsigned long *)arg); -+ break; -+ case LIRC_GET_SEND_MODE: -+ if (!(w83667hg_lirc_plugin->features & LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ ret = put_user(LIRC_REC2MODE -+ (w83667hg_lirc_plugin->features & LIRC_CAN_REC_MASK), -+ (unsigned long *)arg); -+ if (ret) -+ return ret; -+ break; -+ case LIRC_SET_SEND_MODE: -+ ret = get_user(mode, (unsigned long *)arg); -+ if (ret) -+ return ret; -+ if (mode != (LIRC_MODE_PULSE&LIRC_CAN_SEND_MASK)) -+ return -EINVAL; -+ break; -+ case LIRC_GET_LENGTH: -+ ret = put_user((unsigned long)w83667hg_lirc_plugin->code_length, -+ (unsigned long *)arg); -+ break; -+ -+ /* ioctl commands for lirc_wb667 */ -+ case IR_DUMPCIRREG: -+ cir_dump_reg(); -+ break; -+ case IR_DUMPWAKEREG: -+ cir_wake_dump_reg(); -+ break; -+ case IR_IOLEARNWAKE: -+ spin_lock(&ir_recv->lock); -+ if (ir_recv->wake_state) { -+ spin_unlock(&ir_recv->lock); -+ ret = -EFAULT; -+ break; -+ } -+ ir_recv->wake_state = ST_WAKE_START; -+ spin_unlock(&ir_recv->lock); -+ -+ /* close cir first */ -+ cr_enter_ext(); -+ cr_select_log_dev(CIR_LOG_DEV); -+ cr_update(DEACTIVE_LOG_DEV, 0x30); -+ cr_exit_ext(); -+ /*//cir_update(0, CIR_IREN);*/ -+ cir_update(0xff, CIR_IRSTS); -+ -+ /* set cir wake */ -+ cir_wake_update(CIR_WAKE_IRCON_RXEN | CIR_WAKE_IRCON_RXINV | CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, CIR_WAKE_IRCON); -+ cir_wake_update(0xff, CIR_WAKE_IRSTS); -+ cir_wake_update(0xff, CIR_WAKE_FIFOCON); -+ cir_wake_update(0, CIR_WAKE_FIFOCON); -+#ifdef ALLOW_DEBUG_WAKE -+ printk("%s FIFO count len = %d\n", DRVNAME, cir_wake_read(CIR_WAKE_FIFO_COUNT)); -+#endif -+ cir_wake_update(CIR_WAKE_IREN_PE, CIR_WAKE_IREN); -+ -+ wait_event(ir_recv->queue, ir_recv->wake_state == ST_WAKE_FINISH); -+ while ((cir_wake_read(CIR_WAKE_RD_FIFO_ONLY_IDX)) != 0) { -+#ifdef ALLOW_DEBUG_WAKE -+ printk("%s setting wake up key: 0x%x\n", DRVNAME, cir_wake_read(CIR_WAKE_RD_FIFO_ONLY)); -+#else -+ cir_wake_read(CIR_WAKE_RD_FIFO_ONLY); -+#endif -+ } -+ -+ /* learn wake up complete */ -+ spin_lock(&ir_recv->lock); -+ ir_recv->wake_state = ST_WAKE_NONE; -+ spin_unlock(&ir_recv->lock); -+ -+#ifdef ALLOW_DEBUG_WAKE -+ ret = 0; -+ for (; ret < 67; ret++) { -+ printk("%s FIFO count = 0x%x\n", DRVNAME, cir_wake_read(CIR_WAKE_RD_FIFO_ONLY)); -+ } -+ printk("%s FIFO count len = %d\n", DRVNAME, cir_wake_read(CIR_WAKE_FIFO_COUNT)); -+#endif -+ -+ /* cir wake interrupt stop, resume cir */ -+ cir_wake_update(CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, CIR_WAKE_IRCON); -+ cir_wake_update(0xff, CIR_WAKE_IRSTS); -+ cir_wake_update(0, CIR_WAKE_IREN); -+ cr_enter_ext(); -+ cr_select_log_dev(CIR_LOG_DEV); -+ cr_update(ACTIVE_LOG_DEV, 0x30); -+ cr_exit_ext(); -+ ret = 0; -+ -+ break; -+ case IR_IOUNSETWAKE: -+ cir_wake_update(0, CIR_WAKE_IRCON); -+ cir_wake_update(0, CIR_WAKE_IREN); -+ cir_wake_update(0xFF, CIR_WAKE_IRSTS); -+ cir_wake_update(0, CIR_WAKE_IRSTS); -+ cr_enter_ext(); -+ cr_select_log_dev(CIR_WAKE_LOG_DEV); -+ cr_update(DEACTIVE_LOG_DEV, 0x30); -+ cr_exit_ext(); -+ /*//cir_wake_update(CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, CIR_WAKE_IRCON);*/ -+ break; -+ case IR_IOSETWAKE: -+ cr_enter_ext(); -+ cr_select_log_dev(CIR_WAKE_LOG_DEV); -+ cr_update(ACTIVE_LOG_DEV, 0x30); -+ cr_exit_ext(); -+ cir_wake_update(CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, CIR_WAKE_IRCON); -+ cir_wake_update(0xFF, CIR_WAKE_IRSTS); -+ cir_wake_update(0, CIR_WAKE_IRSTS); -+ cir_wake_update(0, CIR_WAKE_IREN); -+ break; -+ case IR_IOCLEANDATA: -+ w83667hg_clean_data(&w83667hg_ir_recv, &w83667hg_irctl); -+ break; -+ case IR_IOSTARTSTUDY: -+ spin_lock(&ir->lock); -+ ir->study_state = ST_STUDY_START; -+ spin_unlock(&ir->lock); -+ /*//cir_update(cir_read(CIR_IRCON) | CIR_IRCON_WIREN, CIR_IRCON);*/ -+ cir_update(CIR_IRCON_WIREN | CIR_IRCON_RXEN | CIR_IRCON_SAMPLE_PERIOD_SEL, CIR_IRCON); -+ -+/* for WRX RTR -+ cir_update(CIR_FIFOCON_RX_TRIGGER_LEV_8, CIR_FIFOCON); -+ //cir_update(CIR_IREN_RTR, CIR_IREN); -+ cir_update(0, CIR_IREN); -+*/ -+ break; -+ case IR_IOSTOPSTUDY: -+ cir_update(CIR_IRCON_TXEN | CIR_IRCON_RXEN | CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, CIR_IRCON); -+ spin_lock(&ir->lock); -+ ir->study_state = ST_STUDY_NONE; -+ ir->buf_count = 0; -+ ir->cur_buf_num = 0; -+ wake_up(&ir->queue); -+ spin_unlock(&ir->lock); -+ break; -+ case IR_IOGETCARRIER: -+ spin_lock(&ir->lock); -+ if (!(ir->study_state > ST_STUDY_NONE)) { -+ ret = -EFAULT; -+ spin_unlock(&ir->lock); -+ break; -+ } -+ /*//w83667hg_record_study_carrier(ir);*/ -+#ifdef ALLOW_DEBUG_IOCTL -+ printk("%s: current get carrier: %d\n", DRVNAME, ir->carrier); -+#endif -+ if (copy_to_user(uptr, &ir->carrier, sizeof(unsigned int))) { -+ ret = -EFAULT; -+ } -+ spin_unlock(&ir->lock); -+ break; -+ case IR_IOSETCARRIER: -+ spin_lock(&ir->lock); -+ /* you can set carrier at any time */ -+ /* -+ if (~(ir->send_state)) { -+ ret = -EFAULT; -+ up(&ir->lock); -+ break; -+ } -+ */ -+ if (copy_from_user(&ir->carrier, uptr, sizeof(unsigned int))) { -+ ret = -EFAULT; -+ spin_unlock(&ir->lock); -+ break; -+ } -+#ifdef ALLOW_DEBUG_IOCTL -+ printk("%s: current set carrier: %x\n", DRVNAME, ir->carrier); -+#endif -+ w83667hg_set_carrier(&ir->carrier); -+ spin_unlock(&ir->lock); -+ break; -+ case IR_IOSTUDYLEN: -+ spin_lock(&ir->lock); -+ if (ir->study_state == ST_STUDY_NONE) { -+ spin_unlock(&ir->lock); -+#ifdef ALLOW_DEBUG_IOCTL -+ printk("%s: open STUDY first\n", DRVNAME); -+#endif -+ ret = -EFAULT; -+ break; -+ } -+ ir->study_state = ST_STUDY_START; -+ spin_unlock(&ir->lock); -+ wait_event(ir->queue, ir->study_state == ST_STUDY_ALL_RECV); -+ spin_lock(&ir->lock); -+ -+ /* in STUDY, copy data buf len to user space for read() */ -+ ir->cur_buf_num = 0; -+ if (ir->buf_count == 0) { -+ ret = -EFAULT; -+ } else if (copy_to_user(uptr, &ir->buf_count, sizeof(unsigned int))) { -+ ret = -EFAULT; -+ } -+ /* copy data to lirc plugin buffer, ready copy to user space */ -+ spin_unlock(&ir->lock); -+ break; -+ case IR_IOSTUDYBUF: -+ spin_lock(&ir->lock); -+ if (ir->study_state != ST_STUDY_ALL_RECV) { -+ spin_unlock(&ir->lock); -+ ret = -EFAULT; -+ break; -+ } -+ if (copy_to_user(uptr, &ir->buf[ir->cur_buf_num], sizeof(unsigned char))) { -+ spin_unlock(&ir->lock); -+ ret = -EFAULT; -+ break; -+ } -+ if (ir->cur_buf_num < ir->buf_count) { -+ ir->cur_buf_num++; -+ } -+ spin_unlock(&ir->lock); -+ break; -+ case IR_IORESTUDYBUF: -+ spin_lock(&ir->lock); -+ ir->cur_buf_num = 0; -+ spin_unlock(&ir->lock); -+ break; -+ case IR_CHECKCHIP: -+ if (copy_to_user(uptr, chip_id, sizeof(unsigned long long))) { -+ ret = -EFAULT; -+ } -+ break; -+ default: -+ return -ENOIOCTLCMD; -+ } -+ -+ return ret; -+} -+ -+static int w83667hg_set_carrier(unsigned int *carrier) -+{ -+ u16 val; -+ -+ cir_update(1, CIR_CP); -+ val = 3000000 / (*carrier) - 1; -+ cir_update(val & 0xff, CIR_CC); -+ -+#ifdef ALLOW_DEBUG_STUDY -+ printk("cp: 0x%x cc: 0x%x\n", cir_read(CIR_CP), cir_read(CIR_CC)); -+#endif -+ return 0; -+} -+ -+static ssize_t lirc_write(struct file *file, const char *buf, size_t n, loff_t * ppos) -+{ -+ size_t cur_count; -+ struct ir_send_t *ir_send = &w83667hg_ir_send; -+ unsigned int i; -+ ssize_t ret; -+ -+ spin_lock(&ir_send->lock); -+ -+ if (n >= IRCTL_BUF_LIMIT) { -+ ir_send->buf_count = cur_count = IRCTL_BUF_LIMIT; -+ ret = IRCTL_BUF_LIMIT; -+ } else { -+ ir_send->buf_count = cur_count = n; -+ ret = n; -+ } -+ -+ /* the first copy from user and open interrupt for TX */ -+ if (copy_from_user(ir_send->buf, buf, ir_send->buf_count)) { -+ ir_send->buf_count = 0; -+ spin_unlock(&ir_send->lock); -+ return -EFAULT; -+ } -+ -+ ir_send->cur_buf_num = 0; -+ -+ /* for safety, close RX while TX */ -+ cir_update(CIR_IREN_TFU | CIR_IREN_TTR, CIR_IREN); -+ -+ ir_send->send_state = ST_SEND_REPLY; -+ -+ cir_update(CIR_FIFOCON_TX_TRIGGER_LEV_8 | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); -+ /* turn on TTR interrupt, it's ugly */ -+ i = 0; -+ for (; i < 9; i++) { -+ cir_update(0x01, CIR_STXFIFO); -+ } -+ spin_unlock(&ir_send->lock); -+ -+ wait_event(ir_send->queue, ir_send->send_state == ST_SEND_REQUEST); -+ -+ spin_lock(&ir_send->lock); -+ ir_send->send_state = ST_SEND_NONE; -+ spin_unlock(&ir_send->lock); -+ -+ cir_update(CIR_IREN_RDR | CIR_IREN_PE, CIR_IREN); -+ -+ return ret; -+} -+ -+static void w83667hg_clean_data(struct ir_recv_t *ir_recv, struct irctl *ir) -+{ -+ spin_lock(&ir_recv->lock); -+ ir_recv->buf_count = 0; -+ /*//ir_recv->wake_state = ST_WAKE_NONE;*/ -+ wake_up(&ir_recv->queue); -+ spin_unlock(&ir_recv->lock); -+ -+ spin_lock(&ir->lock); -+ ir->lircdata = 0; -+ /* -+ for (i = 0; i < IRCTL_BUF_LIMIT; i++) { -+ ir->buf = 0; -+ } -+ */ -+ ir->pressed_keycode = 0; -+ ir->pressed_shiftmask = 0; -+ ir->buf_count = 0; -+ ir->cur_buf_num = 0; -+ /* -+ ir->study_state = ST_STUDY_NONE; -+ ir->send_state = ST_SEND_NONE; -+ */ -+ wake_up(&ir->queue); -+ spin_unlock(&ir->lock); -+ -+ cir_update(cir_read(CIR_FIFOCON) | 0x88, CIR_FIFOCON); -+ cir_wake_update(cir_wake_read(CIR_WAKE_FIFOCON) | 0x8, CIR_WAKE_FIFOCON); -+ -+} -+ -+/* 3. */ -+static void w83667hg_ir_recv_init(struct ir_recv_t *ir_recv) -+{ -+ ir_recv->buf_count = 0; -+ spin_lock_init(&ir_recv->lock); -+ ir_recv->wake_state = ST_WAKE_NONE; -+ init_waitqueue_head(&ir_recv->queue); -+ ir_recv->recv_state = ST_RECV_WAIT_7F; -+} -+ -+static void w83667hg_ir_send_init(struct ir_send_t *ir_send) -+{ -+ ir_send->buf_count = 0; -+ spin_lock_init(&ir_send->lock); -+ ir_send->send_state = ST_SEND_NONE; -+ init_waitqueue_head(&ir_send->queue); -+} -+ -+ -+/* lirc_fops -+ * -+ * 1) it's LIRC's fops, so NOT allow add owner in it -+ * 2) define lirc functions at here will replace the lirc original fops functions, so lirc_write() in lirc_dev will not work -+ * 3) lirc has its own ioctl, lirc_ioctl() in current file not register in lirc_fops, so it only work for lirc_wb667 -+ * lirc_ioctl() in current file register in w83667hg_irctl_init() as lirc_plugin's ioctl while initial driver, and it does not effect on lirc_dev -+ */ -+static struct file_operations lirc_fops = { -+ write: lirc_write, -+ ioctl : lirc_ioctl, -+}; -+ -+ -+/* init lirc buffer, register, irctl */ -+static int w83667hg_irctl_init(struct irctl *ir) -+{ -+ int err = 0, minor = -1; -+ -+ w83667hg_lirc_buffer = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!w83667hg_lirc_buffer) { -+ err = -ENOMEM; -+ goto out_lirc_buffer; -+ } -+ memset(w83667hg_lirc_buffer, 0, sizeof(struct lirc_buffer)); -+ -+ if (lirc_buffer_init(w83667hg_lirc_buffer, sizeof(int), LIRCBUF_SIZE)) { -+ err = -ENOMEM; -+ goto out_lirc_buffer; -+ } -+ -+ w83667hg_lirc_plugin = kmalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!w83667hg_lirc_plugin) { -+ err = -ENOMEM; -+ goto out_lirc_plugin; -+ } -+ memset(w83667hg_lirc_plugin, 0, sizeof(struct lirc_driver)); -+ -+ ir->lirc_plugin = w83667hg_lirc_plugin; -+ -+ strcpy(w83667hg_lirc_plugin->name, DRVNAME); -+ w83667hg_lirc_plugin->minor = -1; -+ w83667hg_lirc_plugin->features = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_TRANSMITTER_MASK | -+ LIRC_CAN_REC_MODE2; -+ /*// LIRC_CAN_SET_SEND_DUTY_CYCLE | -+ // LIRC_CAN_SET_SEND_CARRIER;*/ -+ w83667hg_lirc_plugin->data = &w83667hg_irctl; -+ w83667hg_lirc_plugin->rbuf = w83667hg_lirc_buffer; -+ w83667hg_lirc_plugin->set_use_inc = &lirc_set_use_inc; -+ w83667hg_lirc_plugin->set_use_dec = &lirc_set_use_dec; -+ w83667hg_lirc_plugin->code_length = sizeof(int) * 8; -+/*// w83667hg_lirc_plugin->ioctl = lirc_ioctl;*/ -+ w83667hg_lirc_plugin->fops = &lirc_fops; -+ w83667hg_lirc_plugin->dev = NULL; -+ w83667hg_lirc_plugin->owner = THIS_MODULE; -+ -+ minor = lirc_register_driver(w83667hg_lirc_plugin); -+ if (minor < 0) { -+ err = -ENOMEM; -+ goto out_lirc_plugin_register; -+ } -+#ifdef IR_667_DEBUG -+ printk("%s register lirc minor: %d\n", DRVNAME, minor); -+#endif -+ -+ w83667hg_lirc_plugin->minor = minor; -+ ir->lirc_plugin = w83667hg_lirc_plugin; -+ -+ /* init irctl */ -+ ir->pressed_keycode = 0; -+ ir->pressed_shiftmask = 0; -+ ir->buf_count = 0; -+ ir->ctrl_fix_head = 1; -+ spin_lock_init(&ir->lock); -+ ir->study_state = ST_STUDY_NONE; -+ init_waitqueue_head(&ir->queue); -+ -+ goto out; -+ -+ out_lirc_plugin_register: -+ kfree(w83667hg_lirc_plugin); -+ out_lirc_plugin: -+ lirc_buffer_free(w83667hg_lirc_buffer); -+ out_lirc_buffer: -+ kfree(w83667hg_lirc_buffer); -+ out: -+ return err; -+} -+ -+static void w83667hg_irctl_uninit(struct irctl *ir) -+{ -+ /*//lirc_unregister_plugin(w83667hg_lirc_plugin->minor);*/ -+ lirc_unregister_driver(w83667hg_lirc_plugin->minor); -+ kfree(w83667hg_lirc_plugin); -+ ir->lirc_plugin = NULL; -+ lirc_buffer_free(w83667hg_lirc_buffer); -+ kfree(w83667hg_lirc_buffer); -+ ir->lirc_buffer = NULL; -+} -+ -+#ifdef ALLOW_DEBUG_PRINT_PULSE -+void debug_print_pulse(void) -+{ -+ u8 count, i; -+ -+ count = cir_read(CIR_RXFCONT); -+ for (i = 0; i < count; i++) { -+ printk("%s current cir pluse: 0x%x\n", DRVNAME, cir_read(CIR_SRXFIFO)); -+ } -+} -+ -+void debug_print_wake_pulse(void) -+{ -+ u8 count, i; -+ -+ count = cir_wake_read(CIR_WAKE_FIFO_COUNT); -+ for (i = 0; i < count; i++) { -+ printk("%s current cir wake pluse: 0x%x\n", DRVNAME, cir_wake_read(CIR_WAKE_SRXFSTS)); -+ } -+} -+#endif -+ -+static void w83667hg_study_recv(struct ir_recv_t *ir_recv, struct irctl *ir) -+{ -+ unsigned int i = 0; -+ unsigned int packet_on_dur = 0; -+ -+ spin_lock(&ir_recv->lock); -+ ir_recv->buf[ir_recv->buf_count] = cir_read(CIR_SRXFIFO); -+ if (ir_recv->buf[ir_recv->buf_count] == 0x80) { -+ /* close interrupt now */ -+ /*//cir_wake_update(0, CIR_WAKE_IREN);*/ -+ -+ spin_lock(&ir->lock); -+ -+ /* 1. get carrier */ -+ ir->carrier = cir_read(CIR_FCCL); -+ ir->carrier |= cir_read(CIR_FCCH) << 8; -+ -+ if (ir->carrier == 0) { -+ printk("%s: get carrier error!\n", DRVNAME); -+ } -+ -+ i = 0; -+ for (; i < ir_recv->buf_count; i++) { -+ if (ir_recv->buf[i] & BIT_PULSE_MASK) { -+ packet_on_dur += ir_recv->buf[i] & BIT_LEN; -+ } -+ } -+ packet_on_dur *= MCE_TIME_UNIT; -+ -+#ifdef ALLOW_DEBUG_STUDY -+ printk("%s: carrier count: 0x%x\n", DRVNAME, ir->carrier); -+ printk("%s: packet on duration: %u\n", DRVNAME, packet_on_dur); -+#endif -+ ir->carrier *= 1000000; -+ ir->carrier /= packet_on_dur; -+#ifdef ALLOW_DEBUG_STUDY -+ printk("%s: final carrier frequency: %u\n", DRVNAME, ir->carrier); -+#endif -+ if ((ir->carrier > MAX_CARRIER) || (ir->carrier < MIN_CARRIER)) { -+ /* carrier is too large or too small */ -+#ifdef ALLOW_DEBUG_STUDY -+ printk("%s: current received carrier is too large or too small\n", DRVNAME); -+#endif -+ ir_recv->buf_count = 0; -+ spin_unlock(&ir_recv->lock); -+ -+ ir->buf_count = 0; -+ ir->study_state = ST_STUDY_ALL_RECV; -+ wake_up(&ir->queue); -+ spin_unlock(&ir->lock); -+ return; -+ } -+ -+ /* 2. get pulse */ -+ i = 0; -+ /* 1) find sync head */ -+ while (!((ir_recv->buf[i] & BIT_PULSE_MASK) & 0x80)) { -+ i++; -+ } -+ /* 2) find 0x7f */ -+ /* FIXME, the silent part of infrared signal may change by protocol or sample period. but current value fits MCE RC-6*/ -+ while ((ir_recv->buf[i] != 0x7f) || -+ (ir_recv->buf[i + 1] != 0x7f) || -+ (ir_recv->buf[i + 2] != 0x7f)) { -+ i++; -+ } -+ /* 3) find next head */ -+ while (!((ir_recv->buf[i] & BIT_PULSE_MASK) & 0x80)) { -+ i++; -+ } -+ /*//ir->buf_count = --i;*/ -+ /* now buf_count direct to next pulse sync head */ -+ ir->buf_count = i; -+ /* 4) copy pluse from recv to ir */ -+ i = 0; -+ for (; i <= ir->buf_count; i++) { -+ ir->buf[i] = ir_recv->buf[i]; -+ } -+ -+ -+ ir_recv->buf_count = 0; -+ spin_unlock(&ir_recv->lock); -+ -+ ir->study_state = ST_STUDY_ALL_RECV; -+ wake_up(&ir->queue); -+ spin_unlock(&ir->lock); -+ } else { -+ ir_recv->buf_count++; -+ spin_unlock(&ir_recv->lock); -+ } -+} -+ -+ -+static void w83667hg_recv(struct ir_recv_t *ir_recv, struct irctl *ir) -+{ -+ u8 buf; -+ unsigned int i = 0, rlc = 0; -+ -+ spin_lock(&ir_recv->lock); -+ -+ ir_recv->buf[ir_recv->buf_count] = cir_read(CIR_SRXFIFO); -+ if (ir_recv->buf[ir_recv->buf_count] == 0x7f) { -+ if (ir_recv->recv_state & ST_RECV_WAIT_7F) { -+ ir_recv->recv_state = ST_RECV_WAIT_HEAD; -+ ir_recv->buf_count++; -+ { /* decode begin*/ -+ spin_lock(&ir->lock); -+ -+ ir->buf_count = ir_recv->buf_count; -+ for (; i < ir->buf_count; i++) { -+ ir->buf[i] = ir_recv->buf[i]; -+ } -+ ir->cur_buf_num = 0; -+ -+ /*//ir_recv->buf_count++;*/ -+ spin_unlock(&ir_recv->lock); -+ -+ i = 0; -+ while (i < ir->buf_count) { -+ rlc += ir->buf[i] & BIT_LEN; -+ i++; -+ } -+#ifdef ALLOW_DEBUG_DECODE -+ printk("\n%s cur rlc len: %d\n", DRVNAME, rlc); -+#endif -+ -+#ifdef DECODE_KEYBOARD_MOUSE -+ if (rlc >= CONTROLLER_BUF_LEN_MIN) { -+#endif -+ /* lirc controller*/ -+ w83667hg_submit_controller(ir); -+ -+#ifdef DECODE_KEYBOARD_MOUSE -+ } else if ((rlc >= KEYBOARD_BUF_LEN_MIN) && -+ (rlc < KEYBOARD_BUF_LEN_MAX)) { -+ w83667hg_submit_key(ir); -+ input_sync(ir->input_dev); -+ } else if ((rlc >= MOUSE_BUF_LEN_MIN) && -+ (rlc < KEYBOARD_BUF_LEN_MIN)) { -+ w83667hg_submit_mouse(ir); -+ input_sync(ir->input_dev); -+ } -+#endif -+ -+ ir->buf_count = 0; -+ spin_unlock(&ir->lock); -+ } /* decode end*/ -+ } else { -+ ir_recv->buf_count++; -+ spin_unlock(&ir_recv->lock); -+ } -+ } else { /* normal recv*/ -+ if (ir_recv->recv_state & ST_RECV_WAIT_HEAD) { -+ if (ir_recv->buf[ir_recv->buf_count] & BIT_PULSE_MASK) { -+ ir_recv->recv_state = ST_RECV_WAIT_7F; -+ buf = ir_recv->buf[ir_recv->buf_count]; -+ ir_recv->buf_count = 0; -+ ir_recv->buf[0] = buf; -+ } -+ } -+ ir_recv->buf_count++; -+ spin_unlock(&ir_recv->lock); -+ } -+} -+ -+ -+ -+static void w83667hg_send_packet_to_lirc_1(struct irctl *ir, int *val) -+{ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: send data to lirc : 0x%x\n", DRVNAME, (*val)); -+#endif -+/*// lirc_buffer_write_1(ir->lirc_plugin->rbuf, (char *)val);*/ -+ lirc_buffer_write(ir->lirc_plugin->rbuf, (char *)val); -+ wake_up(&ir->lirc_plugin->rbuf->wait_poll); -+} -+ -+ -+static void w83667hg_submit_controller(struct irctl *ir) -+{ -+ unsigned int buf_num; -+ u8 bit; -+ -+ static struct timeval last_time; -+ static bool is_not_initialed_yet = true; /* lirc group does not allow to initialize static variable to false(0) */ -+ struct timeval curr_time; -+ long duration; -+ -+ /* silence time */ -+ -+ ir->lircdata = 0; -+ -+ if (is_not_initialed_yet == true) { -+ duration = MAX_SILENCE_TIME; -+ is_not_initialed_yet = false; -+ } else{ -+ do_gettimeofday(&curr_time); -+ duration = (curr_time.tv_usec - last_time.tv_usec) + -+ (curr_time.tv_sec - last_time.tv_sec) * 1000000; -+ } -+ -+ if (duration >= MAX_SILENCE_TIME) { -+ ir->lircdata = MAX_SILENCE_TIME; -+ } else{ -+ ir->lircdata = duration; -+ } -+ w83667hg_send_packet_to_lirc_1(ir, &ir->lircdata); -+ -+ -+ /* fix controller head not sync problem */ -+ /* lirc doesn't response DK MCE controller signal until press several times, not find same problem on M$ MCE controller keyboard */ -+ /* for lirc group's suggestion, we need not add these code to prevent from this problem. -+ Just make it as comment. If we do not get any problem report from our customer, we will remove it at next some version. -+ if (ir->ctrl_fix_head) { -+ ir->lircdata = 50000; -+ w83667hg_send_packet_to_lirc_1(ir, &ir->lircdata); -+ ir->ctrl_fix_head = 0; -+ } -+ */ -+ -+ -+ buf_num = 0; -+ bit = BIT_PULSE_MASK; -+ ir->lircdata = 0; -+ for (; buf_num < ir->buf_count; buf_num++) { -+ if (bit == (ir->buf[buf_num] & BIT_PULSE_MASK)) { -+ ir->lircdata += (ir->buf[buf_num] & BIT_LEN) * MCE_TIME_UNIT; -+ } else { -+ if (bit) { -+ ir->lircdata |= PULSE_BIT; -+ } -+ w83667hg_send_packet_to_lirc_1(ir, &ir->lircdata); -+ bit = ir->buf[buf_num] & BIT_PULSE_MASK; -+ ir->lircdata = (ir->buf[buf_num] & BIT_LEN) * MCE_TIME_UNIT; -+ } -+ } -+ -+ /* update last_time for measure silence time*/ -+ do_gettimeofday(&last_time); -+ -+ /* for final silent pulse */ -+ /*ir->lircdata = 50000; -+ w83667hg_send_packet_to_lirc_1(ir, &ir->lircdata);*/ -+ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("\n"); -+#endif -+} -+ -+static irqreturn_t w83667hg_interrupt_handler(int irq, void *dev) -+{ -+ u8 tmp = 0; -+ struct irctl *ir = (struct irctl *)dev; -+ struct ir_send_t *ir_send = &w83667hg_ir_send; -+ -+ -+ /*Because interrupt is shared, check IREN first. */ -+ tmp = cir_read(CIR_IREN); -+ if (!tmp) { -+ return IRQ_RETVAL(IRQ_NONE); -+ } -+ tmp = cir_read(CIR_IRSTS); -+ cir_update(0xff, CIR_IRSTS); -+ if (!tmp) { -+ return IRQ_NONE; -+ } -+ if (tmp & CIR_IRSTS_RDR) { -+ -+ -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_IRSTS_RDR\n"); -+#endif -+#ifdef ALLOW_DEBUG_PRINT_PULSE -+ debug_print_pulse(); -+#else -+ spin_lock(&ir_send->lock); -+ if (ir_send->send_state == ST_SEND_NONE) { -+ spin_unlock(&ir_send->lock); -+ if (ir->study_state & ST_STUDY_START) { -+ w83667hg_study_recv(&w83667hg_ir_recv, &w83667hg_irctl); -+ } else { -+ w83667hg_recv(&w83667hg_ir_recv, &w83667hg_irctl); -+ } -+ } else { -+ spin_unlock(&ir_send->lock); -+ } -+#endif -+ } -+ if (tmp & CIR_IRSTS_RTR) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_IRSTS_RTR\n"); -+#endif -+ } -+ if (tmp & CIR_IRSTS_PE) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_IRSTS_PE\n"); -+#endif -+#ifdef ALLOW_DEBUG_PRINT_PULSE -+ printk("\n now get interrupt PE\n\n"); -+ debug_print_pulse(); -+#else -+ if (ir->study_state == ST_STUDY_NONE) { -+ w83667hg_clean_data(&w83667hg_ir_recv, &w83667hg_irctl); -+ } -+#endif -+ } -+ if (tmp & CIR_IRSTS_RFO) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_IRSTS_RFO\n"); -+#endif -+ } -+ if (tmp & CIR_IRSTS_TE) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_IRSTS_TE\n"); -+#endif -+ } -+ if (tmp & CIR_IRSTS_TTR) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_IRSTS_TTR\n"); -+#endif -+ -+ spin_lock(&ir_send->lock); -+ if (ir_send->cur_buf_num < ir_send->buf_count) { -+ cir_update(ir_send->buf[ir_send->cur_buf_num++], CIR_STXFIFO); -+ } else { -+ cir_update(cir_read(CIR_IREN) & (~CIR_IREN_TTR), CIR_IREN); -+ } -+ spin_unlock(&ir_send->lock); -+ -+ } -+ if (tmp & CIR_IRSTS_TFU) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_IRSTS_TFU\n"); -+#endif -+ spin_lock(&ir_send->lock); -+ if (ST_SEND_REPLY == ir_send->send_state) { -+ ir_send->send_state = ST_SEND_REQUEST; -+ wake_up(&ir_send->queue); -+ } -+ spin_unlock(&ir_send->lock); -+ } -+ if (tmp & CIR_IRSTS_GH) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_IRSTS_GH\n"); -+#endif -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t w83667hg_wake_interrupt_handler(int irq, void *dev) -+{ -+ u8 tmp; -+ struct ir_recv_t *ir_recv = (struct ir_recv_t *)dev; -+ -+ -+ /*Because interrupt is shared, check IREN first. */ -+ tmp = cir_wake_read(CIR_WAKE_IREN); -+ if (!tmp) { -+ return IRQ_RETVAL(IRQ_NONE); -+ } -+ -+ tmp = cir_wake_read(CIR_WAKE_IRSTS); -+ if (!tmp) { -+ return IRQ_NONE; -+ } -+ cir_wake_update(0xff, CIR_WAKE_IRSTS); -+ -+ if (tmp & CIR_WAKE_IRSTS_RDR) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_WAKE_IRSTS_RDR\n"); -+#endif -+#ifdef ALLOW_DEBUG_PRINT_PULSE -+ debug_print_wake_pulse(); -+#endif -+ } -+ if (tmp & CIR_WAKE_IRSTS_RTR) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_WAKE_IRSTS_RTR\n"); -+#endif -+ } -+ if ((tmp & CIR_WAKE_IRSTS_PE) && -+ (ST_WAKE_START == ir_recv->wake_state)) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_WAKE_IRSTS_PE\n"); -+#endif -+#ifdef ALLOW_DEBUG_PRINT_PULSE -+ printk("\n now get interrupt PE\n\n"); -+ debug_print_wake_pulse(); -+#else -+ while ((cir_wake_read(CIR_WAKE_RD_FIFO_ONLY_IDX)) != 0) { -+#ifdef ALLOW_DEBUG_WAKE -+ printk("%s setting wake up key: 0x%x\n", DRVNAME, cir_wake_read(CIR_WAKE_RD_FIFO_ONLY)); -+#else -+ cir_wake_read(CIR_WAKE_RD_FIFO_ONLY); -+#endif -+ } -+ -+ cir_wake_update(0, CIR_WAKE_IREN); -+ spin_lock(&ir_recv->lock); -+ ir_recv->wake_state = ST_WAKE_FINISH; -+ wake_up(&ir_recv->queue); -+ spin_unlock(&ir_recv->lock); -+#endif -+ } -+ if (tmp & CIR_WAKE_IRSTS_RFO) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_WAKE_IRSTS_RFO\n"); -+#endif -+ } -+ if (tmp & CIR_WAKE_IRSTS_GH) { -+#ifdef ALLOW_DEBUG_INTERRUPT -+ printk("get CIR_WAKE_IRSTS_GH\n"); -+#endif -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+/* 4. */ -+/* init 667 cir dev, req_region, req_irq */ -+static int w83667hg_cir_probe(void) -+{ -+ int err = 0; -+ -+ if (!request_region(cir_address, CIR_IOREG_LENGTH, DRVNAME)) { -+ err = -EBUSY; -+#ifdef IR_667_DEBUG -+ printk("%s request 667 cir io port error! \n", DRVNAME); -+#endif -+ goto exit; -+ } -+ -+ cir_update(CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, CIR_IRCON); -+ cir_update(0xFF, CIR_IRSTS); -+ cir_update(CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH); -+ cir_update(CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL); -+ cir_update(CIR_FIFOCON_TXFIFOCLR | CIR_FIFOCON_TX_TRIGGER_LEV_24 | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); -+ cir_update(CIR_IRCON_RECV | CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, CIR_IRCON); -+ cir_update(CIR_IRCON_TXEN | CIR_IRCON_RXEN | CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, CIR_IRCON); -+ -+ if (0 != request_irq(CIR_IRQ_NUM, w83667hg_interrupt_handler, IRQF_SHARED, -+ DRVNAME, &w83667hg_irctl)) { -+ err = -EINTR; -+#ifdef IR_667_DEBUG -+ printk("%s : request cir irq error\n", DRVNAME); -+#endif -+ goto rel_irq_exit; -+ } -+ /* open interrupt */ -+ cir_update(CIR_IREN_RDR | CIR_IREN_PE, CIR_IREN); -+ -+ if (!request_region(cir_wake_address, CIR_IOREG_LENGTH, DRVNAME)) { -+ err = -EBUSY; -+#ifdef IR_667_DEBUG -+ printk("%s request 667 cir wake io port error! \n", DRVNAME); -+#endif -+ goto rel_wake_exit; -+ } -+ -+ cir_wake_update(0xff, CIR_WAKE_IRSTS); -+ /* Modify it as more safe values: CIR_WAKE_FIFO_CMP_DEEP reg:0x41, -+ CIR_WAKE_FIFO_CMP_TOL reg: 0x05. 20091224 -+ */ -+ cir_wake_update(0x41, CIR_WAKE_FIFO_CMP_DEEP); /* 0x41 = 65 */ -+ cir_wake_update(0x05, CIR_WAKE_FIFO_CMP_TOL); -+ cir_wake_update(CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH); -+ cir_wake_update(CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL); -+ cir_wake_update(0xff, CIR_WAKE_FIFOCON); -+ cir_wake_update(0, CIR_WAKE_FIFOCON); -+ cir_wake_update(CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, CIR_WAKE_IRCON); -+ -+ /* cir wake has irq_handler, open interrupt after received ioctl IR_IOLEARNWAKE */ -+ if (0 != request_irq(CIR_WAKE_IRQ_NUM, w83667hg_wake_interrupt_handler, IRQF_SHARED, -+ DRVNAME, &w83667hg_ir_recv)) { -+ err = -EINTR; -+#ifdef IR_667_DEBUG -+ printk("%s : request cir wake irq error\n", DRVNAME); -+#endif -+ goto rel_wake_irq_exit; -+ } -+ -+#ifdef IR_667_DEBUG -+ printk("%s : init cir success\n", DRVNAME); -+#endif -+ goto exit; -+ -+ /* error exit */ -+ rel_wake_irq_exit: -+ release_region(cir_wake_address, CIR_IOREG_LENGTH); -+ rel_wake_exit: -+ cir_update(0, CIR_IREN); -+ free_irq(CIR_IRQ_NUM, &w83667hg_irctl); -+ rel_irq_exit: -+ release_region(cir_address, CIR_IOREG_LENGTH); -+ -+ /* final exit */ -+ exit: -+ return err; -+} -+ -+static void w83667hg_cir_remove(void) -+{ -+ /* Don't clean CIR_WAKE_IRCON. When wake-up at power-on, it needs the function. 20091224 -+ cir_wake_update(0, CIR_WAKE_IRCON); -+ */ -+ free_irq(CIR_WAKE_IRQ_NUM, &w83667hg_ir_recv); -+ release_region(cir_wake_address, CIR_IOREG_LENGTH); -+ cir_update(0, CIR_IRCON); -+ free_irq(CIR_IRQ_NUM, &w83667hg_irctl); -+ release_region(cir_address, CIR_IOREG_LENGTH); -+} -+ -+static int lirc_wb667_init(void) -+{ -+ int err = 0; -+ -+ /* Initialise global static variables here instead of at declaration becuase of -+ lirc group does not allow it.*/ -+#ifdef CONFIG_PNP -+ nopnp = 0; -+#else -+ nopnp = 1; -+#endif -+ w83667hg_input_dev = NULL; -+ w83667hg_lirc_plugin = NULL; -+ w83667hg_lirc_buffer = NULL; -+ -+ /* 1. init cr */ -+ if (w83667hg_cr_init()) { -+ printk("%s: Unable to init device.\n", DRVNAME); -+ err = -ENODEV; -+ goto out; -+ } -+ -+ /* 2. init input */ -+ w83667hg_input_dev = w83667hg_input_init(); -+ if (!w83667hg_input_dev) { -+ printk("%s: Unable to register input device.\n", DRVNAME); -+ err = -ENODEV; -+ goto out_input; -+ } -+ w83667hg_irctl.input_dev = w83667hg_input_dev; -+ -+ /* 3. init lirc buffer, register, irctl */ -+ w83667hg_ir_recv_init(&w83667hg_ir_recv); -+ w83667hg_ir_send_init(&w83667hg_ir_send); -+ err = w83667hg_irctl_init(&w83667hg_irctl); -+ if (err) { -+ printk("%s: Unable to register lirc.\n", DRVNAME); -+ goto out_irctl; -+ } -+ -+ -+ /* 4. init 667 cir dev, req_region, req_irq */ -+ err = w83667hg_cir_probe(); -+ if (err) { -+ printk("%s: Unable to probe cir device.\n", DRVNAME); -+ goto out_cir_probe; -+ } -+ -+ goto out; -+ -+ /* error exit */ -+ out_cir_probe: -+ w83667hg_irctl_uninit(&w83667hg_irctl); -+ w83667hg_irctl.input_dev = NULL; -+ out_irctl: -+ w83667hg_input_uninit(w83667hg_input_dev); -+ out_input: -+ w83667hg_cr_uninit(); -+ -+ /* final exit */ -+ out: -+ return err; -+} -+ -+void lirc_wb667_uninit(void) -+{ -+ w83667hg_cir_remove(); -+ w83667hg_irctl_uninit(&w83667hg_irctl); -+ w83667hg_irctl.input_dev = NULL; -+ w83667hg_input_uninit(w83667hg_input_dev); -+ w83667hg_cr_uninit(); -+ -+} -+ -+ -+ -+/* For resume function use only. 20100119*/ -+static void w83667hg_irctl_resume_reset(struct irctl *ir) -+{ -+ /* init irctl */ -+ ir->pressed_keycode = 0; -+ ir->pressed_shiftmask = 0; -+ ir->buf_count = 0; -+ ir->ctrl_fix_head = 1; -+ spin_lock_init(&ir->lock); -+ ir->study_state = ST_STUDY_NONE; -+ init_waitqueue_head(&ir->queue); -+} -+ -+ -+/* For resume function use only. 20100119*/ -+static int w83667hg_cir_resume_reset(void) -+{ -+ int err = 0; -+ -+ cir_update(CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, CIR_IRCON); -+ cir_update(0xFF, CIR_IRSTS); -+ cir_update(CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH); -+ cir_update(CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL); -+ cir_update(CIR_FIFOCON_TXFIFOCLR | CIR_FIFOCON_TX_TRIGGER_LEV_24 | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); -+ cir_update(CIR_IRCON_RECV | CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, CIR_IRCON); -+ cir_update(CIR_IRCON_TXEN | CIR_IRCON_RXEN | CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, CIR_IRCON); -+ -+ /* open interrupt */ -+ cir_update(CIR_IREN_RDR | CIR_IREN_PE, CIR_IREN); -+ -+ -+ cir_wake_update(0xff, CIR_WAKE_IRSTS); -+ -+ cir_wake_update(0x41, CIR_WAKE_FIFO_CMP_DEEP); /* 0x41 = 65 */ -+ cir_wake_update(0x05, CIR_WAKE_FIFO_CMP_TOL); -+ cir_wake_update(CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH); -+ cir_wake_update(CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL); -+ cir_wake_update(0xff, CIR_WAKE_FIFOCON); -+ cir_wake_update(0, CIR_WAKE_FIFOCON); -+ cir_wake_update(CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, CIR_WAKE_IRCON); -+ -+ -+#ifdef IR_667_DEBUG -+ printk("%s : cir_resume_reset finish\n", DRVNAME); -+#endif -+ -+ return err; -+} -+ -+ -+/* For resume function use only. 20100119*/ -+static int lirc_wb667_resume_init(void) -+{ -+ int err = 0; -+ -+ /* init lirc buffer */ -+ w83667hg_ir_recv_init(&w83667hg_ir_recv); -+ w83667hg_ir_send_init(&w83667hg_ir_send); -+ -+ /* reset variables in irctl, but no re-locate and no re-register 20100119*/ -+ w83667hg_irctl_resume_reset(&w83667hg_irctl); -+ -+ -+ /* init 667 cir dev */ -+ -+ w83667hg_cir_resume_reset(); -+ -+ -+ return err; -+} -+ -+ -+ -+#ifdef CONFIG_PNP -+ -+/* CIR and CIR WAKE */ -+ -+static struct pnp_driver lirc_wb667_pnp_driver = { -+ .name = PLATNAME, -+ .id_table = pnp_dev_table, -+ .probe = lirc_wb667_pnp_probe, -+ .remove = __devexit_p(lirc_wb667_pnp_remove), -+ .suspend = lirc_wb667_pnp_suspend, -+ .resume = lirc_wb667_pnp_resume, -+}; -+ -+static int __devinit lirc_wb667_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) -+{ -+ /* CIR */ -+ -+ #ifdef IR_667_DEBUG -+ printk("%s receive probe\n", DRVNAME); -+ #endif -+ -+ if (!pnp_port_valid(dev, 0)) -+ return -ENODEV; -+ -+ -+ CIR_BASE = (unsigned int)pnp_port_start(dev, 0); -+ CIR_IRQ_NUM = (unsigned short)pnp_irq(dev, 0); -+ -+ -+ /* CIR WAKE*/ -+ if (!pnp_port_valid(dev, 1)) -+ return -ENODEV; -+ CIR_WAKE_BASE = (unsigned int)pnp_port_start(dev, 1); -+ CIR_WAKE_IRQ_NUM = (unsigned short)pnp_irq(dev, 0); /* share the same irq with CIR device.*/ -+ -+ return 0; -+} -+ -+static void __devexit lirc_wb667_pnp_remove(struct pnp_dev *dev) -+{ -+} -+ -+ -+ -+static int lirc_wb667_pnp_suspend(struct pnp_dev *dev, pm_message_t state) -+{ -+ struct irctl *ir = &w83667hg_irctl; -+ struct ir_recv_t *ir_recv = &w83667hg_ir_recv; -+ struct ir_send_t *ir_send = &w83667hg_ir_send; -+ -+#ifdef IR_667_DEBUG -+ printk("%s receive suspend\n", DRVNAME); -+#endif -+ -+ /* 1. */ -+ spin_lock(&ir->lock); -+ ir->study_state = ST_STUDY_NONE; -+ spin_unlock(&ir->lock); -+ -+ spin_lock(&ir_recv->lock); -+ ir_recv->wake_state = ST_WAKE_NONE; -+ spin_unlock(&ir_recv->lock); -+ -+ spin_lock(&ir_send->lock); -+ ir_send->send_state = ST_SEND_NONE; -+ spin_unlock(&ir_send->lock); -+ -+ /* 2. */ -+ cir_update(0, CIR_IREN); -+ cir_wake_update(0, CIR_WAKE_IREN); -+ -+ -+ /* 3. */ -+ cr_enter_ext(); -+ cr_select_log_dev(CIR_LOG_DEV); -+ cr_update(DEACTIVE_LOG_DEV, 0x30); -+ -+ /*Don't close CIR Wake. When wake-up at power-on, it needs the function. 20091224 -+ cr_select_log_dev(CIR_WAKE_LOG_DEV); -+ cr_update(DEACTIVE_LOG_DEV, 0x30); -+ */ -+ -+ cr_exit_ext(); -+ -+ -+ return 0; -+} -+ -+static int lirc_wb667_pnp_resume(struct pnp_dev *dev) -+{ -+ int ret = 0; -+ -+#ifdef IR_667_DEBUG -+ printk("%s receive resume\n", DRVNAME); -+#endif -+ -+ -+ /* open interrupt */ -+ cir_update(CIR_IREN_RDR | CIR_IREN_PE, CIR_IREN); -+ -+ -+ /* Enable CIR logical device */ -+ cr_enter_ext(); -+ cr_select_log_dev(CIR_LOG_DEV); -+ cr_update(ACTIVE_LOG_DEV, 0x30); -+ -+ -+ /*Don't close CIR Wake. When wake-up at power-on, it needs the function. 20091224 -+ cr_select_log_dev(CIR_WAKE_LOG_DEV); -+ cr_update(ACTIVE_LOG_DEV, 0x30); -+ */ -+ cr_exit_ext(); -+ -+ /* special uninit function for resume only. 20100119 */ -+ lirc_wb667_resume_init(); -+ -+ return ret; -+} -+ -+ -+ -+ -+ -+ -+#endif -+ -+ -+/*//int init_module(void)*/ -+int init_module_wb667(void) -+{ -+ int ret; -+ -+ if (nopnp) { -+ printk("%s does not support Non-PNP kernel now.\n", DRVNAME); -+ } -+ -+#ifdef CONFIG_PNP -+ if (!nopnp) { -+ -+ ret = pnp_register_driver(&lirc_wb667_pnp_driver); -+ if (ret < 0) -+ return ret; -+ -+ -+ -+ } -+#endif /* CONFIG_PNP */ -+ -+ -+ -+ -+ ret = lirc_wb667_init(); -+ if (ret) { -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/*//void cleanup_module(void)*/ -+void cleanup_module_wb667(void) -+{ -+ -+#ifdef CONFIG_PNP -+ if (!nopnp) { -+ pnp_unregister_driver(&lirc_wb667_pnp_driver); -+ -+ } -+#endif /* CONFIG_PNP */ -+ -+ -+ lirc_wb667_uninit(); -+} -+ -+module_init(init_module_wb667); -+module_exit(cleanup_module_wb667); -+ -+ -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_wb677_mouse_kbd.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677_mouse_kbd.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_wb677_mouse_kbd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677_mouse_kbd.c 2010-04-03 18:42:04.214701792 +0200 -@@ -0,0 +1,881 @@ -+/* Notice: -+ Do NOT merge this file with other file. -+ According to lirc group's suggestion, they hope that -+ we should put keyboard/mouse decoding into a separate file if we want to preserve it. -+*/ -+ -+#include -+#include "lirc_wb677_common_extern.h" -+#include "lirc_wb677_mouse_kbd.h" -+ -+ -+void w83667hg_set_key(u8 *set_frame, u8 val, u8 *keycode, u8 *shiftmask) -+{ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s set key: %d\n", DRVNAME, val); -+#endif -+ -+ if (*set_frame <= KEY_SUBMIT_KEYCODE_FRAME_NUM + 1) { -+ *keycode <<= 1; -+ *keycode |= val; -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s set key keycode:0x%x\n", DRVNAME, *keycode); -+ printk("set frame: %d\n", *set_frame); -+#endif -+ } else { -+ *shiftmask <<= 1; -+ *shiftmask |= val; -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s set key mask:0x%x\n", DRVNAME, *shiftmask); -+ printk("set frame: %d\n", *set_frame); -+#endif -+ } -+ (*set_frame)++; -+} -+ -+ -+int w83667hg_jump_frame(struct irctl *ir, u8 frame_num, unsigned int *buf_num, u8 *out_bit, u8 *decode_status) -+{ -+ unsigned int rlc = 0, cur_buf_num = *buf_num; -+ u8 bit = *out_bit, buf; -+ u8 cur_decode_status = *decode_status; -+ u8 cur_frame_num; -+ -+ cur_frame_num = 1; -+ for (; cur_frame_num <= frame_num; cur_buf_num++) { -+ buf = ir->buf[cur_buf_num]; -+ if (cur_buf_num > ir->buf_count) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: jump frame error\n", DRVNAME); -+ printk("current buf num: %d\n", cur_buf_num); -+ printk("current jumped frame: %d\n", cur_frame_num); -+ printk("current frame length: %d\n", rlc); -+ printk("total cir signal:\n"); -+ for (cur_buf_num = 0; cur_buf_num < ir->buf_count; cur_buf_num++) { -+ printk("0x%x ", ir->buf[cur_buf_num]); -+ if (cur_buf_num % 6 == 5) { -+ printk("\n"); -+ } -+ } -+#endif -+ return -1; -+ } -+ if (bit == (buf & BIT_PULSE_MASK)) { -+ rlc += buf & BIT_LEN; -+ } else { -+ -+ /* decode*/ -+ switch (cur_decode_status) { -+ case ST_DECODE_NEW: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ cur_decode_status = ST_DECODE_ONE; -+ } else { -+ cur_decode_status = ST_DECODE_ZERO; -+ } -+ } else if ((rlc > TWO_PULSE_LEN_LOW) && -+ (rlc < TWO_PULSE_LEN_HIGH)) { -+ /* error occur, just ignore */ -+ cur_decode_status = ST_DECODE_NEW; -+ cur_frame_num++; -+ } -+ break; -+ case ST_DECODE_ZERO: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "01" => 0 */ -+ cur_decode_status = ST_DECODE_NEW; -+ cur_frame_num++; -+ } else { -+ /* error */ -+ cur_decode_status = ST_DECODE_NEW; -+ cur_frame_num++; -+ } -+ } else if ((rlc > TWO_PULSE_LEN_LOW) && -+ (rlc < TWO_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "01" => 0 */ -+ cur_decode_status = ST_DECODE_ONE; -+ cur_frame_num++; -+ } else { -+ /* error */ -+ cur_decode_status = ST_DECODE_ZERO; -+ cur_frame_num++; -+ } -+ } -+ break; -+ case ST_DECODE_ONE: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "11" => error */ -+ cur_decode_status = ST_DECODE_NEW; -+ cur_frame_num++; -+ } else { -+ /* "10" => 1 */ -+ cur_decode_status = ST_DECODE_NEW; -+ cur_frame_num++; -+ } -+ } else if (rlc > TWO_PULSE_LEN_LOW) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "11" => error */ -+ cur_decode_status = ST_DECODE_ONE; -+ cur_frame_num++; -+ } else { -+ /* "10" => 1 */ -+ cur_decode_status = ST_DECODE_ZERO; -+ cur_frame_num++; -+ } -+ } -+ break; -+ } /* switch*/ -+ -+ bit = buf & BIT_PULSE_MASK; -+ rlc = buf & BIT_LEN; -+ } -+ } /* for decode*/ -+ -+/* -+ bit = ir->buf[cur_buf_num] & BIT_PULSE_MASK; -+ if (cur_decode_status & ST_DECODE_NEW) { -+ if (bit) { -+ *decode_status = ST_DECODE_ONE; -+ } else { -+ *decode_status = ST_DECODE_ZERO; -+ } -+ } else { -+ *decode_status = ST_DECODE_NEW; -+ } -+ *out_bit = bit; -+*/ -+ -+ /* Fix problem 1 */ -+ if ((ir->buf[cur_buf_num] & BIT_LEN) > TWO_PULSE_LEN_LOW) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: fix problem 1 in jump_frame()\n", DRVNAME); -+#endif -+#ifdef ALLOW_DEBUG_DECODE -+ if (cur_frame_num > frame_num + 1) { -+ printk("%s error: jump_frame() get a too long frame\n", DRVNAME); -+ } -+#endif -+ cur_buf_num--; -+ } -+ -+ /* copy from jump_iden */ -+ if (cur_decode_status & ST_DECODE_NEW) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("hey man, it's NEW in jump_frame\n"); -+printk("cur buf: 0x%x\n", ir->buf[cur_buf_num]); -+printk("cur state: 0x%x\n", cur_decode_status); -+#endif -+ *buf_num = --cur_buf_num; -+ /*//cur_buf_num--;*/ -+ *out_bit = ir->buf[cur_buf_num] & BIT_PULSE_MASK; -+ if (*out_bit) { -+ *decode_status = ST_DECODE_ONE; -+ } else { -+ *decode_status = ST_DECODE_ZERO; -+ } -+ } else { -+#ifdef ALLOW_DEBUG_DECODE -+printk("cur buf: 0x%x\n", ir->buf[cur_buf_num]); -+printk("cur state: 0x%x\n", cur_decode_status); -+#endif -+ *buf_num = cur_buf_num; -+ *out_bit = ir->buf[cur_buf_num] & BIT_PULSE_MASK; -+ *decode_status = ST_DECODE_NEW; -+/* -+ if (*out_bit) { -+ *decode_status = ST_DECODE_ONE; -+ } else { -+ *decode_status = ST_DECODE_ZERO; -+ } -+*/ -+ } -+ -+ return 0; -+} -+ -+int w83667hg_jump_head(struct irctl *ir, unsigned int *buf_num) -+{ -+ unsigned int i, rlc = 0, max_buf_count = ir->buf_count; -+ u8 bit = BIT_PULSE_MASK, buf; -+ -+ for (i = 0; i < max_buf_count; i++) { -+ buf = ir->buf[i]; -+ if (bit == (buf & BIT_PULSE_MASK)) { -+ rlc += buf & BIT_LEN; -+ } else { -+ if ((rlc > HEAD_SYNC_LEN_LOW) && -+ (rlc < HEAD_SYNC_LEN_HIGH) && -+ (bit & BIT_PULSE_MASK)) { -+ break; -+ } -+ bit = buf & BIT_PULSE_MASK; -+ rlc = buf & BIT_LEN; -+ } -+ } /* for decode*/ -+ -+ if (i >= max_buf_count) { -+/*//#ifdef ALLOW_DEBUG_DECODE*/ -+#if 0 -+ printk("%s jump pulse error\n", DRVNAME); -+ printk("current buf num: %d\n", *buf_num); -+ printk("current jumped pulse: %d\n", i); -+ printk("current pulse length: %d\n", rlc); -+ printk("total cir signal:\n"); -+ for (i = 0; i < max_buf_count; i++) { -+ printk("0x%x ", ir->buf[i]); -+ if (i % 6 == 5) { -+ printk("\n"); -+ } -+ } -+#endif -+ return -1; -+ } -+ -+ *buf_num = i; -+ -+ return 0; -+} -+ -+ -+int w83667hg_check_identification(u8 val, u8 identification, u8 *cur_iden) -+{ -+ *cur_iden <<= 1; -+ *cur_iden |= val ; -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s current check iden recv: %d\n", DRVNAME, val); -+ printk("%s current iden value: 0x%x\n", DRVNAME, *cur_iden); -+#endif -+ -+ if (identification == (*cur_iden & IDENTIFICATION_CHECK_BIT)) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s find identification\n\n", DRVNAME); -+#endif -+ return 0; -+ } else { -+ return -1; -+ } -+} -+ -+int w83667hg_jump_identification(struct irctl *ir, u8 identification, unsigned int *buf_num, u8 *out_bit, u8 *decode_status) -+{ -+ unsigned int rlc = 0, i = 1; -+ u8 bit = *out_bit, buf; -+ u8 cur_iden = 0; -+ u8 cur_decode_status = *decode_status; -+ -+ bit = BIT_PULSE_MASK; -+ cur_decode_status = ST_DECODE_NEW; -+ -+ for (; i < ir->buf_count; i++) { -+ buf = ir->buf[i]; -+#ifdef ALLOW_DEBUG_DECODE -+printk("buf: 0x%x\n", buf); -+#endif -+ if (bit == (buf & BIT_PULSE_MASK)) { -+ rlc += buf & BIT_LEN; -+ } else { -+ /* decode*/ -+ switch (cur_decode_status) { -+ case ST_DECODE_NEW: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ cur_decode_status = ST_DECODE_ONE; -+ } else { -+ cur_decode_status = ST_DECODE_ZERO; -+ } -+ } else if ((rlc > TWO_PULSE_LEN_LOW) && -+ (rlc < TWO_PULSE_LEN_HIGH)) { -+ /* error occur, just ignore */ -+ cur_decode_status = ST_DECODE_NEW; -+ if (!w83667hg_check_identification(0, identification, &cur_iden)) { -+ goto find_iden; -+ } -+ } -+ break; -+ case ST_DECODE_ZERO: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "01" => 0 */ -+ cur_decode_status = ST_DECODE_NEW; -+ if (!w83667hg_check_identification(0, identification, &cur_iden)) { -+ goto find_iden; -+ } -+ } else { -+ /* error */ -+ cur_decode_status = ST_DECODE_NEW; -+ if (!w83667hg_check_identification(0, identification, &cur_iden)) { -+ goto find_iden; -+ } -+ } -+ } else if ((rlc > TWO_PULSE_LEN_LOW) && -+ (rlc < TWO_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "01" => 0 */ -+ cur_decode_status = ST_DECODE_ONE; -+ if (!w83667hg_check_identification(0, identification, &cur_iden)) { -+ goto find_iden; -+ } -+ } else { -+ /* error */ -+ cur_decode_status = ST_DECODE_ZERO; -+ if (!w83667hg_check_identification(0, identification, &cur_iden)) { -+ goto find_iden; -+ } -+ } -+ } -+ break; -+ case ST_DECODE_ONE: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "11" => error */ -+ cur_decode_status = ST_DECODE_NEW; -+ if (!w83667hg_check_identification(0, identification, &cur_iden)) { -+ goto find_iden; -+ } -+ } else { -+ /* "10" => 1 */ -+ cur_decode_status = ST_DECODE_NEW; -+ if (!w83667hg_check_identification(1, identification, &cur_iden)) { -+ goto find_iden; -+ } -+ } -+ } else if (rlc > TWO_PULSE_LEN_LOW) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "11" => error */ -+ cur_decode_status = ST_DECODE_ONE; -+ if (!w83667hg_check_identification(0, identification, &cur_iden)) { -+ goto find_iden; -+ } -+ } else { -+ /* "10" => 1 */ -+ cur_decode_status = ST_DECODE_ZERO; -+ if (!w83667hg_check_identification(1, identification, &cur_iden)) { -+ goto find_iden; -+ } -+ } -+ } -+ break; -+ } /* switch*/ -+ bit = buf & BIT_PULSE_MASK; -+ rlc = buf & BIT_LEN; -+ } -+ } -+ -+ if (i >= ir->buf_count) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s jump iden error\n", DRVNAME); -+ printk("current buf num: %d\n", i); -+ printk("current pulse length: %d\n", rlc); -+ printk("total cir signal:\n"); -+ for (i = 0; i < ir->buf_count; i++) { -+ printk("0x%x ", ir->buf[i]); -+ if (i % 6 == 5) { -+ printk("\n"); -+ } -+ } -+#endif -+ return -1; -+ } -+ -+ find_iden: -+#ifdef ALLOW_DEBUG_DECODE -+ printk("current buf num after iden: %d\n", i); -+ printk("current pulse length: %d\n", rlc); -+#endif -+ /* try fix problem 1 */ -+ if ((rlc & BIT_LEN) >= TWO_PULSE_LEN_LOW) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s fix problem 1 in jump iden\n", DRVNAME); -+ printk("cur pulse len: %d\n", ir->buf[i] & BIT_LEN); -+#endif -+ *buf_num = i + 1; -+ *out_bit = ir->buf[i] & BIT_PULSE_MASK; -+ if (*out_bit) { -+ *decode_status = ST_DECODE_ZERO; -+ } else { -+ *decode_status = ST_DECODE_ONE; -+ } -+ -+ return 0; -+ } -+ -+ /* now find identification successful! */ -+ { -+ *buf_num = i; -+ i--; -+ *out_bit = ir->buf[i] & BIT_PULSE_MASK; -+ if (bit) { -+ *decode_status = ST_DECODE_ONE; -+ } else { -+ *decode_status = ST_DECODE_ZERO; -+ } -+ } -+#ifdef ALLOW_DEBUG_DECODE -+ printk("total cir signal:\n"); -+ for (i = 0; i < ir->buf_count; i++) { -+ printk("0x%x ", ir->buf[i]); -+ if (i % 7 == 6) { -+ printk("\n"); -+ } -+ } -+ printk("\n"); -+#endif -+ -+ return 0; -+} -+ -+void w83667hg_submit_key(struct irctl *ir) -+{ -+ unsigned int rlc = 0, buf_num = 0, i; -+ /* current usb keyboard key code setting, usb_kbd_keycode[keycode] */ -+ unsigned int input_code; -+ u8 bit, buf; -+ /* keycode and shiftmask parts in mce keyboard protocol*/ -+ u8 keycode = 0, shiftmask = 0; -+ u8 decode_status; -+ u8 frame_num, set_frame; -+ -+ /* 1) jump head */ -+ if (w83667hg_jump_head(ir, &buf_num)) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: decode key jump head error\n", DRVNAME); -+#endif -+ return; -+ } -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s buf_num after jump head: %d\n", DRVNAME, buf_num); -+#endif -+ -+ /* 2) jump identification */ -+ if (w83667hg_jump_identification(ir, KEY_IDENTIFICATION, &buf_num, &bit, &decode_status)) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: decode key jump identification error\n", DRVNAME); -+#endif -+ return; -+ } -+ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s jump iden success\n\n", DRVNAME); -+ printk("%s buf_num after jump iden: %d\n", DRVNAME, buf_num); -+ printk("decode status: 0x%x, bit: 0x%x\n", decode_status, bit); -+#endif -+ -+ /* 3) jump "unknown", "C" and "CodeSet" parts in mce keyboard signal */ -+ if (w83667hg_jump_frame(ir, KEY_KEYCODE_FRAME_AFTER_I_START, &buf_num, &bit, &decode_status)) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: decode key jump pulse error\n", DRVNAME); -+#endif -+ return; -+ } -+ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s buf_num after jump pulse: %d\n", DRVNAME, buf_num); -+ printk("decode status: 0x%x, bit: 0x%x\n", decode_status, bit); -+ frame_num = buf_num; -+ for (; frame_num < ir->buf_count; frame_num++) { -+ printk("0x%x\t", ir->buf[frame_num]); -+ if (frame_num % 7 == 6) { -+ printk("\n"); -+ } -+ } -+ printk("\n"); -+#endif -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: decode status before check key: %x\n", DRVNAME, decode_status); -+#endif -+ -+ -+ /* 4) deocde "KeyCode" and "ShiftMask" parts in mce key signal */ -+ frame_num = 1, set_frame = 1; -+ for (; frame_num < KEY_FRAME_AFTER_JUMP + 2; buf_num++) { -+ if (bit != (ir->buf[buf_num] & BIT_PULSE_MASK)) { -+ /* decode*/ -+ if (rlc > PULSE_SILENT_LEN_LOW) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s error: cir signal end before received all key pulses\n", DRVNAME); -+ printk("bit: %d ", bit); -+ printk("rlc: %d\n", rlc); -+ printk("current pulse number: %d\n", frame_num); -+#endif -+ if (decode_status == ST_DECODE_ONE) { -+ /* must set the last one */ -+ w83667hg_set_key(&set_frame, 1, &keycode, &shiftmask); -+ } -+ break; -+ } -+ switch (decode_status) { -+ case ST_DECODE_NEW: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ decode_status = ST_DECODE_ONE; -+ } else { -+ decode_status = ST_DECODE_ZERO; -+ } -+ } else if ((rlc > TWO_PULSE_LEN_LOW) && -+ (rlc < TWO_PULSE_LEN_HIGH)) { -+ /* error occur, just ignore */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_key(&set_frame, 0, &keycode, &shiftmask); -+ frame_num += 1; -+ } -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s cur state: %x\n", DRVNAME, decode_status); -+#endif -+ break; -+ case ST_DECODE_ZERO: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "01" => 0 */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_key(&set_frame, 0, &keycode, &shiftmask); -+ frame_num += 1; -+ } else { -+ /* error */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_key(&set_frame, 0, &keycode, &shiftmask); -+ } -+ } else if ((rlc > TWO_PULSE_LEN_LOW) && -+ (rlc < TWO_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "01" => 0 */ -+ decode_status = ST_DECODE_ONE; -+ w83667hg_set_key(&set_frame, 0, &keycode, &shiftmask); -+ frame_num += 1; -+ } else { -+ /* error */ -+ decode_status = ST_DECODE_ZERO; -+ w83667hg_set_key(&set_frame, 0, &keycode, &shiftmask); -+ } -+ } -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s cur state: %x\n", DRVNAME, decode_status); -+#endif -+ break; -+ case ST_DECODE_ONE: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "11" => error */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_key(&set_frame, 0, &keycode, &shiftmask); -+ } else { -+ /* "10" => 1 */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_key(&set_frame, 1, &keycode, &shiftmask); -+ frame_num += 1; -+ } -+ } else if (rlc > TWO_PULSE_LEN_LOW) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "11" => error */ -+ decode_status = ST_DECODE_ONE; -+ w83667hg_set_key(&set_frame, 0, &keycode, &shiftmask); -+ } else { -+ /* "10" => 1 */ -+ decode_status = ST_DECODE_ZERO; -+ w83667hg_set_key(&set_frame, 1, &keycode, &shiftmask); -+ frame_num += 1; -+ } -+ } -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s cur state %x\n", DRVNAME, decode_status); -+#endif -+ break; -+ } /* switch*/ -+ bit = ir->buf[buf_num] & BIT_PULSE_MASK; -+ rlc = ir->buf[buf_num] & BIT_LEN; -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: decode keyboard buf: 0x%x\n", DRVNAME, ir->buf[buf_num]); -+#endif -+ -+ } else { -+ /* continue last pulse*/ -+ rlc += ir->buf[buf_num] & BIT_LEN; -+ } -+ -+ } /* for*/ -+ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: after decode keyboard:\n", DRVNAME); -+ printk("keycode: 0x%x ", keycode); -+ printk("shiftmask: 0x%x\n\n", shiftmask); -+#endif -+ -+ /* 5) submit keycode to input */ -+ if (keycode != ir->pressed_keycode) { -+ if (ir->pressed_keycode) { -+ input_code = (unsigned int)usb_kbd_keycode[ir->pressed_keycode]; -+ input_report_key(ir->input_dev, input_code, 0); -+ } -+ ir->pressed_keycode = keycode; -+ if (keycode) { -+ input_code = (unsigned int)usb_kbd_keycode[keycode]; -+ input_report_key(ir->input_dev, input_code, 1); -+ } -+ } -+ -+ /* 6) submit shiftmask to input */ -+ -+ if (shiftmask != ir->pressed_shiftmask) { -+ for (i = 0; i < 7; i++) { -+ buf = 1<pressed_shiftmask) && (!(buf & shiftmask))) { -+ input_code = (unsigned int)usb_kbd_keycode[0xE0 + i]; -+ input_report_key(ir->input_dev, input_code, 0); -+ } else if (!(buf & ir->pressed_shiftmask) && (buf & shiftmask)) { -+ input_code = (unsigned int)usb_kbd_keycode[0xE0 + i]; -+ input_report_key(ir->input_dev, input_code, 1); -+ } -+ } /* for*/ -+ ir->pressed_shiftmask = shiftmask; -+ } -+} -+ -+void w83667hg_set_mouse(u8 *set_frame, u8 val, u8 *deltay, u8 *deltax, u8 *clickrl) -+{ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s set mouse val:%d\n", DRVNAME, val); -+#endif -+ if (*set_frame <= MOUSE_SUBMIT_DELTAY_FRAME_NUM + 1) { -+ *deltay <<= 1; -+ *deltay |= val; -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s set mouse delta y:0x%x\n", DRVNAME, *deltay); -+#endif -+ } else if (*set_frame <= MOUSE_SUBMIT_DELTAX_FRAME_NUM) { -+ *deltax <<= 1; -+ *deltax |= val; -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s set mouse delta x:0x%x\n", DRVNAME, *deltax); -+#endif -+ } else if (*set_frame <= MOUSE_SUBMIT_L_FRAME_NUM) { -+ /* move right key, then set left key */ -+ *clickrl <<= 1; -+ *clickrl |= val; -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s set mouse l:0x%x\n", DRVNAME, *clickrl); -+ printk("set pulse: %d\n", *set_frame); -+#endif -+ } -+ (*set_frame)++; -+} -+ -+void w83667hg_submit_mouse(struct irctl *ir) -+{ -+ unsigned int rlc = 0, buf_num = 0; -+ u8 bit; -+ /* deltax, deltay and clickrl parts in mce mouse protocol*/ -+ u8 deltax = 0, deltay = 0, clickrl = 0; -+ signed char x, y; -+ u8 decode_status; -+ u8 frame_num, set_frame; -+ -+ /* 1) jump head */ -+ if (w83667hg_jump_head(ir, &buf_num)) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: decode mouse jump head error\n", DRVNAME); -+#endif -+ return; -+ } -+ -+ /* 2) jump identification */ -+ if (w83667hg_jump_identification(ir, MOUSE_IDENTIFICATION, &buf_num, &bit, &decode_status)) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: decode mouse jump identification error\n", DRVNAME); -+#endif -+ return; -+ } -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: after iden mouse:\n", DRVNAME); -+ printk("decode status: 0x%x, bit: 0x%x\n", decode_status, bit); -+ frame_num = buf_num; -+ for (; frame_num < ir->buf_count; frame_num++) { -+ printk("0x%x ", ir->buf[frame_num]); -+ if (frame_num % 7 == 6) { -+ printk("\n"); -+ } -+ } -+ printk("\n"); -+#endif -+ -+ /* 3) jump "unknown" part in mce mouse signal */ -+ if (w83667hg_jump_frame(ir, MOUSE_DELTAY_PULSE_AFTER_I_START, &buf_num, &bit, &decode_status)) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: decode mouse jump pulse error\n", DRVNAME); -+#endif -+ return; -+ } -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: after jump pulse buf num: %d\n", DRVNAME, buf_num); -+ printk("decode status: 0x%x, bit: 0x%x\n", decode_status, bit); -+ frame_num = buf_num; -+ for (; frame_num < ir->buf_count; frame_num++) { -+ printk("0x%x ", ir->buf[frame_num]); -+ if (frame_num % 7 == 6) { -+ printk("\n"); -+ } -+ } -+ printk("\n"); -+#endif -+ -+ /* 4) deocde "deltay", "deltax", "r" and "l" parts in mce mouse signal */ -+ frame_num = 1, set_frame = 1; -+ for (; frame_num < MOUSE_CHECKSUM_FRAME_AFTER_JUMP + 1; buf_num++) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: cur buf: 0x%x, pulse num: %d\n", DRVNAME, ir->buf[buf_num], frame_num); -+ printk("decode status: 0x%x\n", decode_status); -+#endif -+ if (bit != (ir->buf[buf_num] & BIT_PULSE_MASK)) { -+ /* decode*/ -+ if (rlc > PULSE_SILENT_LEN_LOW) { -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s error: cir signal end before received all mouse pulses\n", DRVNAME); -+ printk("bit: %d ", bit); -+ printk("rlc: %d\n", rlc); -+#endif -+ break; -+ } -+ switch (decode_status) { -+ case ST_DECODE_NEW: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ decode_status = ST_DECODE_ONE; -+ } else { -+ decode_status = ST_DECODE_ZERO; -+ } -+ } else -+ if ((rlc > TWO_PULSE_LEN_LOW) && -+ (rlc < TWO_PULSE_LEN_HIGH)) { -+ /* error occur, just ignore */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_mouse(&set_frame, 0, &deltay, &deltax, &clickrl); -+ frame_num += 1; -+ } -+ break; -+ case ST_DECODE_ZERO: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "01" => 0 */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_mouse(&set_frame, 0, &deltay, &deltax, &clickrl); -+ frame_num += 1; -+ } else { -+ /* error */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_mouse(&set_frame, 0, &deltay, &deltax, &clickrl); -+ } -+ } else if ((rlc > TWO_PULSE_LEN_LOW) && -+ (rlc < TWO_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "01" => 0 */ -+ decode_status = ST_DECODE_ONE; -+ w83667hg_set_mouse(&set_frame, 0, &deltay, &deltax, &clickrl); -+ frame_num += 1; -+ } else { -+ /* error */ -+ decode_status = ST_DECODE_ZERO; -+ w83667hg_set_mouse(&set_frame, 0, &deltay, &deltax, &clickrl); -+ } -+ } -+ break; -+ case ST_DECODE_ONE: -+ if ((rlc > ONE_PULSE_LEN_LOW) && -+ (rlc < ONE_PULSE_LEN_HIGH)) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "11" => error */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_mouse(&set_frame, 0, &deltay, &deltax, &clickrl); -+ } else { -+ /* "10" => 1 */ -+ decode_status = ST_DECODE_NEW; -+ w83667hg_set_mouse(&set_frame, 1, &deltay, &deltax, &clickrl); -+ frame_num += 1; -+ } -+ } else if (rlc > TWO_PULSE_LEN_LOW) { -+ if (bit & BIT_PULSE_MASK) { -+ /* "11" => error */ -+ decode_status = ST_DECODE_ONE; -+ w83667hg_set_mouse(&set_frame, 0, &deltay, &deltax, &clickrl); -+ frame_num += 1; -+ } else { -+ /* "10" => 1 */ -+ decode_status = ST_DECODE_ZERO; -+ w83667hg_set_mouse(&set_frame, 1, &deltay, &deltax, &clickrl); -+ frame_num += 1; -+ } -+ } -+ break; -+ } /* switch*/ -+ bit = ir->buf[buf_num] & BIT_PULSE_MASK; -+ rlc = ir->buf[buf_num] & BIT_LEN; -+ } else { -+ /* continue last pulse*/ -+ rlc += ir->buf[buf_num] & BIT_LEN; -+ } -+ -+ } /* for*/ -+ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: after decode mouse:\n", DRVNAME); -+ frame_num = buf_num; -+ for (; frame_num < ir->buf_count; frame_num++) { -+ printk("0x%x ", ir->buf[frame_num]); -+ if (frame_num % 7 == 6) { -+ printk("\n"); -+ } -+ } -+ printk("\n"); -+#endif -+ -+ /* fix deltax lost problem */ -+ if (deltax) { -+ deltax <<= 1; -+ deltax |= 1; -+ } -+ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: after decode mouse:\n", DRVNAME); -+ printk("deltay: 0x%x ", deltay); -+ printk("deltax: 0x%x ", deltax); -+ printk("click rl: 0x%x \n\n", clickrl); -+#endif -+ if (deltay & 0x40) { -+ y = -((~deltay & 0x7f) + 1); -+ } else { -+ y = deltay; -+ } -+ if (deltax & 0x40) { -+ x = -((~deltax & 0x7f) + 1); -+ } else { -+ x = deltax; -+ } -+ -+ /* 5) send to input */ -+ -+#ifdef ALLOW_DEBUG_DECODE -+ printk("%s: after decode mouse and rebuild:\n", DRVNAME); -+ printk("y: %d ", y); -+ printk("x: %d ", x); -+ printk("click rl: 0x%x \n\n", clickrl); -+#endif -+ -+ input_report_rel(ir->input_dev, REL_X, x); -+ input_report_rel(ir->input_dev, REL_Y, y); -+ -+ input_report_key(ir->input_dev, BTN_LEFT, clickrl & 1); -+ input_report_key(ir->input_dev, BTN_RIGHT, (clickrl >> 1) & 1); -+} -+ -+ -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_wb677_mouse_kbd.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677_mouse_kbd.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_wb677_mouse_kbd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_wb677_mouse_kbd.h 2010-04-03 18:42:04.216701266 +0200 -@@ -0,0 +1,190 @@ -+#ifndef __LIRC_WB677_MOUSE_KBD_HEADER__ -+#define __LIRC_WB677_MOUSE_KBD_HEADER__ -+ -+ -+ -+ -+/* jump asked frame number, can use on key, mouse and controller signals -+ * -+ * after jump frame_num, current frame number = frame_num + 1 -+ * record current buf number of irctl buf -+ * record current pulse's bit and decode_status -+ * -+ * problem 1: -+ * When jump_frame() stops on a two_width_len pulse, the buf_num will be the -+ * second pulse of the double_width_len pulse. -+ * So jump_frame() must increase buf_num 1 on problem 1. -+ * For sample period is 50us, a 444us piulse's minimal sample value is 7, and -+ * two piulses' minimal sample value is 15. So just increase buf_num 1 works -+ * fine. If sample period changes, this solution also need change. -+ * -+ * one_width_len pulse: -+ * _ _ -+ * .| |_| |_. (1010) -+ * ^ -+ * | -+ * stop: jumped frame_num -+ * -+ * -+ * problem 1: double_width_len pulse: -+ * __ _ -+ * .| |__| |. (11001) -+ * ^ -+ * | -+ * stop: jumped frame_num + 1, buf_num + 1 -+ * -+ * so if cur buf len > TWO_PULSE_LEN_LOW, buf_num -- -+ * and recheck polar bit and decode_status -+ * decode_status go back 1 buf, -+ * NEW -> ONE/ZERO; ONE/ZERO -> NEW -+ * -+ * jump out of buf limit, return < 0 -+ */ -+int w83667hg_jump_frame(struct irctl *ir, u8 frame_num, unsigned int *buf_num, u8 *out_bit, u8 *decode_status); -+ -+/* jump MCE head sync signal (1111 11) -+ * -+ * after jump signal head, current pulse number = 7 -+ * record current buf number of irctl buf -+ * record current pulse's bit and decode_status -+ * -+ * jump out of buf limit, return < 0 -+ */ -+int w83667hg_jump_head(struct irctl *ir, unsigned int *buf_num); -+ -+#define KEY_IDENTIFICATION 0x04 -+#define MOUSE_IDENTIFICATION 0x01 -+#define IDENTIFICATION_CHECK_BIT 0xF -+ -+/* check mce identification -+ * -+ * compare identification and cur_iden -+ * same return 0 -+ * else return < 0, need continue check -+ */ -+int w83667hg_check_identification(u8 val, u8 identification, u8 *cur_iden); -+ -+/* jump mce identification -+ * can use on key, mouse and controller signals -+ * -+ * jump and search identification parts -+ * record current buf number of irctl buf -+ * -+ * jump all pulse until find identification -+ * -+ * -+ * -+ * problem 1: -+ * When jump_identification() stops on a double_width_len pulse, the buf_num will be the -+ * second pulse of the doule_width_len frame. -+ * -+ * one_width_len pulse: -+ * _ _ -+ * .| |_| |_. (1010) -+ * ^ -+ * | -+ * stop: jumped frame_num -+ * -+ * -+ * problem 1: double_width_len pulse: -+ * __ _ -+ * .| |__| |. (11001) -+ * ^ -+ * | -+ * stop: jumped frame_num + 1, buf_num + 2 -+ * -+ * solution: -+ * Now buf_num is the next double-pulse-width buf. -+ * Just decrease buf_num by one can fix this problem. -+ * -+ * -+ * After jump iden, output may diff by decode status: -+ * 1) -+ * For status ONE and ZERO, all decode work is done. -+ * Set status as NEW and inverse out_bit -+ * in fact, bit is not important, for a buf can indicate one frame, whether its -+ * length is one or two, the bit can be ignored -+ * -+ * after jump frame, all status is NEW! reset them as inverse polar bit -+ * -+ * -+ * -+ * -+ * can not find identification, return < 0 -+ */ -+int w83667hg_jump_identification(struct irctl *ir, u8 identification, unsigned int *buf_num, u8 *out_bit, u8 *decode_status); -+ -+ -+/* the frame number between identification and code */ -+#define KEY_KEYCODE_FRAME_AFTER_I_START 16 /*//32*/ -+#define KEY_FRAME_AFTER_JUMP 16 /*//64*/ -+#define KEY_SUBMIT_KEYCODE_FRAME_NUM 8 -+ -+ -+#define MOUSE_DELTAY_PULSE_AFTER_I_START 8 -+#define MOUSE_CHECKSUM_FRAME_AFTER_JUMP 16 -+#define MOUSE_SUBMIT_DELTAY_FRAME_NUM 7 -+#define MOUSE_SUBMIT_DELTAX_FRAME_NUM 14 -+#define MOUSE_SUBMIT_R_FRAME_NUM 15 -+#define MOUSE_SUBMIT_L_FRAME_NUM 16 -+ -+ -+/* FIXME, not sure this value, select a large number*/ -+#define PULSE_SILENT_LEN_LOW 90 -+ -+ -+/* set keycode and shiftmask for keyboard */ -+void w83667hg_set_key(u8 *set_frame, u8 val, u8 *keycode, u8 *shiftmask); -+ -+/* decode mce keyboard signal and send data to input -+ * -+ * 1) jump mce keyboard signal sync head (1111 11) -+ * 2) jump identification (0100) -+ * pulse number before identification is not sure -+ * 3) jump "unknown", "C" and "CodeSet" parts in mce keyboard signal -+ * 4) deocde "KeyCode" and "ShiftMask" parts in mce key signal -+ * 5) send keycode to input by array usb_kbd_keycode -+ * 6) send shiftmask to input by array usb_kbd_keycode -+ */ -+void w83667hg_submit_key(struct irctl *ir); -+ -+/* set deltax, deltay, x, y for mce mouse */ -+void w83667hg_set_mouse(u8 *set_frame, u8 val, u8 *deltay, u8 *deltax, u8 *clickrl); -+ -+/* decode mce mouse signal and send data to input -+ * -+ * 1) jump mce mouse signal sync head (1111 11) -+ * 2) jump identification (0001) -+ * pulse number before identification is not sure -+ * 3) jump "unknown" part in mce mouse signal -+ * 4) deocde "deltay", "deltax", "r" and "l" parts in mce mouse signal -+ * 5) send these parts to input -+ */ -+void w83667hg_submit_mouse(struct irctl *ir); -+ -+ -+ -+#define BIT_PULSE_MASK 0x80 -+#define BIT_LEN 0x7f -+ -+ -+ -+/* "10"=>1 (+2), "01"=>0 (+2) */ -+#define ST_DECODE_NEW 0x01 -+#define ST_DECODE_ZERO 0x02 -+#define ST_DECODE_ONE 0x04 -+ -+/* RC6 sync head: 1111 11 -+ * 6 * 444us / 50us (sample period) * 0.85 (inaccuracy) -+ */ -+#define HEAD_SYNC_LEN_LOW 45 -+/* 7 pulses long, for inaccuracy */ -+#define HEAD_SYNC_LEN_HIGH 71 -+ -+#define ONE_PULSE_LEN_LOW 2 -+#define ONE_PULSE_LEN_HIGH 10 -+#define TWO_PULSE_LEN_LOW 10 -+#define TWO_PULSE_LEN_HIGH 15 -+ -+ -+#endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/Makefile linux-2.6.33.2.patch/drivers/input/lirc/Makefile ---- linux-2.6.33.2/drivers/input/lirc/Makefile 2010-04-03 18:40:52.422576074 +0200 -+++ linux-2.6.33.2.patch/drivers/input/lirc/Makefile 2010-04-03 18:42:04.217701457 +0200 -@@ -1,6 +1,9 @@ - # Makefile for the lirc drivers. - # - -+# Multipart objects. -+lirc_wb677-objs := lirc_wb677_main.o lirc_wb677_mouse_kbd.o -+ - # Each configuration option enables a list of files. - - obj-$(CONFIG_INPUT_LIRC) += lirc_dev.o -@@ -12,6 +15,7 @@ - obj-$(CONFIG_LIRC_IT87) += lirc_it87.o - obj-$(CONFIG_LIRC_ITE8709) += lirc_ite8709.o - obj-$(CONFIG_LIRC_MCEUSB) += lirc_mceusb.o -+obj-$(CONFIG_LIRC_NCT667X) += lirc_wb677.o - obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o - obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o - obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o -diff -Naur linux-2.6.33.2/drivers/input/lirc/wb83677hg_ir.h linux-2.6.33.2.patch/drivers/input/lirc/wb83677hg_ir.h ---- linux-2.6.33.2/drivers/input/lirc/wb83677hg_ir.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/wb83677hg_ir.h 2010-04-03 18:42:04.218701439 +0200 -@@ -0,0 +1,44 @@ -+#define IR_IOC_MAGIC 'i' -+ -+/* output chip registers for debug */ -+#define IR_DUMPCIRREG _IO(IR_IOC_MAGIC, 0x80) -+#define IR_DUMPWAKEREG _IO(IR_IOC_MAGIC, 0x81) -+ -+ -+/* study wake key on MCE CIR controller */ -+#define IR_IOLEARNWAKE _IO(IR_IOC_MAGIC, 0x82) -+ -+/* disable cir wake */ -+#define IR_IOUNSETWAKE _IO(IR_IOC_MAGIC, 0x83) -+ -+/* enable cir wake */ -+#define IR_IOSETWAKE _IO(IR_IOC_MAGIC, 0x84) -+ -+ -+/* get carrier for study ir signal */ -+#define IR_IOGETCARRIER _IOR(IR_IOC_MAGIC, 0x85, unsigned int) -+ -+/* set carrier for send ir signal */ -+#define IR_IOSETCARRIER _IOW(IR_IOC_MAGIC, 0x86, unsigned int) -+ -+/* start/stop study key */ -+#define IR_IOSTARTSTUDY _IO(IR_IOC_MAGIC, 0x88) -+#define IR_IOSTOPSTUDY _IO(IR_IOC_MAGIC, 0x89) -+ -+/* study key buf len */ -+#define IR_IOSTUDYLEN _IOR(IR_IOC_MAGIC, 0x8A, unsigned int) -+ -+/* study key buf data */ -+#define IR_IOSTUDYBUF _IOR(IR_IOC_MAGIC, 0x8B, unsigned char) -+ -+/* restudy key buf data */ -+#define IR_IORESTUDYBUF _IO(IR_IOC_MAGIC, 0x8C) -+ -+ -+/* clean data */ -+#define IR_IOCLEANDATA _IO(IR_IOC_MAGIC, 0x8E) -+ -+ -+/* check chip identification for the applications which are related to hardware */ -+#define IR_CHECKCHIP _IOR(IR_IOC_MAGIC, 0x8F, unsigned long long) -+ diff --git a/packages/linux/patches/021-linux-2.6.34-squashfs_lzma.diff b/packages/linux/patches/021-linux-2.6.35-squashfs_lzma.diff similarity index 77% rename from packages/linux/patches/021-linux-2.6.34-squashfs_lzma.diff rename to packages/linux/patches/021-linux-2.6.35-squashfs_lzma.diff index fff5e57323..7e7d7835f6 100644 --- a/packages/linux/patches/021-linux-2.6.34-squashfs_lzma.diff +++ b/packages/linux/patches/021-linux-2.6.35-squashfs_lzma.diff @@ -1,6 +1,6 @@ -diff -Naur linux-2.6.34-old/fs/squashfs/decompressor.c linux-2.6.34-new/fs/squashfs/decompressor.c ---- linux-2.6.34-old/fs/squashfs/decompressor.c 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/fs/squashfs/decompressor.c 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/fs/squashfs/decompressor.c linux-2.6.35-rc6.patch/fs/squashfs/decompressor.c +--- linux-2.6.35-rc6/fs/squashfs/decompressor.c 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/fs/squashfs/decompressor.c 2010-07-29 06:51:11.797408264 +0200 @@ -50,7 +50,11 @@ static const struct squashfs_decompressor *decompressor[] = { @@ -13,10 +13,10 @@ diff -Naur linux-2.6.34-old/fs/squashfs/decompressor.c linux-2.6.34-new/fs/squas &squashfs_lzo_unsupported_comp_ops, &squashfs_unknown_comp_ops }; -diff -Naur linux-2.6.34-old/fs/squashfs/Kconfig linux-2.6.34-new/fs/squashfs/Kconfig ---- linux-2.6.34-old/fs/squashfs/Kconfig 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/fs/squashfs/Kconfig 2010-05-17 13:11:22.000000000 -0700 -@@ -26,6 +26,12 @@ +diff -Naur linux-2.6.35-rc6/fs/squashfs/Kconfig linux-2.6.35-rc6.patch/fs/squashfs/Kconfig +--- linux-2.6.35-rc6/fs/squashfs/Kconfig 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/fs/squashfs/Kconfig 2010-07-29 06:51:11.798406430 +0200 +@@ -37,6 +37,12 @@ If unsure, say N. @@ -29,9 +29,9 @@ diff -Naur linux-2.6.34-old/fs/squashfs/Kconfig linux-2.6.34-new/fs/squashfs/Kco config SQUASHFS_EMBEDDED bool "Additional option for memory-constrained systems" -diff -Naur linux-2.6.34-old/fs/squashfs/lzma_wrapper.c linux-2.6.34-new/fs/squashfs/lzma_wrapper.c ---- linux-2.6.34-old/fs/squashfs/lzma_wrapper.c 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.6.34-new/fs/squashfs/lzma_wrapper.c 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/fs/squashfs/lzma_wrapper.c linux-2.6.35-rc6.patch/fs/squashfs/lzma_wrapper.c +--- linux-2.6.35-rc6/fs/squashfs/lzma_wrapper.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/fs/squashfs/lzma_wrapper.c 2010-07-29 06:51:12.257251312 +0200 @@ -0,0 +1,152 @@ +/* + * Squashfs - a compressed read only filesystem for Linux @@ -185,27 +185,29 @@ diff -Naur linux-2.6.34-old/fs/squashfs/lzma_wrapper.c linux-2.6.34-new/fs/squas + .supported = 1 +}; + -diff -Naur linux-2.6.34-old/fs/squashfs/Makefile linux-2.6.34-new/fs/squashfs/Makefile ---- linux-2.6.34-old/fs/squashfs/Makefile 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/fs/squashfs/Makefile 2010-05-17 13:11:22.000000000 -0700 -@@ -5,3 +5,4 @@ +diff -Naur linux-2.6.35-rc6/fs/squashfs/Makefile linux-2.6.35-rc6.patch/fs/squashfs/Makefile +--- linux-2.6.35-rc6/fs/squashfs/Makefile 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/fs/squashfs/Makefile 2010-07-29 06:52:22.842250915 +0200 +@@ -5,5 +5,6 @@ obj-$(CONFIG_SQUASHFS) += squashfs.o squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o +squashfs-$(CONFIG_SQUASHFS_LZMA) += lzma_wrapper.o -diff -Naur linux-2.6.34-old/fs/squashfs/squashfs.h linux-2.6.34-new/fs/squashfs/squashfs.h ---- linux-2.6.34-old/fs/squashfs/squashfs.h 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/fs/squashfs/squashfs.h 2010-05-17 13:11:22.000000000 -0700 -@@ -94,3 +94,6 @@ + squashfs-$(CONFIG_SQUASHFS_XATTRS) += xattr.o xattr_id.o + +diff -Naur linux-2.6.35-rc6/fs/squashfs/squashfs.h linux-2.6.35-rc6.patch/fs/squashfs/squashfs.h +--- linux-2.6.35-rc6/fs/squashfs/squashfs.h 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/fs/squashfs/squashfs.h 2010-07-29 06:51:12.273377004 +0200 +@@ -104,3 +104,6 @@ /* zlib_wrapper.c */ extern const struct squashfs_decompressor squashfs_zlib_comp_ops; + +/* lzma wrapper.c */ +extern const struct squashfs_decompressor squashfs_lzma_comp_ops; -diff -Naur linux-2.6.34-old/include/linux/decompress/bunzip2_mm.h linux-2.6.34-new/include/linux/decompress/bunzip2_mm.h ---- linux-2.6.34-old/include/linux/decompress/bunzip2_mm.h 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.6.34-new/include/linux/decompress/bunzip2_mm.h 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/include/linux/decompress/bunzip2_mm.h linux-2.6.35-rc6.patch/include/linux/decompress/bunzip2_mm.h +--- linux-2.6.35-rc6/include/linux/decompress/bunzip2_mm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/include/linux/decompress/bunzip2_mm.h 2010-07-29 06:51:12.274376635 +0200 @@ -0,0 +1,13 @@ +#ifndef BUNZIP2_MM_H +#define BUNZIP2_MM_H @@ -220,9 +222,9 @@ diff -Naur linux-2.6.34-old/include/linux/decompress/bunzip2_mm.h linux-2.6.34-n +#endif + +#endif -diff -Naur linux-2.6.34-old/include/linux/decompress/inflate_mm.h linux-2.6.34-new/include/linux/decompress/inflate_mm.h ---- linux-2.6.34-old/include/linux/decompress/inflate_mm.h 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.6.34-new/include/linux/decompress/inflate_mm.h 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/include/linux/decompress/inflate_mm.h linux-2.6.35-rc6.patch/include/linux/decompress/inflate_mm.h +--- linux-2.6.35-rc6/include/linux/decompress/inflate_mm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/include/linux/decompress/inflate_mm.h 2010-07-29 06:51:12.275376896 +0200 @@ -0,0 +1,13 @@ +#ifndef INFLATE_MM_H +#define INFLATE_MM_H @@ -237,9 +239,9 @@ diff -Naur linux-2.6.34-old/include/linux/decompress/inflate_mm.h linux-2.6.34-n +#endif + +#endif -diff -Naur linux-2.6.34-old/include/linux/decompress/mm.h linux-2.6.34-new/include/linux/decompress/mm.h ---- linux-2.6.34-old/include/linux/decompress/mm.h 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/include/linux/decompress/mm.h 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/include/linux/decompress/mm.h linux-2.6.35-rc6.patch/include/linux/decompress/mm.h +--- linux-2.6.35-rc6/include/linux/decompress/mm.h 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/include/linux/decompress/mm.h 2010-07-29 06:51:12.276375899 +0200 @@ -63,8 +63,6 @@ #define set_error_fn(x) @@ -260,9 +262,9 @@ diff -Naur linux-2.6.34-old/include/linux/decompress/mm.h linux-2.6.34-new/inclu #define STATIC #include -diff -Naur linux-2.6.34-old/include/linux/decompress/unlzma_mm.h linux-2.6.34-new/include/linux/decompress/unlzma_mm.h ---- linux-2.6.34-old/include/linux/decompress/unlzma_mm.h 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.6.34-new/include/linux/decompress/unlzma_mm.h 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/include/linux/decompress/unlzma_mm.h linux-2.6.35-rc6.patch/include/linux/decompress/unlzma_mm.h +--- linux-2.6.35-rc6/include/linux/decompress/unlzma_mm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/include/linux/decompress/unlzma_mm.h 2010-07-29 06:51:12.277376579 +0200 @@ -0,0 +1,20 @@ +#ifndef UNLZMA_MM_H +#define UNLZMA_MM_H @@ -284,9 +286,9 @@ diff -Naur linux-2.6.34-old/include/linux/decompress/unlzma_mm.h linux-2.6.34-ne +#endif + +#endif -diff -Naur linux-2.6.34-old/include/linux/decompress/unlzo_mm.h linux-2.6.34-new/include/linux/decompress/unlzo_mm.h ---- linux-2.6.34-old/include/linux/decompress/unlzo_mm.h 1969-12-31 16:00:00.000000000 -0800 -+++ linux-2.6.34-new/include/linux/decompress/unlzo_mm.h 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/include/linux/decompress/unlzo_mm.h linux-2.6.35-rc6.patch/include/linux/decompress/unlzo_mm.h +--- linux-2.6.35-rc6/include/linux/decompress/unlzo_mm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.35-rc6.patch/include/linux/decompress/unlzo_mm.h 2010-07-29 06:51:12.278376490 +0200 @@ -0,0 +1,13 @@ +#ifndef UNLZO_MM_H +#define UNLZO_MM_H @@ -301,9 +303,9 @@ diff -Naur linux-2.6.34-old/include/linux/decompress/unlzo_mm.h linux-2.6.34-new +#endif + +#endif -diff -Naur linux-2.6.34-old/lib/decompress_bunzip2.c linux-2.6.34-new/lib/decompress_bunzip2.c ---- linux-2.6.34-old/lib/decompress_bunzip2.c 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/lib/decompress_bunzip2.c 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/lib/decompress_bunzip2.c linux-2.6.35-rc6.patch/lib/decompress_bunzip2.c +--- linux-2.6.35-rc6/lib/decompress_bunzip2.c 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/lib/decompress_bunzip2.c 2010-07-29 06:51:12.315251128 +0200 @@ -52,6 +52,7 @@ #include #endif /* STATIC */ @@ -312,9 +314,9 @@ diff -Naur linux-2.6.34-old/lib/decompress_bunzip2.c linux-2.6.34-new/lib/decomp #include #ifndef INT_MAX -diff -Naur linux-2.6.34-old/lib/decompress_inflate.c linux-2.6.34-new/lib/decompress_inflate.c ---- linux-2.6.34-old/lib/decompress_inflate.c 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/lib/decompress_inflate.c 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/lib/decompress_inflate.c linux-2.6.35-rc6.patch/lib/decompress_inflate.c +--- linux-2.6.35-rc6/lib/decompress_inflate.c 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/lib/decompress_inflate.c 2010-07-29 06:51:12.321251434 +0200 @@ -23,6 +23,7 @@ #endif /* STATIC */ @@ -323,9 +325,9 @@ diff -Naur linux-2.6.34-old/lib/decompress_inflate.c linux-2.6.34-new/lib/decomp #include #define GZIP_IOBUF_SIZE (16*1024) -diff -Naur linux-2.6.34-old/lib/decompress_unlzma.c linux-2.6.34-new/lib/decompress_unlzma.c ---- linux-2.6.34-old/lib/decompress_unlzma.c 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/lib/decompress_unlzma.c 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/lib/decompress_unlzma.c linux-2.6.35-rc6.patch/lib/decompress_unlzma.c +--- linux-2.6.35-rc6/lib/decompress_unlzma.c 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/lib/decompress_unlzma.c 2010-07-29 06:51:12.334286250 +0200 @@ -36,6 +36,7 @@ #include #endif /* STATIC */ @@ -640,9 +642,9 @@ diff -Naur linux-2.6.34-old/lib/decompress_unlzma.c linux-2.6.34-new/lib/decompr #ifdef PREBOOT STATIC int INIT decompress(unsigned char *buf, int in_len, -diff -Naur linux-2.6.34-old/lib/decompress_unlzo.c linux-2.6.34-new/lib/decompress_unlzo.c ---- linux-2.6.34-old/lib/decompress_unlzo.c 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/lib/decompress_unlzo.c 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/lib/decompress_unlzo.c linux-2.6.35-rc6.patch/lib/decompress_unlzo.c +--- linux-2.6.35-rc6/lib/decompress_unlzo.c 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/lib/decompress_unlzo.c 2010-07-29 06:51:12.340249191 +0200 @@ -39,6 +39,7 @@ #include @@ -651,9 +653,9 @@ diff -Naur linux-2.6.34-old/lib/decompress_unlzo.c linux-2.6.34-new/lib/decompre #include #include -diff -Naur linux-2.6.34-old/lib/Kconfig linux-2.6.34-new/lib/Kconfig ---- linux-2.6.34-old/lib/Kconfig 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/lib/Kconfig 2010-05-17 13:11:22.000000000 -0700 +diff -Naur linux-2.6.35-rc6/lib/Kconfig linux-2.6.35-rc6.patch/lib/Kconfig +--- linux-2.6.35-rc6/lib/Kconfig 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/lib/Kconfig 2010-07-29 06:51:12.340249191 +0200 @@ -121,6 +121,9 @@ select LZO_DECOMPRESS tristate @@ -664,10 +666,10 @@ diff -Naur linux-2.6.34-old/lib/Kconfig linux-2.6.34-new/lib/Kconfig # # Generic allocator support is selected if needed # -diff -Naur linux-2.6.34-old/lib/Makefile linux-2.6.34-new/lib/Makefile ---- linux-2.6.34-old/lib/Makefile 2010-05-16 14:17:36.000000000 -0700 -+++ linux-2.6.34-new/lib/Makefile 2010-05-17 13:11:22.000000000 -0700 -@@ -69,7 +69,7 @@ +diff -Naur linux-2.6.35-rc6/lib/Makefile linux-2.6.35-rc6.patch/lib/Makefile +--- linux-2.6.35-rc6/lib/Makefile 2010-07-22 21:13:38.000000000 +0200 ++++ linux-2.6.35-rc6.patch/lib/Makefile 2010-07-29 06:51:12.341249940 +0200 +@@ -72,7 +72,7 @@ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o @@ -676,3 +678,4 @@ diff -Naur linux-2.6.34-old/lib/Makefile linux-2.6.34-new/lib/Makefile lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o obj-$(CONFIG_TEXTSEARCH) += textsearch.o +diff -Naur linux-2.6.35-rc6/lib/Makefile.orig linux-2.6.35-rc6.patch/lib/Makefile.orig diff --git a/packages/linux/patches/036-linux-2.6-cantiga-iommu-gfx.diff b/packages/linux/patches/036-linux-2.6-cantiga-iommu-gfx.diff deleted file mode 100644 index a18e38ba9e..0000000000 --- a/packages/linux/patches/036-linux-2.6-cantiga-iommu-gfx.diff +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c -index 4173125..baa32a0 100644 ---- a/drivers/pci/intel-iommu.c -+++ b/drivers/pci/intel-iommu.c -@@ -340,7 +340,7 @@ int dmar_disabled = 0; - int dmar_disabled = 1; - #endif /*CONFIG_DMAR_DEFAULT_ON*/ - --static int __initdata dmar_map_gfx = 1; -+static int dmar_map_gfx = 1; - static int dmar_forcedac; - static int intel_iommu_strict; - -@@ -3728,6 +3728,12 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) - */ - printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n"); - rwbf_quirk = 1; -+ -+ /* https://bugzilla.redhat.com/show_bug.cgi?id=538163 */ -+ if (dev->revision == 0x07) { -+ printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n"); -+ dmar_map_gfx = 0; -+ } - } - - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf); diff --git a/packages/linux/patches/linux-2.6-v4l-dvb-ir-core-update.diff b/packages/linux/patches/linux-2.6-v4l-dvb-ir-core-update.diff new file mode 100644 index 0000000000..c1105a3306 --- /dev/null +++ b/packages/linux/patches/linux-2.6-v4l-dvb-ir-core-update.diff @@ -0,0 +1,6741 @@ +Patch generated from the linuxtv staging/other branch, with a few +additional pending fixes merged in, and just about everything not +essential to the ir-core update chopped out. + +(Patch generated 2010.07.16) + +Signed-off-by: Jarod Wilson + +--- + Documentation/DocBook/media-entities.tmpl | 1 + Documentation/DocBook/media.tmpl | 8 + Documentation/DocBook/v4l/lirc_device_interface.xml | 235 ++++ + Documentation/DocBook/v4l/remote_controllers.xml | 2 + Documentation/dvb/get_dvb_firmware | 19 + Documentation/video4linux/CARDLIST.cx23885 | 6 + drivers/input/evdev.c | 39 + drivers/input/input.c | 268 ++++ + drivers/media/IR/Kconfig | 34 + drivers/media/IR/Makefile | 3 + drivers/media/IR/imon.c | 5 + drivers/media/IR/ir-core-priv.h | 54 + drivers/media/IR/ir-jvc-decoder.c | 152 -- + drivers/media/IR/ir-lirc-codec.c | 283 ++++ + drivers/media/IR/ir-nec-decoder.c | 151 -- + drivers/media/IR/ir-raw-event.c | 167 +- + drivers/media/IR/ir-rc5-decoder.c | 167 -- + drivers/media/IR/ir-rc6-decoder.c | 153 -- + drivers/media/IR/ir-sony-decoder.c | 155 -- + drivers/media/IR/ir-sysfs.c | 261 ++-- + drivers/media/IR/keymaps/Makefile | 2 + drivers/media/IR/keymaps/rc-lirc.c | 41 + drivers/media/IR/keymaps/rc-rc6-mce.c | 105 + + drivers/media/IR/lirc_dev.c | 764 +++++++++++++ + drivers/media/IR/mceusb.c | 1143 ++++++++++++++++++++ + drivers/media/common/tuners/tda18271-fe.c | 8 + drivers/media/dvb/mantis/Kconfig | 14 + drivers/media/dvb/mantis/mantis_input.c | 5 + drivers/media/video/cx23885/cx23885-cards.c | 40 + drivers/media/video/cx23885/cx23885-core.c | 11 + drivers/media/video/cx23885/cx23885-dvb.c | 2 + drivers/media/video/cx23885/cx23885-input.c | 317 +---- + drivers/media/video/cx23885/cx23885-ir.c | 2 + drivers/media/video/cx23885/cx23885.h | 12 + drivers/media/video/cx88/cx88-cards.c | 9 + drivers/media/video/cx88/cx88-i2c.c | 6 + drivers/media/video/cx88/cx88-input.c | 46 + drivers/media/video/cx88/cx88.h | 1 + drivers/media/video/em28xx/em28xx-input.c | 80 - + drivers/media/video/em28xx/em28xx-video.c | 4 + drivers/media/video/em28xx/em28xx.h | 1 + drivers/media/video/hdpvr/hdpvr-core.c | 5 + drivers/media/video/ir-kbd-i2c.c | 14 + drivers/media/video/pvrusb2/pvrusb2-ioread.c | 5 + include/linux/input.h | 39 + include/media/ir-core.h | 8 + include/media/ir-kbd-i2c.h | 2 + include/media/lirc.h | 165 ++ + include/media/lirc_dev.h | 225 +++ + include/media/rc-map.h | 7 + 50 files changed, 3971 insertions(+), 1275 deletions(-) + +diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl +index 5d4d40f..6ae9715 100644 +--- a/Documentation/DocBook/media-entities.tmpl ++++ b/Documentation/DocBook/media-entities.tmpl +@@ -218,6 +218,7 @@ + + + ++ + + + +diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl +index eea564b..f11048d 100644 +--- a/Documentation/DocBook/media.tmpl ++++ b/Documentation/DocBook/media.tmpl +@@ -28,7 +28,7 @@ + LINUX MEDIA INFRASTRUCTURE API + + +- 2009 ++ 2009-2010 + LinuxTV Developers + + +@@ -61,7 +61,7 @@ Foundation. A copy of the license is included in the chapter entitled + in fact it covers several different video standards including + DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated + to documment support also for DVB-S2, ISDB-T and ISDB-S. +- The third part covers other API's used by all media infrastructure devices ++ The third part covers Remote Controller API + For additional information and for the latest development code, + see: http://linuxtv.org. + For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: Linux Media Mailing List (LMML).. +@@ -86,7 +86,7 @@ Foundation. A copy of the license is included in the chapter entitled + + + +- 2009 ++ 2009-2010 + Mauro Carvalho Chehab + + +@@ -101,7 +101,7 @@ Foundation. A copy of the license is included in the chapter entitled + + + +-Other API's used by media infrastructure drivers ++Remote Controller API + + &sub-remote_controllers; + +diff --git a/Documentation/DocBook/v4l/lirc_device_interface.xml b/Documentation/DocBook/v4l/lirc_device_interface.xml +new file mode 100644 +index 0000000..0413234 +--- /dev/null ++++ b/Documentation/DocBook/v4l/lirc_device_interface.xml +@@ -0,0 +1,235 @@ ++
++LIRC Device Interface ++ ++ ++
++Introduction ++ ++The LIRC device interface is a bi-directional interface for ++transporting raw IR data between userspace and kernelspace. Fundamentally, ++it is just a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number ++of standard struct file_operations defined on it. With respect to ++transporting raw IR data to and fro, the essential fops are read, write ++and ioctl. ++ ++Example dmesg output upon a driver registering w/LIRC: ++
++ $ dmesg |grep lirc_dev ++ lirc_dev: IR Remote Control driver registered, major 248 ++ rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0 ++
++ ++What you should see for a chardev: ++
++ $ ls -l /dev/lirc* ++ crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0 ++
++
++ ++
++LIRC read fop ++ ++The lircd userspace daemon reads raw IR data from the LIRC chardev. The ++exact format of the data depends on what modes a driver supports, and what ++mode has been selected. lircd obtains supported modes and sets the active mode ++via the ioctl interface, detailed at . The generally ++preferred mode is LIRC_MODE_MODE2, in which packets containing an int value ++describing an IR signal are read from the chardev. ++ ++See also http://www.lirc.org/html/technical.html for more info. ++
++ ++
++LIRC write fop ++ ++The data written to the chardev is a pulse/space sequence of integer ++values. Pulses and spaces are only marked implicitly by their position. The ++data must start and end with a pulse, therefore, the data must always include ++an unevent number of samples. The write function must block until the data has ++been transmitted by the hardware. ++
++ ++
++LIRC ioctl fop ++ ++The LIRC device's ioctl definition is bound by the ioctl function ++definition of struct file_operations, leaving us with an unsigned int ++for the ioctl command and an unsigned long for the arg. For the purposes ++of ioctl portability across 32-bit and 64-bit, these values are capped ++to their 32-bit sizes. ++ ++The following ioctls can be used to change specific hardware settings. ++In general each driver should have a default set of settings. The driver ++implementation is expected to re-apply the default settings when the device ++is closed by user-space, so that every application opening the device can rely ++on working with the default settings initially. ++ ++ ++ ++ LIRC_GET_FEATURES ++ ++ Obviously, get the underlying hardware device's features. If a driver ++ does not announce support of certain features, calling of the corresponding ++ ioctls is undefined. ++ ++ ++ ++ LIRC_GET_SEND_MODE ++ ++ Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd. ++ ++ ++ ++ LIRC_GET_REC_MODE ++ ++ Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE ++ are supported by lircd. ++ ++ ++ ++ LIRC_GET_SEND_CARRIER ++ ++ Get carrier frequency (in Hz) currently used for transmit. ++ ++ ++ ++ LIRC_GET_REC_CARRIER ++ ++ Get carrier frequency (in Hz) currently used for IR reception. ++ ++ ++ ++ LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE ++ ++ Get/set the duty cycle (from 0 to 100) of the carrier signal. Currently, ++ no special meaning is defined for 0 or 100, but this could be used to switch ++ off carrier generation in the future, so these values should be reserved. ++ ++ ++ ++ LIRC_GET_REC_RESOLUTION ++ ++ Some receiver have maximum resolution which is defined by internal ++ sample rate or data format limitations. E.g. it's common that signals can ++ only be reported in 50 microsecond steps. This integer value is used by ++ lircd to automatically adjust the aeps tolerance value in the lircd ++ config file. ++ ++ ++ ++ LIRC_GET_M{IN,AX}_TIMEOUT ++ ++ Some devices have internal timers that can be used to detect when ++ there's no IR activity for a long time. This can help lircd in detecting ++ that a IR signal is finished and can speed up the decoding process. ++ Returns an integer value with the minimum/maximum timeout that can be ++ set. Some devices have a fixed timeout, in that case both ioctls will ++ return the same value even though the timeout cannot be changed. ++ ++ ++ ++ LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE} ++ ++ Some devices are able to filter out spikes in the incoming signal ++ using given filter rules. These ioctls return the hardware capabilities ++ that describe the bounds of the possible filters. Filter settings depend ++ on the IR protocols that are expected. lircd derives the settings from ++ all protocols definitions found in its config file. ++ ++ ++ ++ LIRC_GET_LENGTH ++ ++ Retrieves the code length in bits (only for LIRC_MODE_LIRCCODE). ++ Reads on the device must be done in blocks matching the bit count. ++ The bit could should be rounded up so that it matches full bytes. ++ ++ ++ ++ LIRC_SET_{SEND,REC}_MODE ++ ++ Set send/receive mode. Largely obsolete for send, as only ++ LIRC_MODE_PULSE is supported. ++ ++ ++ ++ LIRC_SET_{SEND,REC}_CARRIER ++ ++ Set send/receive carrier (in Hz). ++ ++ ++ ++ LIRC_SET_TRANSMITTER_MASK ++ ++ This enables the given set of transmitters. The first transmitter ++ is encoded by the least significant bit, etc. When an invalid bit mask ++ is given, i.e. a bit is set, even though the device does not have so many ++ transitters, then this ioctl returns the number of available transitters ++ and does nothing otherwise. ++ ++ ++ ++ LIRC_SET_REC_TIMEOUT ++ ++ Sets the integer value for IR inactivity timeout (cf. ++ LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT). A value of 0 (if ++ supported by the hardware) disables all hardware timeouts and data should ++ be reported as soon as possible. If the exact value cannot be set, then ++ the next possible value _greater_ than the given value should be set. ++ ++ ++ ++ LIRC_SET_REC_TIMEOUT_REPORTS ++ ++ Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By ++ default, timeout reports should be turned off. ++ ++ ++ ++ LIRC_SET_REC_FILTER_{,PULSE,SPACE} ++ ++ Pulses/spaces shorter than this are filtered out by hardware. If ++ filters cannot be set independently for pulse/space, the corresponding ++ ioctls must return an error and LIRC_SET_REC_FILTER shall be used instead. ++ ++ ++ ++ LIRC_SET_MEASURE_CARRIER_MODE ++ ++ Enable (1)/disable (0) measure mode. If enabled, from the next key ++ press on, the driver will send LIRC_MODE2_FREQUENCY packets. By default ++ this should be turned off. ++ ++ ++ ++ LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE ++ ++ To set a range use LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE ++ with the lower bound first and later LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER ++ with the upper bound. ++ ++ ++ ++ LIRC_NOTIFY_DECODE ++ ++ This ioctl is called by lircd whenever a successful decoding of an ++ incoming IR signal could be done. This can be used by supporting hardware ++ to give visual feedback to the user e.g. by flashing a LED. ++ ++ ++ ++ LIRC_SETUP_{START,END} ++ ++ Setting of several driver parameters can be optimized by encapsulating ++ the according ioctl calls with LIRC_SETUP_START/LIRC_SETUP_END. When a ++ driver receives a LIRC_SETUP_START ioctl it can choose to not commit ++ further setting changes to the hardware until a LIRC_SETUP_END is received. ++ But this is open to the driver implementation and every driver must also ++ handle parameter changes which are not encapsulated by LIRC_SETUP_START ++ and LIRC_SETUP_END. Drivers can also choose to ignore these ioctls. ++ ++ ++ ++ ++
++
+diff --git a/Documentation/DocBook/v4l/remote_controllers.xml b/Documentation/DocBook/v4l/remote_controllers.xml +index 73f5eab..3c3b667 100644 +--- a/Documentation/DocBook/v4l/remote_controllers.xml ++++ b/Documentation/DocBook/v4l/remote_controllers.xml +@@ -173,3 +173,5 @@ keymapping. + This program demonstrates how to replace the keymap tables. + &sub-keytable-c; + ++ ++&sub-lirc_device_interface; +diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware +index 239cbdb..9ea94dc 100644 +--- a/Documentation/dvb/get_dvb_firmware ++++ b/Documentation/dvb/get_dvb_firmware +@@ -26,7 +26,7 @@ use IO::Handle; + "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004", + "or51211", "or51132_qam", "or51132_vsb", "bluebird", + "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718", +- "af9015", "ngene"); ++ "af9015", "ngene", "az6027"); + + # Check args + syntax() if (scalar(@ARGV) != 1); +@@ -567,6 +567,23 @@ sub ngene { + "$file1, $file2"; + } + ++sub az6027{ ++ my $file = "AZ6027_Linux_Driver.tar.gz"; ++ my $url = "http://linux.terratec.de/files/$file"; ++ my $firmware = "dvb-usb-az6027-03.fw"; ++ ++ wgetfile($file, $url); ++ ++ #untar ++ if( system("tar xzvf $file $firmware")){ ++ die "failed to untar firmware"; ++ } ++ if( system("rm $file")){ ++ die ("unable to remove unnecessary files"); ++ } ++ ++ $firmware; ++} + # --------------------------------------------------------------- + # Utilities + +diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 +index 16ca030..87c4634 100644 +--- a/Documentation/video4linux/CARDLIST.cx23885 ++++ b/Documentation/video4linux/CARDLIST.cx23885 +@@ -17,9 +17,9 @@ + 16 -> DVBWorld DVB-S2 2005 [0001:2005] + 17 -> NetUP Dual DVB-S2 CI [1b55:2a2c] + 18 -> Hauppauge WinTV-HVR1270 [0070:2211] +- 19 -> Hauppauge WinTV-HVR1275 [0070:2215] +- 20 -> Hauppauge WinTV-HVR1255 [0070:2251] +- 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295] ++ 19 -> Hauppauge WinTV-HVR1275 [0070:2215,0070:221d,0070:22f2] ++ 20 -> Hauppauge WinTV-HVR1255 [0070:2251,0070:2259,0070:22f1] ++ 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295,0070:2299,0070:229d,0070:22f0,0070:22f3,0070:22f4,0070:22f5] + 22 -> Mygica X8506 DMB-TH [14f1:8651] + 23 -> Magic-Pro ProHDTV Extreme 2 [14f1:8657] + 24 -> Hauppauge WinTV-HVR1850 [0070:8541] +diff --git a/Documentation/video4linux/extract_xc3028.pl b/Documentation/video4linux/extract_xc3028.pl +old mode 100644 +new mode 100755 +diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c +index 2ee6c7a..b8a5673 100644 +--- a/drivers/input/evdev.c ++++ b/drivers/input/evdev.c +@@ -515,6 +515,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, + struct input_absinfo abs; + struct ff_effect effect; + int __user *ip = (int __user *)p; ++ struct keycode_table_entry kt, *kt_p = p; ++ char scancode[16]; + unsigned int i, t, u, v; + int error; + +@@ -569,6 +571,43 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, + + return input_set_keycode(dev, t, v); + ++ case EVIOCGKEYCODEBIG: ++ if (copy_from_user(&kt, kt_p, sizeof(kt))) ++ return -EFAULT; ++ ++ if (kt.len > sizeof(scancode)) ++ return -EINVAL; ++ ++ kt.scancode = scancode; ++ ++ error = input_get_keycode_big(dev, &kt); ++ if (error) ++ return error; ++ ++ if (copy_to_user(kt_p, &kt, sizeof(kt))) ++ return -EFAULT; ++ ++ /* FIXME: probably need some compat32 code */ ++ if (copy_to_user(kt_p->scancode, kt.scancode, kt.len)) ++ return -EFAULT; ++ ++ return 0; ++ ++ case EVIOCSKEYCODEBIG: ++ if (copy_from_user(&kt, kt_p, sizeof(kt))) ++ return -EFAULT; ++ ++ if (kt.len > sizeof(scancode)) ++ return -EINVAL; ++ ++ kt.scancode = scancode; ++ ++ /* FIXME: probably need some compat32 code */ ++ if (copy_from_user(kt.scancode, kt_p->scancode, kt.len)) ++ return -EFAULT; ++ ++ return input_set_keycode_big(dev, &kt); ++ + case EVIOCRMFF: + return input_ff_erase(dev, (int)(unsigned long) p, file); + +diff --git a/drivers/input/input.c b/drivers/input/input.c +index 9c79bd5..43aeb71 100644 +--- a/drivers/input/input.c ++++ b/drivers/input/input.c +@@ -568,6 +568,11 @@ static void input_disconnect_device(struct input_dev *dev) + spin_unlock_irq(&dev->event_lock); + } + ++/* ++ * Those routines handle the default case where no [gs]etkeycode() is ++ * defined. In this case, an array indexed by the scancode is used. ++ */ ++ + static int input_fetch_keycode(struct input_dev *dev, int scancode) + { + switch (dev->keycodesize) { +@@ -582,27 +587,74 @@ static int input_fetch_keycode(struct input_dev *dev, int scancode) + } + } + +-static int input_default_getkeycode(struct input_dev *dev, +- unsigned int scancode, +- unsigned int *keycode) ++/* ++ * Supports only 8, 16 and 32 bit scancodes. It wouldn't be that ++ * hard to write some machine-endian logic to support 24 bit scancodes, ++ * but it seemed overkill. It should also be noticed that, since there ++ * are, in general, less than 256 scancodes sparsed into the scancode ++ * space, even with 16 bits, the codespace is sparsed, with leads into ++ * memory and code ineficiency, when retrieving the entire scancode ++ * space. ++ * So, it is highly recommended to implement getkeycodebig/setkeycodebig ++ * instead of using a normal table approach, when more than 8 bits is ++ * needed for the scancode. ++ */ ++static int input_fetch_scancode(struct keycode_table_entry *kt_entry, ++ u32 *scancode) + { ++ switch (kt_entry->len) { ++ case 1: ++ *scancode = *((u8 *)kt_entry->scancode); ++ break; ++ case 2: ++ *scancode = *((u16 *)kt_entry->scancode); ++ break; ++ case 4: ++ *scancode = *((u32 *)kt_entry->scancode); ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++ ++static int input_default_getkeycode_from_index(struct input_dev *dev, ++ struct keycode_table_entry *kt_entry) ++{ ++ u32 scancode = kt_entry->index; ++ + if (!dev->keycodesize) + return -EINVAL; + + if (scancode >= dev->keycodemax) + return -EINVAL; + +- *keycode = input_fetch_keycode(dev, scancode); ++ kt_entry->keycode = input_fetch_keycode(dev, scancode); ++ memcpy(kt_entry->scancode, &scancode, 4); + + return 0; + } + ++static int input_default_getkeycode_from_scancode(struct input_dev *dev, ++ struct keycode_table_entry *kt_entry) ++{ ++ if (input_fetch_scancode(kt_entry, &kt_entry->index)) ++ return -EINVAL; ++ ++ return input_default_getkeycode_from_index(dev, kt_entry); ++} ++ ++ + static int input_default_setkeycode(struct input_dev *dev, +- unsigned int scancode, +- unsigned int keycode) ++ struct keycode_table_entry *kt_entry) + { +- int old_keycode; ++ u32 old_keycode; + int i; ++ u32 scancode; ++ ++ if (input_fetch_scancode(kt_entry, &scancode)) ++ return -EINVAL; + + if (scancode >= dev->keycodemax) + return -EINVAL; +@@ -610,32 +662,33 @@ static int input_default_setkeycode(struct input_dev *dev, + if (!dev->keycodesize) + return -EINVAL; + +- if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) ++ if (dev->keycodesize < sizeof(dev->keycode) && ++ (kt_entry->keycode >> (dev->keycodesize * 8))) + return -EINVAL; + + switch (dev->keycodesize) { + case 1: { + u8 *k = (u8 *)dev->keycode; + old_keycode = k[scancode]; +- k[scancode] = keycode; ++ k[scancode] = kt_entry->keycode; + break; + } + case 2: { + u16 *k = (u16 *)dev->keycode; + old_keycode = k[scancode]; +- k[scancode] = keycode; ++ k[scancode] = kt_entry->keycode; + break; + } + default: { + u32 *k = (u32 *)dev->keycode; + old_keycode = k[scancode]; +- k[scancode] = keycode; ++ k[scancode] = kt_entry->keycode; + break; + } + } + + __clear_bit(old_keycode, dev->keybit); +- __set_bit(keycode, dev->keybit); ++ __set_bit(kt_entry->keycode, dev->keybit); + + for (i = 0; i < dev->keycodemax; i++) { + if (input_fetch_keycode(dev, i) == old_keycode) { +@@ -648,6 +701,110 @@ static int input_default_setkeycode(struct input_dev *dev, + } + + /** ++ * input_get_keycode_big - retrieve keycode currently mapped to a given scancode ++ * @dev: input device which keymap is being queried ++ * @kt_entry: keytable entry ++ * ++ * This function should be called by anyone interested in retrieving current ++ * keymap. Presently evdev handlers use it. ++ */ ++int input_get_keycode_big(struct input_dev *dev, ++ struct keycode_table_entry *kt_entry) ++{ ++ if (dev->getkeycode) { ++ u32 scancode = kt_entry->index; ++ ++ /* ++ * Support for legacy drivers, that don't implement the new ++ * ioctls ++ */ ++ memcpy(kt_entry->scancode, &scancode, 4); ++ return dev->getkeycode(dev, scancode, ++ &kt_entry->keycode); ++ } else ++ return dev->getkeycodebig_from_index(dev, kt_entry); ++} ++EXPORT_SYMBOL(input_get_keycode_big); ++ ++/** ++ * input_set_keycode_big - attribute a keycode to a given scancode ++ * @dev: input device which keymap is being queried ++ * @kt_entry: keytable entry ++ * ++ * This function should be called by anyone needing to update current ++ * keymap. Presently keyboard and evdev handlers use it. ++ */ ++int input_set_keycode_big(struct input_dev *dev, ++ struct keycode_table_entry *kt_entry) ++{ ++ unsigned long flags; ++ int old_keycode; ++ int retval = -EINVAL; ++ u32 uninitialized_var(scancode); ++ ++ if (kt_entry->keycode < 0 || kt_entry->keycode > KEY_MAX) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ ++ /* ++ * We need to know the old scancode, in order to generate a ++ * keyup effect, if the set operation happens successfully ++ */ ++ if (dev->getkeycode) { ++ /* ++ * Support for legacy drivers, that don't implement the new ++ * ioctls ++ */ ++ if (!dev->setkeycode) ++ goto out; ++ ++ retval = input_fetch_scancode(kt_entry, &scancode); ++ if (retval) ++ goto out; ++ ++ retval = dev->getkeycode(dev, scancode, ++ &old_keycode); ++ } else { ++ int new_keycode = kt_entry->keycode; ++ ++ retval = dev->getkeycodebig_from_scancode(dev, kt_entry); ++ old_keycode = kt_entry->keycode; ++ kt_entry->keycode = new_keycode; ++ } ++ ++ if (retval) ++ goto out; ++ ++ if (dev->getkeycode) ++ retval = dev->setkeycode(dev, scancode, ++ kt_entry->keycode); ++ else ++ retval = dev->setkeycodebig(dev, kt_entry); ++ if (retval) ++ goto out; ++ ++ /* ++ * Simulate keyup event if keycode is not present ++ * in the keymap anymore ++ */ ++ if (test_bit(EV_KEY, dev->evbit) && ++ !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && ++ __test_and_clear_bit(old_keycode, dev->key)) { ++ ++ input_pass_event(dev, EV_KEY, old_keycode, 0); ++ if (dev->sync) ++ input_pass_event(dev, EV_SYN, SYN_REPORT, 1); ++ } ++ ++ out: ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ ++ return retval; ++} ++EXPORT_SYMBOL(input_set_keycode_big); ++ ++/** + * input_get_keycode - retrieve keycode currently mapped to a given scancode + * @dev: input device which keymap is being queried + * @scancode: scancode (or its equivalent for device in question) for which +@@ -661,13 +818,35 @@ int input_get_keycode(struct input_dev *dev, + unsigned int scancode, unsigned int *keycode) + { + unsigned long flags; +- int retval; + +- spin_lock_irqsave(&dev->event_lock, flags); +- retval = dev->getkeycode(dev, scancode, keycode); +- spin_unlock_irqrestore(&dev->event_lock, flags); ++ if (dev->getkeycode) { ++ /* ++ * Use the legacy calls ++ */ ++ return dev->getkeycode(dev, scancode, keycode); ++ } else { ++ int retval; ++ struct keycode_table_entry kt_entry; + +- return retval; ++ /* ++ * Userspace is using a legacy call with a driver ported ++ * to the new way. This is a bad idea with long sparsed ++ * tables, since lots of the retrieved values will be in ++ * blank. Also, it makes sense only if the table size is ++ * lower than 2^32. ++ */ ++ memset(&kt_entry, 0, sizeof(kt_entry)); ++ kt_entry.len = 4; ++ kt_entry.index = scancode; ++ kt_entry.scancode = (char *)&scancode; ++ ++ spin_lock_irqsave(&dev->event_lock, flags); ++ retval = dev->getkeycodebig_from_index(dev, &kt_entry); ++ spin_unlock_irqrestore(&dev->event_lock, flags); ++ ++ *keycode = kt_entry.keycode; ++ return retval; ++ } + } + EXPORT_SYMBOL(input_get_keycode); + +@@ -692,13 +871,42 @@ int input_set_keycode(struct input_dev *dev, + + spin_lock_irqsave(&dev->event_lock, flags); + +- retval = dev->getkeycode(dev, scancode, &old_keycode); +- if (retval) +- goto out; ++ if (dev->getkeycode) { ++ /* ++ * Use the legacy calls ++ */ ++ retval = dev->getkeycode(dev, scancode, &old_keycode); ++ if (retval) ++ goto out; + +- retval = dev->setkeycode(dev, scancode, keycode); +- if (retval) +- goto out; ++ retval = dev->setkeycode(dev, scancode, keycode); ++ if (retval) ++ goto out; ++ } else { ++ struct keycode_table_entry kt_entry; ++ ++ /* ++ * Userspace is using a legacy call with a driver ported ++ * to the new way. This is a bad idea with long sparsed ++ * tables, since lots of the retrieved values will be in ++ * blank. Also, it makes sense only if the table size is ++ * lower than 2^32. ++ */ ++ memset(&kt_entry, 0, sizeof(kt_entry)); ++ kt_entry.len = 4; ++ kt_entry.scancode = (char *)&scancode; ++ ++ retval = dev->getkeycodebig_from_scancode(dev, &kt_entry); ++ if (retval) ++ goto out; ++ ++ old_keycode = kt_entry.keycode; ++ kt_entry.keycode = keycode; ++ ++ retval = dev->setkeycodebig(dev, &kt_entry); ++ if (retval) ++ goto out; ++ } + + /* Make sure KEY_RESERVED did not get enabled. */ + __clear_bit(KEY_RESERVED, dev->keybit); +@@ -1636,11 +1843,17 @@ int input_register_device(struct input_dev *dev) + dev->rep[REP_PERIOD] = 33; + } + +- if (!dev->getkeycode) +- dev->getkeycode = input_default_getkeycode; ++ if (!dev->getkeycode) { ++ if (!dev->getkeycodebig_from_index) ++ dev->getkeycodebig_from_index = input_default_getkeycode_from_index; ++ if (!dev->getkeycodebig_from_scancode) ++ dev->getkeycodebig_from_scancode = input_default_getkeycode_from_scancode; ++ } + +- if (!dev->setkeycode) +- dev->setkeycode = input_default_setkeycode; ++ if (!dev->setkeycode) { ++ if (!dev->setkeycodebig) ++ dev->setkeycodebig = input_default_setkeycode; ++ } + + dev_set_name(&dev->dev, "input%ld", + (unsigned long) atomic_inc_return(&input_no) - 1); +diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig +index d22a8ec..e557ae0 100644 +--- a/drivers/media/IR/Kconfig ++++ b/drivers/media/IR/Kconfig +@@ -8,6 +8,17 @@ config VIDEO_IR + depends on IR_CORE + default IR_CORE + ++config LIRC ++ tristate ++ default y ++ ++ ---help--- ++ 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 ++ encoding for IR transmitting (aka "blasting"). ++ + source "drivers/media/IR/keymaps/Kconfig" + + config IR_NEC_DECODER +@@ -42,6 +53,7 @@ config IR_RC6_DECODER + config IR_JVC_DECODER + tristate "Enable IR raw decoder for the JVC protocol" + depends on IR_CORE ++ select BITREVERSE + default y + + ---help--- +@@ -57,6 +69,16 @@ 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_LIRC_CODEC ++ tristate "Enable IR to LIRC bridge" ++ depends on IR_CORE ++ depends on LIRC ++ default y ++ ++ ---help--- ++ Enable this option to pass raw IR to and from userspace via ++ the LIRC interface. ++ + config IR_IMON + tristate "SoundGraph iMON Receiver and Display" + depends on USB_ARCH_HAS_HCD +@@ -68,3 +90,15 @@ config IR_IMON + + To compile this driver as a module, choose M here: the + module will be called imon. ++ ++config IR_MCEUSB ++ tristate "Windows Media Center Ed. eHome Infrared Transceiver" ++ depends on USB_ARCH_HAS_HCD ++ depends on IR_CORE ++ select USB ++ ---help--- ++ Say Y here if you want to use a Windows Media Center Edition ++ eHome Infrared Transceiver. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called mceusb. +diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile +index b998fcc..2ae4f3a 100644 +--- a/drivers/media/IR/Makefile ++++ b/drivers/media/IR/Makefile +@@ -5,11 +5,14 @@ obj-y += keymaps/ + + obj-$(CONFIG_IR_CORE) += ir-core.o + obj-$(CONFIG_VIDEO_IR) += ir-common.o ++obj-$(CONFIG_LIRC) += lirc_dev.o + obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o + 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_LIRC_CODEC) += ir-lirc-codec.o + + # stand-alone IR receivers/transmitters + obj-$(CONFIG_IR_IMON) += imon.o ++obj-$(CONFIG_IR_MCEUSB) += mceusb.o +diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c +index 4bbd45f..0195dd5 100644 +--- a/drivers/media/IR/imon.c ++++ b/drivers/media/IR/imon.c +@@ -1943,7 +1943,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) + return ictx; + + urb_submit_failed: +- input_unregister_device(ictx->idev); ++ ir_input_unregister(ictx->idev); + input_free_device(ictx->idev); + idev_setup_failed: + find_endpoint_failed: +@@ -2067,6 +2067,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) + detected_display_type = IMON_DISPLAY_TYPE_VFD; + break; + /* iMON LCD, MCE IR */ ++ case 0x9e: + case 0x9f: + dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); + detected_display_type = IMON_DISPLAY_TYPE_LCD; +@@ -2306,7 +2307,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface) + if (ifnum == 0) { + ictx->dev_present_intf0 = false; + usb_kill_urb(ictx->rx_urb_intf0); +- input_unregister_device(ictx->idev); ++ ir_input_unregister(ictx->idev); + if (ictx->display_supported) { + if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) + usb_deregister_dev(interface, &imon_lcd_class); +diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h +index 9a5e65a..babd520 100644 +--- a/drivers/media/IR/ir-core-priv.h ++++ b/drivers/media/IR/ir-core-priv.h +@@ -22,17 +22,62 @@ + struct ir_raw_handler { + struct list_head list; + ++ u64 protocols; /* which are handled by this handler */ + int (*decode)(struct input_dev *input_dev, struct ir_raw_event event); ++ ++ /* These two should only be used by the lirc decoder */ + int (*raw_register)(struct input_dev *input_dev); + int (*raw_unregister)(struct input_dev *input_dev); + }; + + struct ir_raw_event_ctrl { ++ struct list_head list; /* to keep track of raw clients */ + struct work_struct rx_work; /* for the rx decoding workqueue */ + 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 */ + struct input_dev *input_dev; /* pointer to the parent input_dev */ ++ u64 enabled_protocols; /* enabled raw protocol decoders */ ++ ++ /* raw decoder state follows */ ++ struct ir_raw_event prev_ev; ++ struct nec_dec { ++ int state; ++ unsigned count; ++ u32 bits; ++ } nec; ++ struct rc5_dec { ++ int state; ++ u32 bits; ++ unsigned count; ++ unsigned wanted_bits; ++ } rc5; ++ struct rc6_dec { ++ int state; ++ u8 header; ++ u32 body; ++ bool toggle; ++ unsigned count; ++ unsigned wanted_bits; ++ } rc6; ++ struct sony_dec { ++ int state; ++ u32 bits; ++ unsigned count; ++ } sony; ++ struct jvc_dec { ++ int state; ++ u16 bits; ++ u16 old_bits; ++ unsigned count; ++ bool first; ++ bool toggle; ++ } jvc; ++ struct lirc_codec { ++ struct ir_input_dev *ir_dev; ++ struct lirc_driver *drv; ++ int lircdata; ++ } lirc; + }; + + /* macros for IR decoders */ +@@ -74,6 +119,7 @@ void ir_unregister_class(struct input_dev *input_dev); + /* + * Routines from ir-raw-event.c to be used internally and by decoders + */ ++u64 ir_raw_get_allowed_protocols(void); + int ir_raw_event_register(struct input_dev *input_dev); + void ir_raw_event_unregister(struct input_dev *input_dev); + int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler); +@@ -123,4 +169,12 @@ void ir_raw_init(void); + #define load_sony_decode() 0 + #endif + ++/* from ir-lirc-codec.c */ ++#ifdef CONFIG_IR_LIRC_CODEC_MODULE ++#define load_lirc_codec() request_module("ir-lirc-codec") ++#else ++#define load_lirc_codec() 0 ++#endif ++ ++ + #endif /* _IR_RAW_EVENT */ +diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/IR/ir-jvc-decoder.c +index 0b80494..8894d8b 100644 +--- a/drivers/media/IR/ir-jvc-decoder.c ++++ b/drivers/media/IR/ir-jvc-decoder.c +@@ -25,10 +25,6 @@ + #define JVC_TRAILER_PULSE (1 * JVC_UNIT) + #define JVC_TRAILER_SPACE (35 * JVC_UNIT) + +-/* Used to register jvc_decoder clients */ +-static LIST_HEAD(decoder_list); +-DEFINE_SPINLOCK(decoder_lock); +- + enum jvc_state { + STATE_INACTIVE, + STATE_HEADER_SPACE, +@@ -38,87 +34,6 @@ enum jvc_state { + STATE_TRAILER_SPACE, + }; + +-struct decoder_data { +- struct list_head list; +- struct ir_input_dev *ir_dev; +- int enabled:1; +- +- /* State machine control */ +- enum jvc_state state; +- u16 jvc_bits; +- u16 jvc_old_bits; +- unsigned count; +- bool first; +- bool toggle; +-}; +- +- +-/** +- * get_decoder_data() - gets decoder data +- * @input_dev: input device +- * +- * Returns the struct decoder_data that corresponds to a device +- */ +-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) +-{ +- struct decoder_data *data = NULL; +- +- spin_lock(&decoder_lock); +- list_for_each_entry(data, &decoder_list, list) { +- if (data->ir_dev == ir_dev) +- break; +- } +- spin_unlock(&decoder_lock); +- return data; +-} +- +-static ssize_t store_enabled(struct device *d, +- struct device_attribute *mattr, +- const char *buf, +- size_t len) +-{ +- unsigned long value; +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (strict_strtoul(buf, 10, &value) || value > 1) +- return -EINVAL; +- +- data->enabled = value; +- +- return len; +-} +- +-static ssize_t show_enabled(struct device *d, +- struct device_attribute *mattr, char *buf) +-{ +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (data->enabled) +- return sprintf(buf, "1\n"); +- else +- return sprintf(buf, "0\n"); +-} +- +-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); +- +-static struct attribute *decoder_attributes[] = { +- &dev_attr_enabled.attr, +- NULL +-}; +- +-static struct attribute_group decoder_attribute_group = { +- .name = "jvc_decoder", +- .attrs = decoder_attributes, +-}; +- + /** + * ir_jvc_decode() - Decode one JVC pulse or space + * @input_dev: the struct input_dev descriptor of the device +@@ -128,14 +43,10 @@ static struct attribute_group decoder_attribute_group = { + */ + static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) + { +- struct decoder_data *data; + struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); ++ struct jvc_dec *data = &ir_dev->raw->jvc; + +- data = get_decoder_data(ir_dev); +- if (!data) +- return -EINVAL; +- +- if (!data->enabled) ++ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC)) + return 0; + + if (IS_RESET(ev)) { +@@ -188,9 +99,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) + if (ev.pulse) + break; + +- data->jvc_bits <<= 1; ++ data->bits <<= 1; + if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) { +- data->jvc_bits |= 1; ++ data->bits |= 1; + decrease_duration(&ev, JVC_BIT_1_SPACE); + } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2)) + decrease_duration(&ev, JVC_BIT_0_SPACE); +@@ -223,13 +134,13 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) + + if (data->first) { + u32 scancode; +- scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) | +- (bitrev8((data->jvc_bits >> 0) & 0xff) << 0); ++ scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) | ++ (bitrev8((data->bits >> 0) & 0xff) << 0); + IR_dprintk(1, "JVC scancode 0x%04x\n", scancode); + ir_keydown(input_dev, scancode, data->toggle); + data->first = false; +- data->jvc_old_bits = data->jvc_bits; +- } else if (data->jvc_bits == data->jvc_old_bits) { ++ data->old_bits = data->bits; ++ } else if (data->bits == data->old_bits) { + IR_dprintk(1, "JVC repeat\n"); + ir_repeat(input_dev); + } else { +@@ -249,54 +160,9 @@ out: + return -EINVAL; + } + +-static int ir_jvc_register(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- struct decoder_data *data; +- int rc; +- +- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- if (rc < 0) +- return rc; +- +- data = kzalloc(sizeof(*data), GFP_KERNEL); +- if (!data) { +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- return -ENOMEM; +- } +- +- data->ir_dev = ir_dev; +- data->enabled = 1; +- +- spin_lock(&decoder_lock); +- list_add_tail(&data->list, &decoder_list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- +-static int ir_jvc_unregister(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- static struct decoder_data *data; +- +- data = get_decoder_data(ir_dev); +- if (!data) +- return 0; +- +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- +- spin_lock(&decoder_lock); +- list_del(&data->list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- + static struct ir_raw_handler jvc_handler = { ++ .protocols = IR_TYPE_JVC, + .decode = ir_jvc_decode, +- .raw_register = ir_jvc_register, +- .raw_unregister = ir_jvc_unregister, + }; + + static int __init ir_jvc_decode_init(void) +diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c +new file mode 100644 +index 0000000..afb1ada +--- /dev/null ++++ b/drivers/media/IR/ir-lirc-codec.c +@@ -0,0 +1,283 @@ ++/* ir-lirc-codec.c - ir-core to classic lirc interface bridge ++ * ++ * Copyright (C) 2010 by Jarod Wilson ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "ir-core-priv.h" ++ ++#define LIRCBUF_SIZE 256 ++ ++/** ++ * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the ++ * lircd userspace daemon for decoding. ++ * @input_dev: the struct input_dev descriptor of the device ++ * @duration: the struct ir_raw_event descriptor of the pulse/space ++ * ++ * This function returns -EINVAL if the lirc interfaces aren't wired up. ++ */ ++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); ++ ++ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC)) ++ return 0; ++ ++ if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf) ++ return -EINVAL; ++ ++ IR_dprintk(2, "LIRC data transfer started (%uus %s)\n", ++ TO_US(ev.duration), TO_STR(ev.pulse)); ++ ++ ir_dev->raw->lirc.lircdata += ev.duration / 1000; ++ if (ev.pulse) ++ ir_dev->raw->lirc.lircdata |= PULSE_BIT; ++ ++ lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf, ++ (unsigned char *) &ir_dev->raw->lirc.lircdata); ++ wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll); ++ ++ ir_dev->raw->lirc.lircdata = 0; ++ ++ return 0; ++} ++ ++static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf, ++ size_t n, loff_t *ppos) ++{ ++ struct lirc_codec *lirc; ++ struct ir_input_dev *ir_dev; ++ int *txbuf; /* buffer with values to transmit */ ++ int ret = 0, count; ++ ++ lirc = lirc_get_pdata(file); ++ if (!lirc) ++ return -EFAULT; ++ ++ if (n % sizeof(int)) ++ return -EINVAL; ++ ++ count = n / sizeof(int); ++ if (count > LIRCBUF_SIZE || count % 2 == 0) ++ return -EINVAL; ++ ++ txbuf = kzalloc(sizeof(int) * LIRCBUF_SIZE, GFP_KERNEL); ++ if (!txbuf) ++ return -ENOMEM; ++ ++ if (copy_from_user(txbuf, buf, n)) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ ir_dev = lirc->ir_dev; ++ if (!ir_dev) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (ir_dev->props && ir_dev->props->tx_ir) ++ ret = ir_dev->props->tx_ir(ir_dev->props->priv, txbuf, (u32)n); ++ ++out: ++ kfree(txbuf); ++ return ret; ++} ++ ++static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) ++{ ++ struct lirc_codec *lirc; ++ struct ir_input_dev *ir_dev; ++ int ret = 0; ++ void *drv_data; ++ unsigned long val; ++ ++ lirc = lirc_get_pdata(filep); ++ if (!lirc) ++ return -EFAULT; ++ ++ ir_dev = lirc->ir_dev; ++ if (!ir_dev || !ir_dev->props || !ir_dev->props->priv) ++ return -EFAULT; ++ ++ drv_data = ir_dev->props->priv; ++ ++ switch (cmd) { ++ case LIRC_SET_TRANSMITTER_MASK: ++ ret = get_user(val, (unsigned long *)arg); ++ if (ret) ++ return ret; ++ ++ if (ir_dev->props && ir_dev->props->s_tx_mask) ++ ret = ir_dev->props->s_tx_mask(drv_data, (u32)val); ++ else ++ return -EINVAL; ++ break; ++ ++ case LIRC_SET_SEND_CARRIER: ++ ret = get_user(val, (unsigned long *)arg); ++ if (ret) ++ return ret; ++ ++ if (ir_dev->props && ir_dev->props->s_tx_carrier) ++ ir_dev->props->s_tx_carrier(drv_data, (u32)val); ++ else ++ return -EINVAL; ++ break; ++ ++ case LIRC_GET_SEND_MODE: ++ val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; ++ ret = put_user(val, (unsigned long *)arg); ++ break; ++ ++ case LIRC_SET_SEND_MODE: ++ ret = get_user(val, (unsigned long *)arg); ++ if (ret) ++ return ret; ++ ++ if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) ++ return -EINVAL; ++ break; ++ ++ default: ++ return lirc_dev_fop_ioctl(filep, cmd, arg); ++ } ++ ++ return ret; ++} ++ ++static int ir_lirc_open(void *data) ++{ ++ return 0; ++} ++ ++static void ir_lirc_close(void *data) ++{ ++ return; ++} ++ ++static struct file_operations lirc_fops = { ++ .owner = THIS_MODULE, ++ .write = ir_lirc_transmit_ir, ++ .unlocked_ioctl = ir_lirc_ioctl, ++ .read = lirc_dev_fop_read, ++ .poll = lirc_dev_fop_poll, ++ .open = lirc_dev_fop_open, ++ .release = lirc_dev_fop_close, ++}; ++ ++static int ir_lirc_register(struct input_dev *input_dev) ++{ ++ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); ++ struct lirc_driver *drv; ++ struct lirc_buffer *rbuf; ++ int rc = -ENOMEM; ++ unsigned long features; ++ ++ drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); ++ if (!drv) ++ return rc; ++ ++ rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); ++ if (!drv) ++ goto rbuf_alloc_failed; ++ ++ rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE); ++ if (rc) ++ goto rbuf_init_failed; ++ ++ features = LIRC_CAN_REC_MODE2; ++ if (ir_dev->props->tx_ir) { ++ features |= LIRC_CAN_SEND_PULSE; ++ if (ir_dev->props->s_tx_mask) ++ features |= LIRC_CAN_SET_TRANSMITTER_MASK; ++ if (ir_dev->props->s_tx_carrier) ++ features |= LIRC_CAN_SET_SEND_CARRIER; ++ } ++ ++ snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", ++ ir_dev->driver_name); ++ drv->minor = -1; ++ drv->features = features; ++ drv->data = &ir_dev->raw->lirc; ++ drv->rbuf = rbuf; ++ drv->set_use_inc = &ir_lirc_open; ++ drv->set_use_dec = &ir_lirc_close; ++ drv->code_length = sizeof(struct ir_raw_event) * 8; ++ drv->fops = &lirc_fops; ++ drv->dev = &ir_dev->dev; ++ drv->owner = THIS_MODULE; ++ ++ drv->minor = lirc_register_driver(drv); ++ if (drv->minor < 0) { ++ rc = -ENODEV; ++ goto lirc_register_failed; ++ } ++ ++ ir_dev->raw->lirc.drv = drv; ++ ir_dev->raw->lirc.ir_dev = ir_dev; ++ ir_dev->raw->lirc.lircdata = PULSE_MASK; ++ ++ return 0; ++ ++lirc_register_failed: ++rbuf_init_failed: ++ kfree(rbuf); ++rbuf_alloc_failed: ++ kfree(drv); ++ ++ return rc; ++} ++ ++static int ir_lirc_unregister(struct input_dev *input_dev) ++{ ++ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); ++ struct lirc_codec *lirc = &ir_dev->raw->lirc; ++ ++ lirc_unregister_driver(lirc->drv->minor); ++ lirc_buffer_free(lirc->drv->rbuf); ++ kfree(lirc->drv); ++ ++ return 0; ++} ++ ++static struct ir_raw_handler lirc_handler = { ++ .protocols = IR_TYPE_LIRC, ++ .decode = ir_lirc_decode, ++ .raw_register = ir_lirc_register, ++ .raw_unregister = ir_lirc_unregister, ++}; ++ ++static int __init ir_lirc_codec_init(void) ++{ ++ ir_raw_handler_register(&lirc_handler); ++ ++ printk(KERN_INFO "IR LIRC bridge handler initialized\n"); ++ return 0; ++} ++ ++static void __exit ir_lirc_codec_exit(void) ++{ ++ ir_raw_handler_unregister(&lirc_handler); ++} ++ ++module_init(ir_lirc_codec_init); ++module_exit(ir_lirc_codec_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Jarod Wilson "); ++MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); ++MODULE_DESCRIPTION("LIRC IR handler bridge"); +diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c +index ba79233..52e0f37 100644 +--- a/drivers/media/IR/ir-nec-decoder.c ++++ b/drivers/media/IR/ir-nec-decoder.c +@@ -27,10 +27,6 @@ + #define NEC_TRAILER_PULSE (1 * NEC_UNIT) + #define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */ + +-/* Used to register nec_decoder clients */ +-static LIST_HEAD(decoder_list); +-static DEFINE_SPINLOCK(decoder_lock); +- + enum nec_state { + STATE_INACTIVE, + STATE_HEADER_SPACE, +@@ -40,84 +36,6 @@ enum nec_state { + STATE_TRAILER_SPACE, + }; + +-struct decoder_data { +- struct list_head list; +- struct ir_input_dev *ir_dev; +- int enabled:1; +- +- /* State machine control */ +- enum nec_state state; +- u32 nec_bits; +- unsigned count; +-}; +- +- +-/** +- * get_decoder_data() - gets decoder data +- * @input_dev: input device +- * +- * Returns the struct decoder_data that corresponds to a device +- */ +-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) +-{ +- struct decoder_data *data = NULL; +- +- spin_lock(&decoder_lock); +- list_for_each_entry(data, &decoder_list, list) { +- if (data->ir_dev == ir_dev) +- break; +- } +- spin_unlock(&decoder_lock); +- return data; +-} +- +-static ssize_t store_enabled(struct device *d, +- struct device_attribute *mattr, +- const char *buf, +- size_t len) +-{ +- unsigned long value; +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (strict_strtoul(buf, 10, &value) || value > 1) +- return -EINVAL; +- +- data->enabled = value; +- +- return len; +-} +- +-static ssize_t show_enabled(struct device *d, +- struct device_attribute *mattr, char *buf) +-{ +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (data->enabled) +- return sprintf(buf, "1\n"); +- else +- return sprintf(buf, "0\n"); +-} +- +-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); +- +-static struct attribute *decoder_attributes[] = { +- &dev_attr_enabled.attr, +- NULL +-}; +- +-static struct attribute_group decoder_attribute_group = { +- .name = "nec_decoder", +- .attrs = decoder_attributes, +-}; +- + /** + * ir_nec_decode() - Decode one NEC pulse or space + * @input_dev: the struct input_dev descriptor of the device +@@ -127,16 +45,12 @@ static struct attribute_group decoder_attribute_group = { + */ + static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) + { +- struct decoder_data *data; + struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); ++ struct nec_dec *data = &ir_dev->raw->nec; + u32 scancode; + u8 address, not_address, command, not_command; + +- data = get_decoder_data(ir_dev); +- if (!data) +- return -EINVAL; +- +- if (!data->enabled) ++ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC)) + return 0; + + if (IS_RESET(ev)) { +@@ -191,9 +105,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) + if (ev.pulse) + break; + +- data->nec_bits <<= 1; ++ data->bits <<= 1; + if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2)) +- data->nec_bits |= 1; ++ data->bits |= 1; + else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2)) + break; + data->count++; +@@ -222,14 +136,14 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) + if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) + break; + +- address = bitrev8((data->nec_bits >> 24) & 0xff); +- not_address = bitrev8((data->nec_bits >> 16) & 0xff); +- command = bitrev8((data->nec_bits >> 8) & 0xff); +- not_command = bitrev8((data->nec_bits >> 0) & 0xff); ++ address = bitrev8((data->bits >> 24) & 0xff); ++ not_address = bitrev8((data->bits >> 16) & 0xff); ++ command = bitrev8((data->bits >> 8) & 0xff); ++ not_command = bitrev8((data->bits >> 0) & 0xff); + + if ((command ^ not_command) != 0xff) { + IR_dprintk(1, "NEC checksum error: received 0x%08x\n", +- data->nec_bits); ++ data->bits); + break; + } + +@@ -256,54 +170,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) + return -EINVAL; + } + +-static int ir_nec_register(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- struct decoder_data *data; +- int rc; +- +- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- if (rc < 0) +- return rc; +- +- data = kzalloc(sizeof(*data), GFP_KERNEL); +- if (!data) { +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- return -ENOMEM; +- } +- +- data->ir_dev = ir_dev; +- data->enabled = 1; +- +- spin_lock(&decoder_lock); +- list_add_tail(&data->list, &decoder_list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- +-static int ir_nec_unregister(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- static struct decoder_data *data; +- +- data = get_decoder_data(ir_dev); +- if (!data) +- return 0; +- +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- +- spin_lock(&decoder_lock); +- list_del(&data->list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- + static struct ir_raw_handler nec_handler = { ++ .protocols = IR_TYPE_NEC, + .decode = ir_nec_decode, +- .raw_register = ir_nec_register, +- .raw_unregister = ir_nec_unregister, + }; + + static int __init ir_nec_decode_init(void) +diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c +index ea68a3f..6f192ef 100644 +--- a/drivers/media/IR/ir-raw-event.c ++++ b/drivers/media/IR/ir-raw-event.c +@@ -20,35 +20,13 @@ + /* Define the max number of pulse/space transitions to buffer */ + #define MAX_IR_EVENT_SIZE 512 + ++/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ ++static LIST_HEAD(ir_raw_client_list); ++ + /* Used to handle IR raw handler extensions */ +-static LIST_HEAD(ir_raw_handler_list); + static DEFINE_SPINLOCK(ir_raw_handler_lock); +- +-/** +- * RUN_DECODER() - runs an operation on all IR decoders +- * @ops: IR raw handler operation to be called +- * @arg: arguments to be passed to the callback +- * +- * Calls ir_raw_handler::ops for all registered IR handlers. It prevents +- * new decode addition/removal while running, by locking ir_raw_handler_lock +- * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum +- * of the return codes. +- */ +-#define RUN_DECODER(ops, ...) ({ \ +- struct ir_raw_handler *_ir_raw_handler; \ +- int _sumrc = 0, _rc; \ +- spin_lock(&ir_raw_handler_lock); \ +- list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) { \ +- if (_ir_raw_handler->ops) { \ +- _rc = _ir_raw_handler->ops(__VA_ARGS__); \ +- if (_rc < 0) \ +- break; \ +- _sumrc += _rc; \ +- } \ +- } \ +- spin_unlock(&ir_raw_handler_lock); \ +- _sumrc; \ +-}) ++static LIST_HEAD(ir_raw_handler_list); ++static u64 available_protocols; + + #ifdef MODULE + /* Used to load the decoders */ +@@ -58,57 +36,17 @@ static struct work_struct wq_load; + static void ir_raw_event_work(struct work_struct *work) + { + struct ir_raw_event ev; ++ struct ir_raw_handler *handler; + struct ir_raw_event_ctrl *raw = + container_of(work, struct ir_raw_event_ctrl, rx_work); + +- while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) +- RUN_DECODER(decode, raw->input_dev, ev); +-} +- +-int ir_raw_event_register(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir = input_get_drvdata(input_dev); +- int rc; +- +- ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); +- if (!ir->raw) +- return -ENOMEM; +- +- ir->raw->input_dev = input_dev; +- INIT_WORK(&ir->raw->rx_work, ir_raw_event_work); +- +- rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE, +- GFP_KERNEL); +- if (rc < 0) { +- kfree(ir->raw); +- ir->raw = NULL; +- return rc; +- } +- +- rc = RUN_DECODER(raw_register, input_dev); +- if (rc < 0) { +- kfifo_free(&ir->raw->kfifo); +- kfree(ir->raw); +- ir->raw = NULL; +- return rc; ++ while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) { ++ spin_lock(&ir_raw_handler_lock); ++ list_for_each_entry(handler, &ir_raw_handler_list, list) ++ handler->decode(raw->input_dev, ev); ++ spin_unlock(&ir_raw_handler_lock); ++ raw->prev_ev = ev; + } +- +- return rc; +-} +- +-void ir_raw_event_unregister(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir = input_get_drvdata(input_dev); +- +- if (!ir->raw) +- return; +- +- cancel_work_sync(&ir->raw->rx_work); +- RUN_DECODER(raw_unregister, input_dev); +- +- kfifo_free(&ir->raw->kfifo); +- kfree(ir->raw); +- ir->raw = NULL; + } + + /** +@@ -204,23 +142,103 @@ void ir_raw_event_handle(struct input_dev *input_dev) + } + EXPORT_SYMBOL_GPL(ir_raw_event_handle); + ++/* used internally by the sysfs interface */ ++u64 ++ir_raw_get_allowed_protocols() ++{ ++ u64 protocols; ++ spin_lock(&ir_raw_handler_lock); ++ protocols = available_protocols; ++ spin_unlock(&ir_raw_handler_lock); ++ return protocols; ++} ++ ++/* ++ * Used to (un)register raw event clients ++ */ ++int ir_raw_event_register(struct input_dev *input_dev) ++{ ++ struct ir_input_dev *ir = input_get_drvdata(input_dev); ++ int rc; ++ struct ir_raw_handler *handler; ++ ++ ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); ++ if (!ir->raw) ++ return -ENOMEM; ++ ++ ir->raw->input_dev = input_dev; ++ INIT_WORK(&ir->raw->rx_work, ir_raw_event_work); ++ ir->raw->enabled_protocols = ~0; ++ rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE, ++ GFP_KERNEL); ++ if (rc < 0) { ++ kfree(ir->raw); ++ ir->raw = NULL; ++ return rc; ++ } ++ ++ spin_lock(&ir_raw_handler_lock); ++ list_add_tail(&ir->raw->list, &ir_raw_client_list); ++ list_for_each_entry(handler, &ir_raw_handler_list, list) ++ if (handler->raw_register) ++ handler->raw_register(ir->raw->input_dev); ++ spin_unlock(&ir_raw_handler_lock); ++ ++ return 0; ++} ++ ++void ir_raw_event_unregister(struct input_dev *input_dev) ++{ ++ struct ir_input_dev *ir = input_get_drvdata(input_dev); ++ struct ir_raw_handler *handler; ++ ++ if (!ir->raw) ++ return; ++ ++ cancel_work_sync(&ir->raw->rx_work); ++ ++ spin_lock(&ir_raw_handler_lock); ++ list_del(&ir->raw->list); ++ list_for_each_entry(handler, &ir_raw_handler_list, list) ++ if (handler->raw_unregister) ++ handler->raw_unregister(ir->raw->input_dev); ++ spin_unlock(&ir_raw_handler_lock); ++ ++ kfifo_free(&ir->raw->kfifo); ++ kfree(ir->raw); ++ ir->raw = NULL; ++} ++ + /* + * Extension interface - used to register the IR decoders + */ + + int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) + { ++ struct ir_raw_event_ctrl *raw; ++ + spin_lock(&ir_raw_handler_lock); + list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); ++ if (ir_raw_handler->raw_register) ++ list_for_each_entry(raw, &ir_raw_client_list, list) ++ ir_raw_handler->raw_register(raw->input_dev); ++ available_protocols |= ir_raw_handler->protocols; + spin_unlock(&ir_raw_handler_lock); ++ + return 0; + } + EXPORT_SYMBOL(ir_raw_handler_register); + + void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) + { ++ struct ir_raw_event_ctrl *raw; ++ + spin_lock(&ir_raw_handler_lock); + list_del(&ir_raw_handler->list); ++ if (ir_raw_handler->raw_unregister) ++ list_for_each_entry(raw, &ir_raw_client_list, list) ++ ir_raw_handler->raw_unregister(raw->input_dev); ++ available_protocols &= ~ir_raw_handler->protocols; + spin_unlock(&ir_raw_handler_lock); + } + EXPORT_SYMBOL(ir_raw_handler_unregister); +@@ -235,6 +253,7 @@ static void init_decoders(struct work_struct *work) + load_rc6_decode(); + load_jvc_decode(); + load_sony_decode(); ++ load_lirc_codec(); + + /* If needed, we may later add some init code. In this case, + it is needed to change the CONFIG_MODULE test at ir-core.h +diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c +index 23cdb1b..df4770d 100644 +--- a/drivers/media/IR/ir-rc5-decoder.c ++++ b/drivers/media/IR/ir-rc5-decoder.c +@@ -30,10 +30,6 @@ + #define RC5_BIT_END (1 * RC5_UNIT) + #define RC5X_SPACE (4 * RC5_UNIT) + +-/* Used to register rc5_decoder clients */ +-static LIST_HEAD(decoder_list); +-static DEFINE_SPINLOCK(decoder_lock); +- + enum rc5_state { + STATE_INACTIVE, + STATE_BIT_START, +@@ -42,87 +38,6 @@ enum rc5_state { + STATE_FINISHED, + }; + +-struct decoder_data { +- struct list_head list; +- struct ir_input_dev *ir_dev; +- int enabled:1; +- +- /* State machine control */ +- enum rc5_state state; +- u32 rc5_bits; +- struct ir_raw_event prev_ev; +- unsigned count; +- unsigned wanted_bits; +-}; +- +- +-/** +- * get_decoder_data() - gets decoder data +- * @input_dev: input device +- * +- * Returns the struct decoder_data that corresponds to a device +- */ +- +-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) +-{ +- struct decoder_data *data = NULL; +- +- spin_lock(&decoder_lock); +- list_for_each_entry(data, &decoder_list, list) { +- if (data->ir_dev == ir_dev) +- break; +- } +- spin_unlock(&decoder_lock); +- return data; +-} +- +-static ssize_t store_enabled(struct device *d, +- struct device_attribute *mattr, +- const char *buf, +- size_t len) +-{ +- unsigned long value; +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (strict_strtoul(buf, 10, &value) || value > 1) +- return -EINVAL; +- +- data->enabled = value; +- +- return len; +-} +- +-static ssize_t show_enabled(struct device *d, +- struct device_attribute *mattr, char *buf) +-{ +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (data->enabled) +- return sprintf(buf, "1\n"); +- else +- return sprintf(buf, "0\n"); +-} +- +-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); +- +-static struct attribute *decoder_attributes[] = { +- &dev_attr_enabled.attr, +- NULL +-}; +- +-static struct attribute_group decoder_attribute_group = { +- .name = "rc5_decoder", +- .attrs = decoder_attributes, +-}; +- + /** + * ir_rc5_decode() - Decode one RC-5 pulse or space + * @input_dev: the struct input_dev descriptor of the device +@@ -132,17 +47,13 @@ static struct attribute_group decoder_attribute_group = { + */ + static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev) + { +- struct decoder_data *data; + struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); ++ struct rc5_dec *data = &ir_dev->raw->rc5; + u8 toggle; + u32 scancode; + +- data = get_decoder_data(ir_dev); +- if (!data) +- return -EINVAL; +- +- if (!data->enabled) +- return 0; ++ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5)) ++ return 0; + + if (IS_RESET(ev)) { + data->state = STATE_INACTIVE; +@@ -176,16 +87,15 @@ again: + if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) + break; + +- data->rc5_bits <<= 1; ++ data->bits <<= 1; + if (!ev.pulse) +- data->rc5_bits |= 1; ++ data->bits |= 1; + data->count++; +- data->prev_ev = ev; + data->state = STATE_BIT_END; + return 0; + + case STATE_BIT_END: +- if (!is_transition(&ev, &data->prev_ev)) ++ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) + break; + + if (data->count == data->wanted_bits) +@@ -217,11 +127,11 @@ again: + if (data->wanted_bits == RC5X_NBITS) { + /* RC5X */ + u8 xdata, command, system; +- xdata = (data->rc5_bits & 0x0003F) >> 0; +- command = (data->rc5_bits & 0x00FC0) >> 6; +- system = (data->rc5_bits & 0x1F000) >> 12; +- toggle = (data->rc5_bits & 0x20000) ? 1 : 0; +- command += (data->rc5_bits & 0x01000) ? 0 : 0x40; ++ xdata = (data->bits & 0x0003F) >> 0; ++ command = (data->bits & 0x00FC0) >> 6; ++ system = (data->bits & 0x1F000) >> 12; ++ toggle = (data->bits & 0x20000) ? 1 : 0; ++ command += (data->bits & 0x01000) ? 0 : 0x40; + scancode = system << 16 | command << 8 | xdata; + + IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n", +@@ -230,10 +140,10 @@ again: + } else { + /* RC5 */ + u8 command, system; +- command = (data->rc5_bits & 0x0003F) >> 0; +- system = (data->rc5_bits & 0x007C0) >> 6; +- toggle = (data->rc5_bits & 0x00800) ? 1 : 0; +- command += (data->rc5_bits & 0x01000) ? 0 : 0x40; ++ command = (data->bits & 0x0003F) >> 0; ++ system = (data->bits & 0x007C0) >> 6; ++ toggle = (data->bits & 0x00800) ? 1 : 0; ++ command += (data->bits & 0x01000) ? 0 : 0x40; + scancode = system << 8 | command; + + IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n", +@@ -252,54 +162,9 @@ out: + return -EINVAL; + } + +-static int ir_rc5_register(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- struct decoder_data *data; +- int rc; +- +- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- if (rc < 0) +- return rc; +- +- data = kzalloc(sizeof(*data), GFP_KERNEL); +- if (!data) { +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- return -ENOMEM; +- } +- +- data->ir_dev = ir_dev; +- data->enabled = 1; +- +- spin_lock(&decoder_lock); +- list_add_tail(&data->list, &decoder_list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- +-static int ir_rc5_unregister(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- static struct decoder_data *data; +- +- data = get_decoder_data(ir_dev); +- if (!data) +- return 0; +- +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- +- spin_lock(&decoder_lock); +- list_del(&data->list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- + static struct ir_raw_handler rc5_handler = { ++ .protocols = IR_TYPE_RC5, + .decode = ir_rc5_decode, +- .raw_register = ir_rc5_register, +- .raw_unregister = ir_rc5_unregister, + }; + + static int __init ir_rc5_decode_init(void) +diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c +index 2bf479f..f1624b8 100644 +--- a/drivers/media/IR/ir-rc6-decoder.c ++++ b/drivers/media/IR/ir-rc6-decoder.c +@@ -36,10 +36,6 @@ + #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ + #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ + +-/* Used to register rc6_decoder clients */ +-static LIST_HEAD(decoder_list); +-static DEFINE_SPINLOCK(decoder_lock); +- + enum rc6_mode { + RC6_MODE_0, + RC6_MODE_6A, +@@ -58,89 +54,8 @@ enum rc6_state { + STATE_FINISHED, + }; + +-struct decoder_data { +- struct list_head list; +- struct ir_input_dev *ir_dev; +- int enabled:1; +- +- /* State machine control */ +- enum rc6_state state; +- u8 header; +- u32 body; +- struct ir_raw_event prev_ev; +- bool toggle; +- unsigned count; +- unsigned wanted_bits; +-}; +- +- +-/** +- * get_decoder_data() - gets decoder data +- * @input_dev: input device +- * +- * Returns the struct decoder_data that corresponds to a device +- */ +-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) +-{ +- struct decoder_data *data = NULL; +- +- spin_lock(&decoder_lock); +- list_for_each_entry(data, &decoder_list, list) { +- if (data->ir_dev == ir_dev) +- break; +- } +- spin_unlock(&decoder_lock); +- return data; +-} +- +-static ssize_t store_enabled(struct device *d, +- struct device_attribute *mattr, +- const char *buf, +- size_t len) ++static enum rc6_mode rc6_mode(struct rc6_dec *data) + { +- unsigned long value; +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (strict_strtoul(buf, 10, &value) || value > 1) +- return -EINVAL; +- +- data->enabled = value; +- +- return len; +-} +- +-static ssize_t show_enabled(struct device *d, +- struct device_attribute *mattr, char *buf) +-{ +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (data->enabled) +- return sprintf(buf, "1\n"); +- else +- return sprintf(buf, "0\n"); +-} +- +-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); +- +-static struct attribute *decoder_attributes[] = { +- &dev_attr_enabled.attr, +- NULL +-}; +- +-static struct attribute_group decoder_attribute_group = { +- .name = "rc6_decoder", +- .attrs = decoder_attributes, +-}; +- +-static enum rc6_mode rc6_mode(struct decoder_data *data) { + switch (data->header & RC6_MODE_MASK) { + case 0: + return RC6_MODE_0; +@@ -162,16 +77,12 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) { + */ + static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev) + { +- struct decoder_data *data; + struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); ++ struct rc6_dec *data = &ir_dev->raw->rc6; + u32 scancode; + u8 toggle; + +- data = get_decoder_data(ir_dev); +- if (!data) +- return -EINVAL; +- +- if (!data->enabled) ++ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6)) + return 0; + + if (IS_RESET(ev)) { +@@ -223,12 +134,11 @@ again: + if (ev.pulse) + data->header |= 1; + data->count++; +- data->prev_ev = ev; + data->state = STATE_HEADER_BIT_END; + return 0; + + case STATE_HEADER_BIT_END: +- if (!is_transition(&ev, &data->prev_ev)) ++ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) + break; + + if (data->count == RC6_HEADER_NBITS) +@@ -244,12 +154,11 @@ again: + break; + + data->toggle = ev.pulse; +- data->prev_ev = ev; + data->state = STATE_TOGGLE_END; + return 0; + + case STATE_TOGGLE_END: +- if (!is_transition(&ev, &data->prev_ev) || ++ if (!is_transition(&ev, &ir_dev->raw->prev_ev) || + !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2)) + break; + +@@ -259,7 +168,6 @@ again: + } + + data->state = STATE_BODY_BIT_START; +- data->prev_ev = ev; + decrease_duration(&ev, RC6_TOGGLE_END); + data->count = 0; + +@@ -291,13 +199,11 @@ again: + if (ev.pulse) + data->body |= 1; + data->count++; +- data->prev_ev = ev; +- + data->state = STATE_BODY_BIT_END; + return 0; + + case STATE_BODY_BIT_END: +- if (!is_transition(&ev, &data->prev_ev)) ++ if (!is_transition(&ev, &ir_dev->raw->prev_ev)) + break; + + if (data->count == data->wanted_bits) +@@ -348,54 +254,9 @@ out: + return -EINVAL; + } + +-static int ir_rc6_register(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- struct decoder_data *data; +- int rc; +- +- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- if (rc < 0) +- return rc; +- +- data = kzalloc(sizeof(*data), GFP_KERNEL); +- if (!data) { +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- return -ENOMEM; +- } +- +- data->ir_dev = ir_dev; +- data->enabled = 1; +- +- spin_lock(&decoder_lock); +- list_add_tail(&data->list, &decoder_list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- +-static int ir_rc6_unregister(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- static struct decoder_data *data; +- +- data = get_decoder_data(ir_dev); +- if (!data) +- return 0; +- +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- +- spin_lock(&decoder_lock); +- list_del(&data->list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- + static struct ir_raw_handler rc6_handler = { ++ .protocols = IR_TYPE_RC6, + .decode = ir_rc6_decode, +- .raw_register = ir_rc6_register, +- .raw_unregister = ir_rc6_unregister, + }; + + static int __init ir_rc6_decode_init(void) +diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/IR/ir-sony-decoder.c +index 9f440c5..b9074f0 100644 +--- a/drivers/media/IR/ir-sony-decoder.c ++++ b/drivers/media/IR/ir-sony-decoder.c +@@ -23,10 +23,6 @@ + #define SONY_BIT_SPACE (1 * SONY_UNIT) + #define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */ + +-/* Used to register sony_decoder clients */ +-static LIST_HEAD(decoder_list); +-static DEFINE_SPINLOCK(decoder_lock); +- + enum sony_state { + STATE_INACTIVE, + STATE_HEADER_SPACE, +@@ -35,84 +31,6 @@ enum sony_state { + STATE_FINISHED, + }; + +-struct decoder_data { +- struct list_head list; +- struct ir_input_dev *ir_dev; +- int enabled:1; +- +- /* State machine control */ +- enum sony_state state; +- u32 sony_bits; +- unsigned count; +-}; +- +- +-/** +- * get_decoder_data() - gets decoder data +- * @input_dev: input device +- * +- * Returns the struct decoder_data that corresponds to a device +- */ +-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev) +-{ +- struct decoder_data *data = NULL; +- +- spin_lock(&decoder_lock); +- list_for_each_entry(data, &decoder_list, list) { +- if (data->ir_dev == ir_dev) +- break; +- } +- spin_unlock(&decoder_lock); +- return data; +-} +- +-static ssize_t store_enabled(struct device *d, +- struct device_attribute *mattr, +- const char *buf, +- size_t len) +-{ +- unsigned long value; +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (strict_strtoul(buf, 10, &value) || value > 1) +- return -EINVAL; +- +- data->enabled = value; +- +- return len; +-} +- +-static ssize_t show_enabled(struct device *d, +- struct device_attribute *mattr, char *buf) +-{ +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- struct decoder_data *data = get_decoder_data(ir_dev); +- +- if (!data) +- return -EINVAL; +- +- if (data->enabled) +- return sprintf(buf, "1\n"); +- else +- return sprintf(buf, "0\n"); +-} +- +-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled); +- +-static struct attribute *decoder_attributes[] = { +- &dev_attr_enabled.attr, +- NULL +-}; +- +-static struct attribute_group decoder_attribute_group = { +- .name = "sony_decoder", +- .attrs = decoder_attributes, +-}; +- + /** + * ir_sony_decode() - Decode one Sony pulse or space + * @input_dev: the struct input_dev descriptor of the device +@@ -122,16 +40,12 @@ static struct attribute_group decoder_attribute_group = { + */ + static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) + { +- struct decoder_data *data; + struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); ++ struct sony_dec *data = &ir_dev->raw->sony; + u32 scancode; + u8 device, subdevice, function; + +- data = get_decoder_data(ir_dev); +- if (!data) +- return -EINVAL; +- +- if (!data->enabled) ++ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY)) + return 0; + + if (IS_RESET(ev)) { +@@ -172,9 +86,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) + if (!ev.pulse) + break; + +- data->sony_bits <<= 1; ++ data->bits <<= 1; + if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2)) +- data->sony_bits |= 1; ++ data->bits |= 1; + else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2)) + break; + +@@ -208,19 +122,19 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) + + switch (data->count) { + case 12: +- device = bitrev8((data->sony_bits << 3) & 0xF8); ++ device = bitrev8((data->bits << 3) & 0xF8); + subdevice = 0; +- function = bitrev8((data->sony_bits >> 4) & 0xFE); ++ function = bitrev8((data->bits >> 4) & 0xFE); + break; + case 15: +- device = bitrev8((data->sony_bits >> 0) & 0xFF); ++ device = bitrev8((data->bits >> 0) & 0xFF); + subdevice = 0; +- function = bitrev8((data->sony_bits >> 7) & 0xFD); ++ function = bitrev8((data->bits >> 7) & 0xFD); + break; + case 20: +- device = bitrev8((data->sony_bits >> 5) & 0xF8); +- subdevice = bitrev8((data->sony_bits >> 0) & 0xFF); +- function = bitrev8((data->sony_bits >> 12) & 0xFE); ++ device = bitrev8((data->bits >> 5) & 0xF8); ++ subdevice = bitrev8((data->bits >> 0) & 0xFF); ++ function = bitrev8((data->bits >> 12) & 0xFE); + break; + default: + IR_dprintk(1, "Sony invalid bitcount %u\n", data->count); +@@ -241,54 +155,9 @@ out: + return -EINVAL; + } + +-static int ir_sony_register(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- struct decoder_data *data; +- int rc; +- +- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- if (rc < 0) +- return rc; +- +- data = kzalloc(sizeof(*data), GFP_KERNEL); +- if (!data) { +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- return -ENOMEM; +- } +- +- data->ir_dev = ir_dev; +- data->enabled = 1; +- +- spin_lock(&decoder_lock); +- list_add_tail(&data->list, &decoder_list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- +-static int ir_sony_unregister(struct input_dev *input_dev) +-{ +- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); +- static struct decoder_data *data; +- +- data = get_decoder_data(ir_dev); +- if (!data) +- return 0; +- +- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group); +- +- spin_lock(&decoder_lock); +- list_del(&data->list); +- spin_unlock(&decoder_lock); +- +- return 0; +-} +- + static struct ir_raw_handler sony_handler = { ++ .protocols = IR_TYPE_SONY, + .decode = ir_sony_decode, +- .raw_register = ir_sony_register, +- .raw_unregister = ir_sony_unregister, + }; + + static int __init ir_sony_decode_init(void) +diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c +index 2098dd1..a841e51 100644 +--- a/drivers/media/IR/ir-sysfs.c ++++ b/drivers/media/IR/ir-sysfs.c +@@ -34,122 +34,186 @@ static struct class ir_input_class = { + }; + + /** +- * show_protocol() - shows the current IR protocol ++ * show_protocols() - shows the current IR protocol(s) + * @d: the device descriptor + * @mattr: the device attribute struct (unused) + * @buf: a pointer to the output buffer + * +- * This routine is a callback routine for input read the IR protocol type. +- * it is trigged by reading /sys/class/rc/rc?/current_protocol. +- * It returns the protocol name, as understood by the driver. ++ * This routine is a callback routine for input read the IR protocol type(s). ++ * it is trigged by reading /sys/class/rc/rc?/protocols. ++ * It returns the protocol names of supported protocols. ++ * Enabled protocols are printed in brackets. + */ +-static ssize_t show_protocol(struct device *d, +- struct device_attribute *mattr, char *buf) ++static ssize_t show_protocols(struct device *d, ++ struct device_attribute *mattr, char *buf) + { +- char *s; + struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- u64 ir_type = ir_dev->rc_tab.ir_type; +- +- IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type); +- +- /* FIXME: doesn't support multiple protocols at the same time */ +- if (ir_type == IR_TYPE_UNKNOWN) +- s = "Unknown"; +- else if (ir_type == IR_TYPE_RC5) +- s = "rc-5"; +- else if (ir_type == IR_TYPE_NEC) +- s = "nec"; +- else if (ir_type == IR_TYPE_RC6) +- s = "rc6"; +- else if (ir_type == IR_TYPE_JVC) +- s = "jvc"; +- else if (ir_type == IR_TYPE_SONY) +- s = "sony"; +- else +- s = "other"; ++ u64 allowed, enabled; ++ char *tmp = buf; ++ ++ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { ++ enabled = ir_dev->rc_tab.ir_type; ++ allowed = ir_dev->props->allowed_protos; ++ } else { ++ enabled = ir_dev->raw->enabled_protocols; ++ allowed = ir_raw_get_allowed_protocols(); ++ } + +- return sprintf(buf, "%s\n", s); ++ IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n", ++ (long long)allowed, ++ (long long)enabled); ++ ++ if (allowed & enabled & IR_TYPE_UNKNOWN) ++ tmp += sprintf(tmp, "[unknown] "); ++ else if (allowed & IR_TYPE_UNKNOWN) ++ tmp += sprintf(tmp, "unknown "); ++ ++ if (allowed & enabled & IR_TYPE_RC5) ++ tmp += sprintf(tmp, "[rc5] "); ++ else if (allowed & IR_TYPE_RC5) ++ tmp += sprintf(tmp, "rc5 "); ++ ++ if (allowed & enabled & IR_TYPE_NEC) ++ tmp += sprintf(tmp, "[nec] "); ++ else if (allowed & IR_TYPE_NEC) ++ tmp += sprintf(tmp, "nec "); ++ ++ if (allowed & enabled & IR_TYPE_RC6) ++ tmp += sprintf(tmp, "[rc6] "); ++ else if (allowed & IR_TYPE_RC6) ++ tmp += sprintf(tmp, "rc6 "); ++ ++ if (allowed & enabled & IR_TYPE_JVC) ++ tmp += sprintf(tmp, "[jvc] "); ++ else if (allowed & IR_TYPE_JVC) ++ tmp += sprintf(tmp, "jvc "); ++ ++ if (allowed & enabled & IR_TYPE_SONY) ++ tmp += sprintf(tmp, "[sony] "); ++ else if (allowed & IR_TYPE_SONY) ++ tmp += sprintf(tmp, "sony "); ++ ++ if (allowed & enabled & IR_TYPE_LIRC) ++ tmp += sprintf(tmp, "[lirc] "); ++ else if (allowed & IR_TYPE_LIRC) ++ tmp += sprintf(tmp, "lirc "); ++ ++ if (tmp != buf) ++ tmp--; ++ *tmp = '\n'; ++ return tmp + 1 - buf; + } + + /** +- * store_protocol() - shows the current IR protocol ++ * store_protocols() - changes the current IR protocol(s) + * @d: the device descriptor + * @mattr: the device attribute struct (unused) + * @buf: a pointer to the input buffer + * @len: length of the input buffer + * + * This routine is a callback routine for changing the IR protocol type. +- * it is trigged by reading /sys/class/rc/rc?/current_protocol. +- * It changes the IR the protocol name, if the IR type is recognized +- * by the driver. +- * If an unknown protocol name is used, returns -EINVAL. ++ * It is trigged by writing to /sys/class/rc/rc?/protocols. ++ * Writing "+proto" will add a protocol to the list of enabled protocols. ++ * Writing "-proto" will remove a protocol from the list of enabled protocols. ++ * Writing "proto" will enable only "proto". ++ * Returns -EINVAL if an invalid protocol combination or unknown protocol name ++ * is used, otherwise @len. + */ +-static ssize_t store_protocol(struct device *d, +- struct device_attribute *mattr, +- const char *data, +- size_t len) ++static ssize_t store_protocols(struct device *d, ++ struct device_attribute *mattr, ++ const char *data, ++ size_t len) + { + struct ir_input_dev *ir_dev = dev_get_drvdata(d); +- u64 ir_type = 0; +- int rc = -EINVAL; ++ bool enable, disable; ++ const char *tmp; ++ u64 type; ++ u64 mask; ++ int rc; + unsigned long flags; +- char *buf; +- +- while ((buf = strsep((char **) &data, " \n")) != NULL) { +- if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5")) +- ir_type |= IR_TYPE_RC5; +- if (!strcasecmp(buf, "nec")) +- ir_type |= IR_TYPE_NEC; +- if (!strcasecmp(buf, "jvc")) +- ir_type |= IR_TYPE_JVC; +- if (!strcasecmp(buf, "sony")) +- ir_type |= IR_TYPE_SONY; ++ ++ tmp = skip_spaces(data); ++ ++ if (*tmp == '+') { ++ enable = true; ++ disable = false; ++ tmp++; ++ } else if (*tmp == '-') { ++ enable = false; ++ disable = true; ++ tmp++; ++ } else { ++ enable = false; ++ disable = false; + } + +- if (!ir_type) { ++ if (!strncasecmp(tmp, "unknown", 7)) { ++ tmp += 7; ++ mask = IR_TYPE_UNKNOWN; ++ } else if (!strncasecmp(tmp, "rc5", 3)) { ++ tmp += 3; ++ mask = IR_TYPE_RC5; ++ } else if (!strncasecmp(tmp, "nec", 3)) { ++ tmp += 3; ++ mask = IR_TYPE_NEC; ++ } else if (!strncasecmp(tmp, "rc6", 3)) { ++ tmp += 3; ++ mask = IR_TYPE_RC6; ++ } else if (!strncasecmp(tmp, "jvc", 3)) { ++ tmp += 3; ++ mask = IR_TYPE_JVC; ++ } else if (!strncasecmp(tmp, "sony", 4)) { ++ tmp += 4; ++ mask = IR_TYPE_SONY; ++ } else if (!strncasecmp(tmp, "lirc", 4)) { ++ tmp += 4; ++ mask = IR_TYPE_LIRC; ++ } else { + IR_dprintk(1, "Unknown protocol\n"); + return -EINVAL; + } + +- if (ir_dev->props && ir_dev->props->change_protocol) +- rc = ir_dev->props->change_protocol(ir_dev->props->priv, +- ir_type); +- +- if (rc < 0) { +- IR_dprintk(1, "Error setting protocol to %lld\n", +- (long long)ir_type); ++ tmp = skip_spaces(tmp); ++ if (*tmp != '\0') { ++ IR_dprintk(1, "Invalid trailing characters\n"); + return -EINVAL; + } + +- spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); +- ir_dev->rc_tab.ir_type = ir_type; +- spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); ++ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) ++ type = ir_dev->rc_tab.ir_type; ++ else ++ type = ir_dev->raw->enabled_protocols; + +- IR_dprintk(1, "Current protocol(s) is(are) %lld\n", +- (long long)ir_type); ++ if (enable) ++ type |= mask; ++ else if (disable) ++ type &= ~mask; ++ else ++ type = mask; + +- return len; +-} ++ if (ir_dev->props && ir_dev->props->change_protocol) { ++ rc = ir_dev->props->change_protocol(ir_dev->props->priv, ++ type); ++ if (rc < 0) { ++ IR_dprintk(1, "Error setting protocols to 0x%llx\n", ++ (long long)type); ++ return -EINVAL; ++ } ++ } + +-static ssize_t show_supported_protocols(struct device *d, +- struct device_attribute *mattr, char *buf) +-{ +- char *orgbuf = buf; +- struct ir_input_dev *ir_dev = dev_get_drvdata(d); ++ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { ++ spin_lock_irqsave(&ir_dev->rc_tab.lock, flags); ++ ir_dev->rc_tab.ir_type = type; ++ spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags); ++ } else { ++ ir_dev->raw->enabled_protocols = type; ++ } + +- /* FIXME: doesn't support multiple protocols at the same time */ +- if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN) +- buf += sprintf(buf, "unknown "); +- if (ir_dev->props->allowed_protos & IR_TYPE_RC5) +- buf += sprintf(buf, "rc-5 "); +- if (ir_dev->props->allowed_protos & IR_TYPE_NEC) +- buf += sprintf(buf, "nec "); +- if (buf == orgbuf) +- buf += sprintf(buf, "other "); + +- buf += sprintf(buf - 1, "\n"); ++ IR_dprintk(1, "Current protocol(s): 0x%llx\n", ++ (long long)type); + +- return buf - orgbuf; ++ return len; + } + + #define ADD_HOTPLUG_VAR(fmt, val...) \ +@@ -159,7 +223,7 @@ static ssize_t show_supported_protocols(struct device *d, + return err; \ + } while (0) + +-static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) ++static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) + { + struct ir_input_dev *ir_dev = dev_get_drvdata(device); + +@@ -174,34 +238,26 @@ static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env) + /* + * Static device attribute struct with the sysfs attributes for IR's + */ +-static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR, +- show_protocol, store_protocol); +- +-static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR, +- show_supported_protocols, NULL); ++static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR, ++ show_protocols, store_protocols); + +-static struct attribute *ir_hw_dev_attrs[] = { +- &dev_attr_protocol.attr, +- &dev_attr_supported_protocols.attr, ++static struct attribute *rc_dev_attrs[] = { ++ &dev_attr_protocols.attr, + NULL, + }; + +-static struct attribute_group ir_hw_dev_attr_grp = { +- .attrs = ir_hw_dev_attrs, ++static struct attribute_group rc_dev_attr_grp = { ++ .attrs = rc_dev_attrs, + }; + +-static const struct attribute_group *ir_hw_dev_attr_groups[] = { +- &ir_hw_dev_attr_grp, ++static const struct attribute_group *rc_dev_attr_groups[] = { ++ &rc_dev_attr_grp, + NULL + }; + + static struct device_type rc_dev_type = { +- .groups = ir_hw_dev_attr_groups, +- .uevent = ir_dev_uevent, +-}; +- +-static struct device_type ir_raw_dev_type = { +- .uevent = ir_dev_uevent, ++ .groups = rc_dev_attr_groups, ++ .uevent = rc_dev_uevent, + }; + + /** +@@ -221,12 +277,7 @@ int ir_register_class(struct input_dev *input_dev) + if (unlikely(devno < 0)) + return devno; + +- if (ir_dev->props) { +- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE) +- ir_dev->dev.type = &rc_dev_type; +- } else +- ir_dev->dev.type = &ir_raw_dev_type; +- ++ ir_dev->dev.type = &rc_dev_type; + ir_dev->dev.class = &ir_input_class; + ir_dev->dev.parent = input_dev->dev.parent; + dev_set_name(&ir_dev->dev, "rc%d", devno); +diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile +index aea649f..86d3d1f 100644 +--- a/drivers/media/IR/keymaps/Makefile ++++ b/drivers/media/IR/keymaps/Makefile +@@ -37,6 +37,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-kaiomy.o \ + rc-kworld-315u.o \ + rc-kworld-plus-tv-analog.o \ ++ rc-lirc.o \ + rc-manli.o \ + rc-msi-tvanywhere.o \ + rc-msi-tvanywhere-plus.o \ +@@ -57,6 +58,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-pv951.o \ + rc-rc5-hauppauge-new.o \ + rc-rc5-tv.o \ ++ rc-rc6-mce.o \ + rc-real-audio-220-32-keys.o \ + rc-tbs-nec.o \ + rc-terratec-cinergy-xs.o \ +diff --git a/drivers/media/IR/keymaps/rc-lirc.c b/drivers/media/IR/keymaps/rc-lirc.c +new file mode 100644 +index 0000000..43fcf90 +--- /dev/null ++++ b/drivers/media/IR/keymaps/rc-lirc.c +@@ -0,0 +1,41 @@ ++/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass ++ * all raw IR data to the lirc userspace decoder. ++ * ++ * Copyright (c) 2010 by Jarod Wilson ++ * ++ * 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 ++ ++static struct ir_scancode lirc[] = { ++ { }, ++}; ++ ++static struct rc_keymap lirc_map = { ++ .map = { ++ .scan = lirc, ++ .size = ARRAY_SIZE(lirc), ++ .ir_type = IR_TYPE_LIRC, ++ .name = RC_MAP_LIRC, ++ } ++}; ++ ++static int __init init_rc_map_lirc(void) ++{ ++ return ir_register_map(&lirc_map); ++} ++ ++static void __exit exit_rc_map_lirc(void) ++{ ++ ir_unregister_map(&lirc_map); ++} ++ ++module_init(init_rc_map_lirc) ++module_exit(exit_rc_map_lirc) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Jarod Wilson "); +diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c +new file mode 100644 +index 0000000..c6726a8 +--- /dev/null ++++ b/drivers/media/IR/keymaps/rc-rc6-mce.c +@@ -0,0 +1,105 @@ ++/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use ++ * with the Media Center Edition eHome Infrared Transceiver. ++ * ++ * Copyright (c) 2010 by Jarod Wilson ++ * ++ * 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 ++ ++static struct ir_scancode rc6_mce[] = { ++ { 0x800f0415, KEY_REWIND }, ++ { 0x800f0414, KEY_FASTFORWARD }, ++ { 0x800f041b, KEY_PREVIOUS }, ++ { 0x800f041a, KEY_NEXT }, ++ ++ { 0x800f0416, KEY_PLAY }, ++ { 0x800f0418, KEY_PAUSE }, ++ { 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 }, ++ ++ { 0x800f0401, KEY_NUMERIC_1 }, ++ { 0x800f0402, KEY_NUMERIC_2 }, ++ { 0x800f0403, KEY_NUMERIC_3 }, ++ { 0x800f0404, KEY_NUMERIC_4 }, ++ { 0x800f0405, KEY_NUMERIC_5 }, ++ { 0x800f0406, KEY_NUMERIC_6 }, ++ { 0x800f0407, KEY_NUMERIC_7 }, ++ { 0x800f0408, KEY_NUMERIC_8 }, ++ { 0x800f0409, KEY_NUMERIC_9 }, ++ { 0x800f0400, KEY_NUMERIC_0 }, ++ ++ { 0x800f041d, KEY_NUMERIC_STAR }, ++ { 0x800f041c, KEY_NUMERIC_POUND }, ++ ++ { 0x800f0446, KEY_TV }, ++ { 0x800f0447, KEY_AUDIO }, /* My Music */ ++ { 0x800f0448, KEY_PVR }, /* RecordedTV */ ++ { 0x800f0449, KEY_CAMERA }, ++ { 0x800f044a, KEY_VIDEO }, ++ { 0x800f0424, KEY_DVD }, ++ { 0x800f0425, KEY_TUNER }, /* LiveTV */ ++ { 0x800f0450, KEY_RADIO }, ++ ++ { 0x800f044c, KEY_LANGUAGE }, ++ { 0x800f0427, KEY_ZOOM }, /* Aspect */ ++ ++ { 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 }, ++ ++ { 0x800f040c, KEY_POWER }, ++ { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */ ++ ++}; ++ ++static struct rc_keymap rc6_mce_map = { ++ .map = { ++ .scan = rc6_mce, ++ .size = ARRAY_SIZE(rc6_mce), ++ .ir_type = IR_TYPE_RC6, ++ .name = RC_MAP_RC6_MCE, ++ } ++}; ++ ++static int __init init_rc_map_rc6_mce(void) ++{ ++ return ir_register_map(&rc6_mce_map); ++} ++ ++static void __exit exit_rc_map_rc6_mce(void) ++{ ++ ir_unregister_map(&rc6_mce_map); ++} ++ ++module_init(init_rc_map_rc6_mce) ++module_exit(exit_rc_map_rc6_mce) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Jarod Wilson "); +diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c +new file mode 100644 +index 0000000..899891b +--- /dev/null ++++ b/drivers/media/IR/lirc_dev.c +@@ -0,0 +1,764 @@ ++/* ++ * LIRC base driver ++ * ++ * by Artur Lipowski ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++static int debug; ++ ++#define IRCTL_DEV_NAME "BaseRemoteCtl" ++#define NOPLUG -1 ++#define LOGHEAD "lirc_dev (%s[%d]): " ++ ++static dev_t lirc_base_dev; ++ ++struct irctl { ++ struct lirc_driver d; ++ int attached; ++ int open; ++ ++ struct mutex irctl_lock; ++ struct lirc_buffer *buf; ++ unsigned int chunk_size; ++ ++ struct task_struct *task; ++ long jiffies_to_wait; ++ ++ struct cdev cdev; ++}; ++ ++static DEFINE_MUTEX(lirc_dev_lock); ++ ++static struct irctl *irctls[MAX_IRCTL_DEVICES]; ++ ++/* Only used for sysfs but defined to void otherwise */ ++static struct class *lirc_class; ++ ++/* helper function ++ * initializes the irctl structure ++ */ ++static void init_irctl(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) ++{ ++ dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); ++ ++ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); ++ ++ if (ir->buf != ir->d.rbuf) { ++ lirc_buffer_free(ir->buf); ++ kfree(ir->buf); ++ } ++ ir->buf = NULL; ++} ++ ++/* helper function ++ * reads key codes from driver and puts them into buffer ++ * returns 0 on success ++ */ ++static int add_to_buf(struct irctl *ir) ++{ ++ if (ir->d.add_to_buf) { ++ int res = -ENODATA; ++ int got_data = 0; ++ ++ /* ++ * service the device as long as it is returning ++ * data and we have space ++ */ ++get_data: ++ res = ir->d.add_to_buf(ir->d.data, ir->buf); ++ if (res == 0) { ++ got_data++; ++ goto get_data; ++ } ++ ++ if (res == -ENODEV) ++ kthread_stop(ir->task); ++ ++ return got_data ? 0 : res; ++ } ++ ++ return 0; ++} ++ ++/* main function of the polling thread ++ */ ++static int lirc_thread(void *irctl) ++{ ++ struct irctl *ir = irctl; ++ ++ dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n", ++ ir->d.name, ir->d.minor); ++ ++ do { ++ if (ir->open) { ++ if (ir->jiffies_to_wait) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(ir->jiffies_to_wait); ++ } ++ if (kthread_should_stop()) ++ break; ++ if (!add_to_buf(ir)) ++ wake_up_interruptible(&ir->buf->wait_poll); ++ } else { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ } ++ } while (!kthread_should_stop()); ++ ++ dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n", ++ ir->d.name, ir->d.minor); ++ ++ return 0; ++} ++ ++ ++static struct file_operations 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, ++ .open = lirc_dev_fop_open, ++ .release = lirc_dev_fop_close, ++}; ++ ++static int lirc_cdev_add(struct irctl *ir) ++{ ++ int retval; ++ struct lirc_driver *d = &ir->d; ++ ++ if (d->fops) { ++ cdev_init(&ir->cdev, d->fops); ++ ir->cdev.owner = d->owner; ++ } else { ++ cdev_init(&ir->cdev, &fops); ++ ir->cdev.owner = THIS_MODULE; ++ } ++ kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor); ++ ++ retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); ++ if (retval) ++ kobject_put(&ir->cdev.kobj); ++ ++ return retval; ++} ++ ++int lirc_register_driver(struct lirc_driver *d) ++{ ++ struct irctl *ir; ++ int minor; ++ int bytes_in_key; ++ unsigned int chunk_size; ++ unsigned int buffer_size; ++ int err; ++ ++ if (!d) { ++ printk(KERN_ERR "lirc_dev: lirc_register_driver: " ++ "driver pointer must be not NULL!\n"); ++ err = -EBADRQC; ++ 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", ++ MAX_IRCTL_DEVICES-1, d->minor); ++ err = -EBADRQC; ++ goto out; ++ } ++ ++ if (1 > d->code_length || (BUFLEN * 8) < d->code_length) { ++ dev_err(d->dev, "lirc_dev: lirc_register_driver: " ++ "code length in bits for minor (%d) " ++ "must be less than %d!\n", ++ d->minor, BUFLEN * 8); ++ err = -EBADRQC; ++ goto out; ++ } ++ ++ dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n", ++ d->sample_rate); ++ if (d->sample_rate) { ++ if (2 > d->sample_rate || HZ < d->sample_rate) { ++ dev_err(d->dev, "lirc_dev: lirc_register_driver: " ++ "sample_rate must be between 2 and %d!\n", HZ); ++ err = -EBADRQC; ++ goto out; ++ } ++ if (!d->add_to_buf) { ++ dev_err(d->dev, "lirc_dev: lirc_register_driver: " ++ "add_to_buf cannot be NULL when " ++ "sample_rate is set\n"); ++ err = -EBADRQC; ++ goto out; ++ } ++ } else if (!(d->fops && d->fops->read) && !d->rbuf) { ++ dev_err(d->dev, "lirc_dev: lirc_register_driver: " ++ "fops->read and rbuf cannot all be NULL!\n"); ++ err = -EBADRQC; ++ goto out; ++ } else if (!d->rbuf) { ++ if (!(d->fops && d->fops->read && d->fops->poll && ++ d->fops->unlocked_ioctl)) { ++ dev_err(d->dev, "lirc_dev: lirc_register_driver: " ++ "neither read, poll nor unlocked_ioctl can be NULL!\n"); ++ err = -EBADRQC; ++ goto out; ++ } ++ } ++ ++ mutex_lock(&lirc_dev_lock); ++ ++ minor = d->minor; ++ ++ if (minor < 0) { ++ /* find first free slot for driver */ ++ for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) ++ if (!irctls[minor]) ++ break; ++ if (MAX_IRCTL_DEVICES == minor) { ++ dev_err(d->dev, "lirc_dev: lirc_register_driver: " ++ "no free slots for drivers!\n"); ++ err = -ENOMEM; ++ goto out_lock; ++ } ++ } else if (irctls[minor]) { ++ dev_err(d->dev, "lirc_dev: lirc_register_driver: " ++ "minor (%d) just registered!\n", minor); ++ err = -EBUSY; ++ goto out_lock; ++ } ++ ++ ir = kzalloc(sizeof(struct irctl), GFP_KERNEL); ++ if (!ir) { ++ err = -ENOMEM; ++ goto out_lock; ++ } ++ init_irctl(ir); ++ irctls[minor] = ir; ++ d->minor = minor; ++ ++ if (d->sample_rate) { ++ ir->jiffies_to_wait = HZ / d->sample_rate; ++ } else { ++ /* it means - wait for external event in task queue */ ++ ir->jiffies_to_wait = 0; ++ } ++ ++ /* some safety check 8-) */ ++ d->name[sizeof(d->name)-1] = '\0'; ++ ++ bytes_in_key = BITS_TO_LONGS(d->code_length) + ++ (d->code_length % 8 ? 1 : 0); ++ buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; ++ chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; ++ ++ if (d->rbuf) { ++ ir->buf = d->rbuf; ++ } else { ++ ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); ++ if (!ir->buf) { ++ err = -ENOMEM; ++ goto out_lock; ++ } ++ err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); ++ if (err) { ++ kfree(ir->buf); ++ goto out_lock; ++ } ++ } ++ ir->chunk_size = ir->buf->chunk_size; ++ ++ if (d->features == 0) ++ 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, ++ "lirc%u", ir->d.minor); ++ ++ if (d->sample_rate) { ++ /* try to fire up polling thread */ ++ ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev"); ++ if (IS_ERR(ir->task)) { ++ dev_err(d->dev, "lirc_dev: lirc_register_driver: " ++ "cannot run poll thread for minor = %d\n", ++ d->minor); ++ err = -ECHILD; ++ goto out_sysfs; ++ } ++ } ++ ++ err = lirc_cdev_add(ir); ++ if (err) ++ goto out_sysfs; ++ ++ ir->attached = 1; ++ mutex_unlock(&lirc_dev_lock); ++ ++ dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", ++ ir->d.name, ir->d.minor); ++ return minor; ++ ++out_sysfs: ++ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); ++out_lock: ++ mutex_unlock(&lirc_dev_lock); ++out: ++ return err; ++} ++EXPORT_SYMBOL(lirc_register_driver); ++ ++int lirc_unregister_driver(int minor) ++{ ++ struct irctl *ir; ++ ++ 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); ++ return -EBADRQC; ++ } ++ ++ ir = irctls[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); ++ mutex_unlock(&lirc_dev_lock); ++ return -ENOENT; ++ } ++ ++ /* end up polling thread */ ++ if (ir->task) ++ kthread_stop(ir->task); ++ ++ dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", ++ ir->d.name, ir->d.minor); ++ ++ ir->attached = 0; ++ if (ir->open) { ++ dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", ++ ir->d.name, ir->d.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); ++ mutex_unlock(&ir->irctl_lock); ++ cdev_del(&ir->cdev); ++ } else { ++ cleanup(ir); ++ cdev_del(&ir->cdev); ++ kfree(ir); ++ irctls[minor] = NULL; ++ } ++ ++ mutex_unlock(&lirc_dev_lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lirc_unregister_driver); ++ ++int lirc_dev_fop_open(struct inode *inode, struct file *file) ++{ ++ struct irctl *ir; ++ int retval = 0; ++ ++ if (iminor(inode) >= MAX_IRCTL_DEVICES) { ++ printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n", ++ iminor(inode)); ++ return -ENODEV; ++ } ++ ++ if (mutex_lock_interruptible(&lirc_dev_lock)) ++ return -ERESTARTSYS; ++ ++ ir = irctls[iminor(inode)]; ++ if (!ir) { ++ retval = -ENODEV; ++ goto error; ++ } ++ file->private_data = ir; ++ ++ dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); ++ ++ if (ir->d.minor == NOPLUG) { ++ retval = -ENODEV; ++ goto error; ++ } ++ ++ if (ir->open) { ++ retval = -EBUSY; ++ goto error; ++ } ++ ++ if (try_module_get(ir->d.owner)) { ++ ++ir->open; ++ retval = ir->d.set_use_inc(ir->d.data); ++ ++ if (retval) { ++ module_put(ir->d.owner); ++ --ir->open; ++ } else { ++ lirc_buffer_clear(ir->buf); ++ } ++ if (ir->task) ++ wake_up_process(ir->task); ++ } ++ ++error: ++ if (ir) ++ dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n", ++ ir->d.name, ir->d.minor, retval); ++ ++ mutex_unlock(&lirc_dev_lock); ++ ++ return retval; ++} ++EXPORT_SYMBOL(lirc_dev_fop_open); ++ ++int lirc_dev_fop_close(struct inode *inode, struct file *file) ++{ ++ struct irctl *ir = irctls[iminor(inode)]; ++ ++ 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; ++ if (ir->attached) { ++ ir->d.set_use_dec(ir->d.data); ++ module_put(ir->d.owner); ++ } else { ++ cleanup(ir); ++ irctls[ir->d.minor] = NULL; ++ kfree(ir); ++ } ++ ++ mutex_unlock(&lirc_dev_lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lirc_dev_fop_close); ++ ++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; ++ ++ dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); ++ ++ if (!ir->attached) { ++ mutex_unlock(&ir->irctl_lock); ++ return POLLERR; ++ } ++ ++ poll_wait(file, &ir->buf->wait_poll, wait); ++ ++ if (ir->buf) ++ if (lirc_buffer_empty(ir->buf)) ++ ret = 0; ++ else ++ ret = POLLIN | POLLRDNORM; ++ else ++ ret = POLLERR; ++ ++ dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n", ++ ir->d.name, ir->d.minor, ret); ++ ++ return ret; ++} ++EXPORT_SYMBOL(lirc_dev_fop_poll); ++ ++long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ unsigned long mode; ++ int result = 0; ++ struct irctl *ir = file->private_data; ++ ++ dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", ++ ir->d.name, ir->d.minor, cmd); ++ ++ if (ir->d.minor == NOPLUG || !ir->attached) { ++ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", ++ ir->d.name, ir->d.minor); ++ return -ENODEV; ++ } ++ ++ mutex_lock(&ir->irctl_lock); ++ ++ switch (cmd) { ++ case LIRC_GET_FEATURES: ++ result = put_user(ir->d.features, (unsigned long *)arg); ++ break; ++ case LIRC_GET_REC_MODE: ++ if (!(ir->d.features & LIRC_CAN_REC_MASK)) { ++ result = -ENOSYS; ++ break; ++ } ++ ++ result = put_user(LIRC_REC2MODE ++ (ir->d.features & LIRC_CAN_REC_MASK), ++ (unsigned long *)arg); ++ break; ++ case LIRC_SET_REC_MODE: ++ if (!(ir->d.features & LIRC_CAN_REC_MASK)) { ++ result = -ENOSYS; ++ break; ++ } ++ ++ result = get_user(mode, (unsigned long *)arg); ++ if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) ++ result = -EINVAL; ++ /* ++ * FIXME: We should actually set the mode somehow but ++ * for now, lirc_serial doesn't support mode changing either ++ */ ++ break; ++ case LIRC_GET_LENGTH: ++ result = put_user(ir->d.code_length, (unsigned long *)arg); ++ break; ++ case LIRC_GET_MIN_TIMEOUT: ++ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || ++ ir->d.min_timeout == 0) { ++ result = -ENOSYS; ++ break; ++ } ++ ++ result = put_user(ir->d.min_timeout, (unsigned long *)arg); ++ break; ++ case LIRC_GET_MAX_TIMEOUT: ++ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || ++ ir->d.max_timeout == 0) { ++ result = -ENOSYS; ++ break; ++ } ++ ++ result = put_user(ir->d.max_timeout, (unsigned long *)arg); ++ break; ++ default: ++ result = -EINVAL; ++ } ++ ++ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n", ++ ir->d.name, ir->d.minor, result); ++ ++ mutex_unlock(&ir->irctl_lock); ++ ++ return result; ++} ++EXPORT_SYMBOL(lirc_dev_fop_ioctl); ++ ++ssize_t lirc_dev_fop_read(struct file *file, ++ char *buffer, ++ size_t length, ++ loff_t *ppos) ++{ ++ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; ++ unsigned char buf[ir->chunk_size]; ++ int ret = 0, written = 0; ++ DECLARE_WAITQUEUE(wait, current); ++ ++ dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); ++ ++ if (mutex_lock_interruptible(&ir->irctl_lock)) ++ return -ERESTARTSYS; ++ if (!ir->attached) { ++ mutex_unlock(&ir->irctl_lock); ++ return -ENODEV; ++ } ++ ++ if (length % ir->chunk_size) { ++ dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n", ++ ir->d.name, ir->d.minor); ++ mutex_unlock(&ir->irctl_lock); ++ return -EINVAL; ++ } ++ ++ /* ++ * we add ourselves to the task queue before buffer check ++ * to avoid losing scan code (in case when queue is awaken somewhere ++ * between while condition checking and scheduling) ++ */ ++ add_wait_queue(&ir->buf->wait_poll, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ /* ++ * while we didn't provide 'length' bytes, device is opened in blocking ++ * mode and 'copy_to_user' is happy, wait for data. ++ */ ++ while (written < length && ret == 0) { ++ if (lirc_buffer_empty(ir->buf)) { ++ /* According to the read(2) man page, 'written' can be ++ * returned as less than 'length', instead of blocking ++ * again, returning -EWOULDBLOCK, or returning ++ * -ERESTARTSYS */ ++ if (written) ++ break; ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EWOULDBLOCK; ++ break; ++ } ++ if (signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ break; ++ } ++ ++ mutex_unlock(&ir->irctl_lock); ++ schedule(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (mutex_lock_interruptible(&ir->irctl_lock)) { ++ ret = -ERESTARTSYS; ++ remove_wait_queue(&ir->buf->wait_poll, &wait); ++ set_current_state(TASK_RUNNING); ++ goto out_unlocked; ++ } ++ ++ if (!ir->attached) { ++ ret = -ENODEV; ++ break; ++ } ++ } else { ++ lirc_buffer_read(ir->buf, buf); ++ ret = copy_to_user((void *)buffer+written, buf, ++ ir->buf->chunk_size); ++ written += ir->buf->chunk_size; ++ } ++ } ++ ++ remove_wait_queue(&ir->buf->wait_poll, &wait); ++ set_current_state(TASK_RUNNING); ++ mutex_unlock(&ir->irctl_lock); ++ ++out_unlocked: ++ dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", ++ ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret); ++ ++ return ret ? ret : written; ++} ++EXPORT_SYMBOL(lirc_dev_fop_read); ++ ++void *lirc_get_pdata(struct file *file) ++{ ++ void *data = NULL; ++ ++ if (file && file->f_dentry && file->f_dentry->d_inode && ++ file->f_dentry->d_inode->i_rdev) { ++ struct irctl *ir; ++ ir = irctls[iminor(file->f_dentry->d_inode)]; ++ data = ir->d.data; ++ } ++ ++ return data; ++} ++EXPORT_SYMBOL(lirc_get_pdata); ++ ++ ++ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, ++ size_t length, loff_t *ppos) ++{ ++ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; ++ ++ dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); ++ ++ if (!ir->attached) ++ return -ENODEV; ++ ++ return -EINVAL; ++} ++EXPORT_SYMBOL(lirc_dev_fop_write); ++ ++ ++static int __init lirc_dev_init(void) ++{ ++ int retval; ++ ++ lirc_class = class_create(THIS_MODULE, "lirc"); ++ if (IS_ERR(lirc_class)) { ++ retval = PTR_ERR(lirc_class); ++ printk(KERN_ERR "lirc_dev: class_create failed\n"); ++ goto error; ++ } ++ ++ retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES, ++ IRCTL_DEV_NAME); ++ if (retval) { ++ class_destroy(lirc_class); ++ printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n"); ++ goto error; ++ } ++ ++ ++ printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, " ++ "major %d \n", MAJOR(lirc_base_dev)); ++ ++error: ++ return retval; ++} ++ ++ ++ ++static void __exit lirc_dev_exit(void) ++{ ++ class_destroy(lirc_class); ++ unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES); ++ printk(KERN_INFO "lirc_dev: module unloaded\n"); ++} ++ ++module_init(lirc_dev_init); ++module_exit(lirc_dev_exit); ++ ++MODULE_DESCRIPTION("LIRC base driver module"); ++MODULE_AUTHOR("Artur Lipowski"); ++MODULE_LICENSE("GPL"); ++ ++module_param(debug, bool, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(debug, "Enable debugging messages"); +diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c +new file mode 100644 +index 0000000..78bf7f7 +--- /dev/null ++++ b/drivers/media/IR/mceusb.c +@@ -0,0 +1,1143 @@ ++/* ++ * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers ++ * ++ * Copyright (c) 2010 by Jarod Wilson ++ * ++ * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan ++ * Conti, Martin Blatter and Daniel Melander, the latter of which was ++ * in turn also based on the lirc_atiusb driver by Paul Miller. The ++ * two mce drivers were merged into one by Jarod Wilson, with transmit ++ * support for the 1st-gen device added primarily by Patrick Calhoun, ++ * with a bit of tweaks by Jarod. Debugging improvements and proper ++ * support for what appears to be 3rd-gen hardware added by Jarod. ++ * Initial port from lirc driver to ir-core drivery by Jarod, based ++ * partially on a port to an earlier proposed IR infrastructure by ++ * Jon Smirl, which included enhancements and simplifications to the ++ * incoming IR buffer parsing routines. ++ * ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_VERSION "1.91" ++#define DRIVER_AUTHOR "Jarod Wilson " ++#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \ ++ "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 */ ++ ++/* 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 */ ++ ++ ++/* module parameters */ ++#ifdef CONFIG_USB_DEBUG ++static int debug = 1; ++#else ++static int debug; ++#endif ++ ++/* general constants */ ++#define SEND_FLAG_IN_PROGRESS 1 ++#define SEND_FLAG_COMPLETE 2 ++#define RECV_FLAG_IN_PROGRESS 3 ++#define RECV_FLAG_COMPLETE 4 ++ ++#define MCEUSB_RX 1 ++#define MCEUSB_TX 2 ++ ++#define VENDOR_PHILIPS 0x0471 ++#define VENDOR_SMK 0x0609 ++#define VENDOR_TATUNG 0x1460 ++#define VENDOR_GATEWAY 0x107b ++#define VENDOR_SHUTTLE 0x1308 ++#define VENDOR_SHUTTLE2 0x051c ++#define VENDOR_MITSUMI 0x03ee ++#define VENDOR_TOPSEED 0x1784 ++#define VENDOR_RICAVISION 0x179d ++#define VENDOR_ITRON 0x195d ++#define VENDOR_FIC 0x1509 ++#define VENDOR_LG 0x043e ++#define VENDOR_MICROSOFT 0x045e ++#define VENDOR_FORMOSA 0x147a ++#define VENDOR_FINTEK 0x1934 ++#define VENDOR_PINNACLE 0x2304 ++#define VENDOR_ECS 0x1019 ++#define VENDOR_WISTRON 0x0fb8 ++#define VENDOR_COMPRO 0x185b ++#define VENDOR_NORTHSTAR 0x04eb ++#define VENDOR_REALTEK 0x0bda ++#define VENDOR_TIVO 0x105a ++ ++static struct usb_device_id mceusb_dev_table[] = { ++ /* Original Microsoft MCE IR Transceiver (often HP-branded) */ ++ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, ++ /* Philips Infrared Transceiver - Sahara branded */ ++ { USB_DEVICE(VENDOR_PHILIPS, 0x0608) }, ++ /* Philips Infrared Transceiver - HP branded */ ++ { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, ++ /* Philips SRM5100 */ ++ { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, ++ /* Philips Infrared Transceiver - Omaura */ ++ { USB_DEVICE(VENDOR_PHILIPS, 0x060f) }, ++ /* Philips Infrared Transceiver - Spinel plus */ ++ { USB_DEVICE(VENDOR_PHILIPS, 0x0613) }, ++ /* Philips eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_PHILIPS, 0x0815) }, ++ /* Realtek MCE IR Receiver */ ++ { USB_DEVICE(VENDOR_REALTEK, 0x0161) }, ++ /* SMK/Toshiba G83C0004D410 */ ++ { USB_DEVICE(VENDOR_SMK, 0x031d) }, ++ /* SMK eHome Infrared Transceiver (Sony VAIO) */ ++ { USB_DEVICE(VENDOR_SMK, 0x0322) }, ++ /* bundled with Hauppauge PVR-150 */ ++ { USB_DEVICE(VENDOR_SMK, 0x0334) }, ++ /* SMK eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_SMK, 0x0338) }, ++ /* Tatung eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, ++ /* Shuttle eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) }, ++ /* Shuttle eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) }, ++ /* Gateway eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_GATEWAY, 0x3009) }, ++ /* Mitsumi */ ++ { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, ++ /* Topseed eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, ++ /* Topseed HP eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, ++ /* Topseed eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, ++ /* Topseed eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, ++ /* Topseed eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_TOPSEED, 0x000a) }, ++ /* Topseed eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_TOPSEED, 0x0011) }, ++ /* Ricavision internal Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, ++ /* Itron ione Libra Q-11 */ ++ { USB_DEVICE(VENDOR_ITRON, 0x7002) }, ++ /* FIC eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_FIC, 0x9242) }, ++ /* LG eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_LG, 0x9803) }, ++ /* Microsoft MCE Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) }, ++ /* Formosa eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_FORMOSA, 0xe015) }, ++ /* Formosa21 / eHome Infrared Receiver */ ++ { USB_DEVICE(VENDOR_FORMOSA, 0xe016) }, ++ /* Formosa aim / Trust MCE Infrared Receiver */ ++ { USB_DEVICE(VENDOR_FORMOSA, 0xe017) }, ++ /* Formosa Industrial Computing / Beanbag Emulation Device */ ++ { USB_DEVICE(VENDOR_FORMOSA, 0xe018) }, ++ /* Formosa21 / eHome Infrared Receiver */ ++ { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) }, ++ /* Formosa Industrial Computing AIM IR605/A */ ++ { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, ++ /* Formosa Industrial Computing */ ++ { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, ++ /* Fintek eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, ++ /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ ++ { USB_DEVICE(VENDOR_FINTEK, 0x0702) }, ++ /* Pinnacle Remote Kit */ ++ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, ++ /* Elitegroup Computer Systems IR */ ++ { USB_DEVICE(VENDOR_ECS, 0x0f38) }, ++ /* Wistron Corp. eHome Infrared Receiver */ ++ { USB_DEVICE(VENDOR_WISTRON, 0x0002) }, ++ /* Compro K100 */ ++ { USB_DEVICE(VENDOR_COMPRO, 0x3020) }, ++ /* Compro K100 v2 */ ++ { USB_DEVICE(VENDOR_COMPRO, 0x3082) }, ++ /* Northstar Systems, Inc. eHome Infrared Transceiver */ ++ { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, ++ /* TiVo PC IR Receiver */ ++ { USB_DEVICE(VENDOR_TIVO, 0x2000) }, ++ /* 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 */ ++ struct ir_input_dev *irdev; ++ struct ir_dev_props *props; ++ struct ir_raw_event rawir; ++ ++ /* core device bits */ ++ struct device *dev; ++ struct input_dev *idev; ++ ++ /* usb */ ++ struct usb_device *usbdev; ++ struct urb *urb_in; ++ struct usb_endpoint_descriptor *usb_ep_in; ++ struct usb_endpoint_descriptor *usb_ep_out; ++ ++ /* buffers and dma */ ++ unsigned char *buf_in; ++ unsigned int len_in; ++ u8 cmd; /* MCE command type */ ++ u8 rem; /* Remaining IR data bytes in packet */ ++ dma_addr_t dma_in; ++ dma_addr_t dma_out; ++ ++ struct { ++ u32 connected:1; ++ u32 tx_mask_inverted:1; ++ u32 microsoft_gen1:1; ++ u32 reserved:29; ++ } flags; ++ ++ /* transmit support */ ++ int send_flags; ++ u32 carrier; ++ unsigned char tx_mask; ++ ++ char name[128]; ++ char phys[64]; ++}; ++ ++/* ++ * MCE Device Command Strings ++ * Device command responses vary from device to device... ++ * - DEVICE_RESET resets the hardware to its default state ++ * - GET_REVISION fetches the hardware/software revision, common ++ * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42 ++ * - GET_CARRIER_FREQ gets the carrier mode and frequency of the ++ * device, with replies in the form of 9f 06 MM FF, where MM is 0-3, ++ * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is ++ * ((clk / frequency) - 1) ++ * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us, ++ * response in the form of 9f 0c msb lsb ++ * - GET_TX_BITMASK fetches the transmitter bitmask, replies in ++ * the form of 9f 08 bm, where bm is the bitmask ++ * - GET_RX_SENSOR fetches the RX sensor setting -- long-range ++ * general use one or short-range learning one, in the form of ++ * 9f 14 ss, where ss is either 01 for long-range or 02 for short ++ * - SET_CARRIER_FREQ sets a new carrier mode and frequency ++ * - SET_TX_BITMASK sets the transmitter bitmask ++ * - 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}; ++/* 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 void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, ++ 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; ++ ++ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ ++ if (ir->flags.microsoft_gen1 && !out) ++ idx = 2; ++ ++ if (len <= idx) ++ return; ++ ++ for (i = 0; i < len && i < USB_BUFLEN; i++) ++ snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF); ++ ++ dev_info(dev, "%sx data: %s (length=%d)\n", ++ (out ? "t" : "r"), codes, len); ++ ++ if (out) ++ strcpy(inout, "Request\0"); ++ else ++ strcpy(inout, "Got\0"); ++ ++ cmd = buf[idx] & 0xff; ++ subcmd = buf[idx + 1] & 0xff; ++ data1 = buf[idx + 2] & 0xff; ++ data2 = buf[idx + 3] & 0xff; ++ ++ switch (cmd) { ++ case 0x00: ++ if (subcmd == 0xff && data1 == 0xaa) ++ dev_info(dev, "Device reset requested\n"); ++ else ++ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", ++ cmd, subcmd); ++ break; ++ case 0xff: ++ switch (subcmd) { ++ case 0x0b: ++ 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]); ++ break; ++ case 0xaa: ++ dev_info(dev, "Device reset requested\n"); ++ break; ++ case 0xfe: ++ dev_info(dev, "Previous command not supported\n"); ++ break; ++ case 0x18: ++ case 0x1b: ++ default: ++ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", ++ cmd, subcmd); ++ break; ++ } ++ break; ++ case 0x9f: ++ switch (subcmd) { ++ case 0x03: ++ dev_info(dev, "Ping\n"); ++ break; ++ case 0x04: ++ dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", ++ data1, data2); ++ break; ++ case 0x06: ++ dev_info(dev, "%s carrier mode and freq of " ++ "0x%02x 0x%02x\n", inout, data1, data2); ++ break; ++ case 0x07: ++ dev_info(dev, "Get carrier mode and freq\n"); ++ break; ++ case 0x08: ++ dev_info(dev, "%s transmit blaster mask of 0x%02x\n", ++ inout, data1); ++ break; ++ case 0x0c: ++ /* 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: ++ dev_info(dev, "Get receive timeout\n"); ++ break; ++ case 0x13: ++ dev_info(dev, "Get transmit blaster mask\n"); ++ break; ++ case 0x14: ++ dev_info(dev, "%s %s-range receive sensor in use\n", ++ inout, data1 == 0x02 ? "short" : "long"); ++ break; ++ case 0x15: ++ 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: ++ dev_info(dev, "Error! Hardware is likely wedged...\n"); ++ break; ++ case 0x05: ++ case 0x09: ++ case 0x0f: ++ default: ++ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", ++ cmd, subcmd); ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void usb_async_callback(struct urb *urb, struct pt_regs *regs) ++{ ++ struct mceusb_dev *ir; ++ int len; ++ ++ if (!urb) ++ return; ++ ++ ir = urb->context; ++ if (ir) { ++ len = urb->actual_length; ++ ++ 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); ++ } ++ ++} ++ ++/* request incoming or send outgoing usb packet - used to initialize remote */ ++static void mce_request_packet(struct mceusb_dev *ir, ++ struct usb_endpoint_descriptor *ep, ++ unsigned char *data, int size, int urb_type) ++{ ++ int res; ++ struct urb *async_urb; ++ struct device *dev = ir->dev; ++ unsigned char *async_buf; ++ ++ if (urb_type == MCEUSB_TX) { ++ async_urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (unlikely(!async_urb)) { ++ dev_err(dev, "Error, couldn't allocate urb!\n"); ++ return; ++ } ++ ++ async_buf = kzalloc(size, GFP_KERNEL); ++ if (!async_buf) { ++ dev_err(dev, "Error, couldn't allocate buf!\n"); ++ usb_free_urb(async_urb); ++ return; ++ } ++ ++ /* outbound data */ ++ usb_fill_int_urb(async_urb, ir->usbdev, ++ usb_sndintpipe(ir->usbdev, ep->bEndpointAddress), ++ async_buf, size, (usb_complete_t) usb_async_callback, ++ ir, ep->bInterval); ++ memcpy(async_buf, data, size); ++ ++ } else if (urb_type == MCEUSB_RX) { ++ /* standard request */ ++ async_urb = ir->urb_in; ++ ir->send_flags = RECV_FLAG_IN_PROGRESS; ++ ++ } else { ++ dev_err(dev, "Error! Unknown urb type %d\n", urb_type); ++ return; ++ } ++ ++ dev_dbg(dev, "receive request called (size=%#x)\n", size); ++ ++ async_urb->transfer_buffer_length = size; ++ async_urb->dev = ir->usbdev; ++ ++ res = usb_submit_urb(async_urb, GFP_ATOMIC); ++ if (res) { ++ dev_dbg(dev, "receive request FAILED! (res=%d)\n", res); ++ return; ++ } ++ dev_dbg(dev, "receive request complete (res=%d)\n", res); ++} ++ ++static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) ++{ ++ mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_TX); ++} ++ ++static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) ++{ ++ mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX); ++} ++ ++/* Send data out the IR blaster port(s) */ ++static int mceusb_tx_ir(void *priv, int *txbuf, u32 n) ++{ ++ struct mceusb_dev *ir = priv; ++ int i, ret = 0; ++ int count, cmdcount = 0; ++ unsigned char *cmdbuf; /* MCE command buffer */ ++ long signal_duration = 0; /* Singnal length in us */ ++ struct timeval start_time, end_time; ++ ++ do_gettimeofday(&start_time); ++ ++ count = n / sizeof(int); ++ ++ cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL); ++ if (!cmdbuf) ++ return -ENOMEM; ++ ++ /* MCE tx init header */ ++ cmdbuf[cmdcount++] = MCE_CONTROL_HEADER; ++ cmdbuf[cmdcount++] = 0x08; ++ cmdbuf[cmdcount++] = ir->tx_mask; ++ ++ /* Generate mce packet data */ ++ for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { ++ signal_duration += txbuf[i]; ++ txbuf[i] = txbuf[i] / MCE_TIME_UNIT; ++ ++ do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ ++ ++ /* Insert mce packet header every 4th entry */ ++ if ((cmdcount < MCE_CMDBUF_SIZE) && ++ (cmdcount - MCE_TX_HEADER_LENGTH) % ++ MCE_CODE_LENGTH == 0) ++ cmdbuf[cmdcount++] = MCE_PACKET_HEADER; ++ ++ /* Insert mce packet data */ ++ if (cmdcount < MCE_CMDBUF_SIZE) ++ cmdbuf[cmdcount++] = ++ (txbuf[i] < MCE_PULSE_BIT ? ++ txbuf[i] : MCE_MAX_PULSE_LENGTH) | ++ (i & 1 ? 0x00 : MCE_PULSE_BIT); ++ else { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) && ++ (txbuf[i] -= MCE_MAX_PULSE_LENGTH)); ++ } ++ ++ /* 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; ++ ++ /* Check if we have room for the empty packet at the end */ ++ if (cmdcount >= MCE_CMDBUF_SIZE) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* All mce commands end with an empty packet (0x80) */ ++ cmdbuf[cmdcount++] = 0x80; ++ ++ /* Transmit the command to the mce device */ ++ mce_async_out(ir, cmdbuf, cmdcount); ++ ++ /* ++ * The lircd gap calculation expects the write function to ++ * wait the time it takes for the ircommand to be sent before ++ * it returns. ++ */ ++ do_gettimeofday(&end_time); ++ signal_duration -= (end_time.tv_usec - start_time.tv_usec) + ++ (end_time.tv_sec - start_time.tv_sec) * 1000000; ++ ++ /* delay with the closest number of ticks */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(usecs_to_jiffies(signal_duration)); ++ ++out: ++ kfree(cmdbuf); ++ return ret ? ret : n; ++} ++ ++/* Sets active IR outputs -- mce devices typically (all?) have two */ ++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; ++ else ++ ir->tx_mask = mask; ++ ++ return 0; ++} ++ ++/* Sets the send carrier frequency and mode */ ++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 }; ++ ++ /* Carrier has changed */ ++ if (ir->carrier != carrier) { ++ ++ if (carrier == 0) { ++ ir->carrier = carrier; ++ cmdbuf[2] = 0x01; ++ cmdbuf[3] = 0x80; ++ dev_dbg(ir->dev, "%s: disabling carrier " ++ "modulation\n", __func__); ++ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); ++ return carrier; ++ } ++ ++ for (prescaler = 0; prescaler < 4; ++prescaler) { ++ divisor = (clk >> (2 * prescaler)) / carrier; ++ if (divisor <= 0xFF) { ++ ir->carrier = carrier; ++ cmdbuf[2] = prescaler; ++ cmdbuf[3] = divisor; ++ dev_dbg(ir->dev, "%s: requesting %u HZ " ++ "carrier\n", __func__, carrier); ++ ++ /* Transmit new carrier to mce device */ ++ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); ++ return carrier; ++ } ++ } ++ ++ return -EINVAL; ++ ++ } ++ ++ return 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; ++ ++ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ ++ if (ir->flags.microsoft_gen1) ++ start_index = 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++) { ++ 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) ++ ir->rawir.duration += rawir.duration; ++ else { ++ ir->rawir.duration = rawir.duration; ++ ir->rawir.pulse = rawir.pulse; ++ } ++ continue; ++ } ++ rawir.duration += ir->rawir.duration; ++ ir->rawir.duration = 0; ++ ir->rawir.pulse = rawir.pulse; ++ ++ dev_dbg(ir->dev, "Storing %s with duration %d\n", ++ rawir.pulse ? "pulse" : "space", ++ rawir.duration); ++ ++ ir_raw_event_store(ir->idev, &rawir); ++ } ++ ++ 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); ++ } ++} ++ ++static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) ++{ ++ struct mceusb_dev *ir; ++ int buf_len; ++ ++ if (!urb) ++ return; ++ ++ ir = urb->context; ++ if (!ir) { ++ usb_unlink_urb(urb); ++ return; ++ } ++ ++ 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->irdev->dev, "setup answer received %d bytes\n", ++ buf_len); ++ } ++ ++ switch (urb->status) { ++ /* success */ ++ case 0: ++ mceusb_process_ir_data(ir, buf_len); ++ break; ++ ++ case -ECONNRESET: ++ case -ENOENT: ++ case -ESHUTDOWN: ++ usb_unlink_urb(urb); ++ return; ++ ++ case -EPIPE: ++ default: ++ break; ++ } ++ ++ usb_submit_urb(urb, GFP_ATOMIC); ++} ++ ++static void mceusb_gen1_init(struct mceusb_dev *ir) ++{ ++ int ret; ++ int maxp = ir->len_in; ++ struct device *dev = ir->dev; ++ char *data; ++ ++ data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL); ++ if (!data) { ++ dev_err(dev, "%s: memory allocation failed!\n", __func__); ++ return; ++ } ++ ++ /* ++ * This is a strange one. Windows issues a set address to the device ++ * on the receive control pipe and expect a certain value pair back ++ */ ++ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), ++ USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, ++ data, USB_CTRL_MSG_SZ, HZ * 3); ++ dev_dbg(dev, "%s - ret = %d\n", __func__, ret); ++ dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n", ++ __func__, data[0], data[1]); ++ ++ /* set feature: bit rate 38400 bps */ ++ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), ++ USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, ++ 0xc04e, 0x0000, NULL, 0, HZ * 3); ++ ++ dev_dbg(dev, "%s - ret = %d\n", __func__, ret); ++ ++ /* bRequest 4: set char length to 8 bits */ ++ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), ++ 4, USB_TYPE_VENDOR, ++ 0x0808, 0x0000, NULL, 0, HZ * 3); ++ dev_dbg(dev, "%s - retB = %d\n", __func__, ret); ++ ++ /* bRequest 2: set handshaking to use DTR/DSR */ ++ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), ++ 2, USB_TYPE_VENDOR, ++ 0x0000, 0x0100, NULL, 0, HZ * 3); ++ dev_dbg(dev, "%s - retC = %d\n", __func__, ret); ++ ++ /* device reset */ ++ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); ++ mce_sync_in(ir, NULL, maxp); ++ ++ /* get hw/sw revision? */ ++ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); ++ mce_sync_in(ir, NULL, maxp); ++ ++ kfree(data); ++}; ++ ++static void mceusb_gen2_init(struct mceusb_dev *ir) ++{ ++ int maxp = ir->len_in; ++ ++ /* device reset */ ++ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); ++ mce_sync_in(ir, NULL, maxp); ++ ++ /* get hw/sw revision? */ ++ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); ++ mce_sync_in(ir, NULL, maxp); ++ ++ /* unknown what the next two actually return... */ ++ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); ++ mce_sync_in(ir, NULL, maxp); ++ mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2)); ++ mce_sync_in(ir, NULL, maxp); ++} ++ ++static void mceusb_get_parameters(struct mceusb_dev *ir) ++{ ++ int maxp = ir->len_in; ++ ++ /* get the carrier and frequency */ ++ mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); ++ mce_sync_in(ir, NULL, maxp); ++ ++ /* get the transmitter bitmask */ ++ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); ++ mce_sync_in(ir, NULL, maxp); ++ ++ /* get receiver timeout value */ ++ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); ++ mce_sync_in(ir, NULL, maxp); ++ ++ /* get receiver sensor setting */ ++ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); ++ mce_sync_in(ir, NULL, maxp); ++} ++ ++static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) ++{ ++ struct input_dev *idev; ++ struct ir_dev_props *props; ++ struct ir_input_dev *irdev; ++ struct device *dev = ir->dev; ++ int ret = -ENODEV; ++ ++ idev = input_allocate_device(); ++ if (!idev) { ++ dev_err(dev, "remote input dev allocation failed\n"); ++ goto idev_alloc_failed; ++ } ++ ++ ret = -ENOMEM; ++ props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL); ++ if (!props) { ++ dev_err(dev, "remote ir dev props allocation failed\n"); ++ goto props_alloc_failed; ++ } ++ ++ irdev = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL); ++ if (!irdev) { ++ dev_err(dev, "remote ir input dev allocation failed\n"); ++ goto ir_dev_alloc_failed; ++ } ++ ++ snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome " ++ "Infrared Remote Transceiver (%04x:%04x)", ++ le16_to_cpu(ir->usbdev->descriptor.idVendor), ++ le16_to_cpu(ir->usbdev->descriptor.idProduct)); ++ ++ idev->name = ir->name; ++ usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys)); ++ strlcat(ir->phys, "/input0", sizeof(ir->phys)); ++ idev->phys = ir->phys; ++ ++ props->priv = ir; ++ props->driver_type = RC_DRIVER_IR_RAW; ++ props->allowed_protos = IR_TYPE_ALL; ++ props->s_tx_mask = mceusb_set_tx_mask; ++ props->s_tx_carrier = mceusb_set_tx_carrier; ++ props->tx_ir = mceusb_tx_ir; ++ ++ ir->props = props; ++ ir->irdev = irdev; ++ ++ input_set_drvdata(idev, irdev); ++ ++ ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME); ++ if (ret < 0) { ++ dev_err(dev, "remote input device register failed\n"); ++ goto irdev_failed; ++ } ++ ++ return idev; ++ ++irdev_failed: ++ kfree(irdev); ++ir_dev_alloc_failed: ++ kfree(props); ++props_alloc_failed: ++ input_free_device(idev); ++idev_alloc_failed: ++ return NULL; ++} ++ ++static int __devinit mceusb_dev_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ struct usb_device *dev = interface_to_usbdev(intf); ++ struct usb_host_interface *idesc; ++ struct usb_endpoint_descriptor *ep = NULL; ++ struct usb_endpoint_descriptor *ep_in = NULL; ++ struct usb_endpoint_descriptor *ep_out = NULL; ++ struct usb_host_config *config; ++ struct mceusb_dev *ir = NULL; ++ int pipe, maxp, i; ++ char buf[63], name[128] = ""; ++ bool is_gen3; ++ bool is_microsoft_gen1; ++ bool tx_mask_inverted; ++ ++ dev_dbg(&intf->dev, ": %s called\n", __func__); ++ ++ config = dev->actconfig; ++ 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; ++ ++ /* step through the endpoints to find first bulk in and out endpoint */ ++ for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { ++ ep = &idesc->endpoint[i].desc; ++ ++ if ((ep_in == NULL) ++ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ++ == USB_DIR_IN) ++ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ == USB_ENDPOINT_XFER_BULK) ++ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ == USB_ENDPOINT_XFER_INT))) { ++ ++ ep_in = ep; ++ ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; ++ ep_in->bInterval = 1; ++ dev_dbg(&intf->dev, ": acceptable inbound endpoint " ++ "found\n"); ++ } ++ ++ if ((ep_out == NULL) ++ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ++ == USB_DIR_OUT) ++ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ == USB_ENDPOINT_XFER_BULK) ++ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ == USB_ENDPOINT_XFER_INT))) { ++ ++ ep_out = ep; ++ ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; ++ ep_out->bInterval = 1; ++ dev_dbg(&intf->dev, ": acceptable outbound endpoint " ++ "found\n"); ++ } ++ } ++ if (ep_in == NULL) { ++ dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n"); ++ return -ENODEV; ++ } ++ ++ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress); ++ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); ++ ++ ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL); ++ if (!ir) ++ goto mem_alloc_fail; ++ ++ ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in); ++ if (!ir->buf_in) ++ goto buf_in_alloc_fail; ++ ++ ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); ++ if (!ir->urb_in) ++ goto urb_in_alloc_fail; ++ ++ ir->usbdev = dev; ++ ir->dev = &intf->dev; ++ ir->len_in = maxp; ++ ir->flags.microsoft_gen1 = is_microsoft_gen1; ++ ir->flags.tx_mask_inverted = tx_mask_inverted; ++ ++ /* Saving usb interface data for use by the transmitter routine */ ++ ir->usb_ep_in = ep_in; ++ ir->usb_ep_out = ep_out; ++ ++ if (dev->descriptor.iManufacturer ++ && usb_string(dev, dev->descriptor.iManufacturer, ++ buf, sizeof(buf)) > 0) ++ strlcpy(name, buf, sizeof(name)); ++ if (dev->descriptor.iProduct ++ && usb_string(dev, dev->descriptor.iProduct, ++ buf, sizeof(buf)) > 0) ++ snprintf(name + strlen(name), sizeof(name) - strlen(name), ++ " %s", buf); ++ ++ ir->idev = mceusb_init_input_dev(ir); ++ if (!ir->idev) ++ goto input_dev_fail; ++ ++ /* flush buffers on the device */ ++ mce_sync_in(ir, NULL, maxp); ++ mce_sync_in(ir, NULL, maxp); ++ ++ /* wire up inbound data handler */ ++ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, ++ maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); ++ ir->urb_in->transfer_dma = ir->dma_in; ++ ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ ++ /* initialize device */ ++ if (ir->flags.microsoft_gen1) ++ mceusb_gen1_init(ir); ++ else if (!is_gen3) ++ mceusb_gen2_init(ir); ++ ++ mceusb_get_parameters(ir); ++ ++ mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK); ++ ++ usb_set_intfdata(intf, ir); ++ ++ dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name, ++ dev->bus->busnum, dev->devnum); ++ ++ return 0; ++ ++ /* Error-handling path */ ++input_dev_fail: ++ usb_free_urb(ir->urb_in); ++urb_in_alloc_fail: ++ usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in); ++buf_in_alloc_fail: ++ kfree(ir); ++mem_alloc_fail: ++ dev_err(&intf->dev, "%s: device setup failed!\n", __func__); ++ ++ return -ENOMEM; ++} ++ ++ ++static void __devexit mceusb_dev_disconnect(struct usb_interface *intf) ++{ ++ struct usb_device *dev = interface_to_usbdev(intf); ++ struct mceusb_dev *ir = usb_get_intfdata(intf); ++ ++ usb_set_intfdata(intf, NULL); ++ ++ if (!ir) ++ return; ++ ++ ir->usbdev = NULL; ++ ir_input_unregister(ir->idev); ++ usb_kill_urb(ir->urb_in); ++ usb_free_urb(ir->urb_in); ++ usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); ++ ++ kfree(ir); ++} ++ ++static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message) ++{ ++ struct mceusb_dev *ir = usb_get_intfdata(intf); ++ dev_info(ir->dev, "suspend\n"); ++ usb_kill_urb(ir->urb_in); ++ return 0; ++} ++ ++static int mceusb_dev_resume(struct usb_interface *intf) ++{ ++ struct mceusb_dev *ir = usb_get_intfdata(intf); ++ dev_info(ir->dev, "resume\n"); ++ if (usb_submit_urb(ir->urb_in, GFP_ATOMIC)) ++ return -EIO; ++ return 0; ++} ++ ++static struct usb_driver mceusb_dev_driver = { ++ .name = DRIVER_NAME, ++ .probe = mceusb_dev_probe, ++ .disconnect = mceusb_dev_disconnect, ++ .suspend = mceusb_dev_suspend, ++ .resume = mceusb_dev_resume, ++ .reset_resume = mceusb_dev_resume, ++ .id_table = mceusb_dev_table ++}; ++ ++static int __init mceusb_dev_init(void) ++{ ++ int ret; ++ ++ ret = usb_register(&mceusb_dev_driver); ++ if (ret < 0) ++ printk(KERN_ERR DRIVER_NAME ++ ": usb register failed, result = %d\n", ret); ++ ++ return ret; ++} ++ ++static void __exit mceusb_dev_exit(void) ++{ ++ usb_deregister(&mceusb_dev_driver); ++} ++ ++module_init(mceusb_dev_init); ++module_exit(mceusb_dev_exit); ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_LICENSE("GPL"); ++MODULE_DEVICE_TABLE(usb, mceusb_dev_table); ++ ++module_param(debug, bool, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(debug, "Debug enabled or not"); +diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c +index b2e1545..7955e49 100644 +--- a/drivers/media/common/tuners/tda18271-fe.c ++++ b/drivers/media/common/tuners/tda18271-fe.c +@@ -1249,7 +1249,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct tda18271_config *cfg) + { + struct tda18271_priv *priv = NULL; +- int instance; ++ int instance, ret; + + mutex_lock(&tda18271_list_mutex); + +@@ -1268,10 +1268,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + priv->cal_initialized = false; + mutex_init(&priv->lock); + +- if (tda_fail(tda18271_get_id(fe))) ++ ret = tda18271_get_id(fe); ++ if (tda_fail(ret)) + goto fail; + +- if (tda_fail(tda18271_assign_map_layout(fe))) ++ ret = tda18271_assign_map_layout(fe); ++ if (tda_fail(ret)) + goto fail; + + mutex_lock(&priv->lock); +diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig +index f7b72a3..decdeda 100644 +--- a/drivers/media/dvb/mantis/Kconfig ++++ b/drivers/media/dvb/mantis/Kconfig +@@ -10,9 +10,15 @@ config MANTIS_CORE + config DVB_MANTIS + tristate "MANTIS based cards" + depends on MANTIS_CORE && DVB_CORE && PCI && I2C +- select DVB_MB86A16 +- select DVB_ZL10353 +- select DVB_STV0299 ++ select DVB_MB86A16 if !DVB_FE_CUSTOMISE ++ select DVB_ZL10353 if !DVB_FE_CUSTOMISE ++ select DVB_STV0299 if !DVB_FE_CUSTOMISE ++ select DVB_LNBP21 if !DVB_FE_CUSTOMISE ++ select DVB_STB0899 if !DVB_FE_CUSTOMISE ++ select DVB_STB6100 if !DVB_FE_CUSTOMISE ++ select DVB_TDA665x if !DVB_FE_CUSTOMISE ++ select DVB_TDA10021 if !DVB_FE_CUSTOMISE ++ select DVB_TDA10023 if !DVB_FE_CUSTOMISE + select DVB_PLL + help + Support for PCI cards based on the Mantis PCI bridge. +@@ -23,7 +29,7 @@ config DVB_MANTIS + config DVB_HOPPER + tristate "HOPPER based cards" + depends on MANTIS_CORE && DVB_CORE && PCI && I2C +- select DVB_ZL10353 ++ select DVB_ZL10353 if !DVB_FE_CUSTOMISE + select DVB_PLL + help + Support for PCI cards based on the Hopper PCI bridge. +diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c +index 3d4e466..a99489b 100644 +--- a/drivers/media/dvb/mantis/mantis_input.c ++++ b/drivers/media/dvb/mantis/mantis_input.c +@@ -19,7 +19,7 @@ + */ + + #include +-#include ++#include + #include + + #include "dmxdev.h" +@@ -104,7 +104,6 @@ EXPORT_SYMBOL_GPL(ir_mantis); + int mantis_input_init(struct mantis_pci *mantis) + { + struct input_dev *rc; +- struct ir_input_state rc_state; + char name[80], dev[80]; + int err; + +@@ -120,8 +119,6 @@ int mantis_input_init(struct mantis_pci *mantis) + rc->name = name; + rc->phys = dev; + +- ir_input_init(rc, &rc_state, IR_TYPE_OTHER); +- + rc->id.bustype = BUS_PCI; + rc->id.vendor = mantis->vendor_id; + rc->id.product = mantis->device_id; +diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c +index d639186..2014dae 100644 +--- a/drivers/media/video/cx23885/cx23885-cards.c ++++ b/drivers/media/video/cx23885/cx23885-cards.c +@@ -408,10 +408,18 @@ struct cx23885_subid cx23885_subids[] = { + .card = CX23885_BOARD_HAUPPAUGE_HVR1275, + }, { + .subvendor = 0x0070, ++ .subdevice = 0x221d, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1275, ++ }, { ++ .subvendor = 0x0070, + .subdevice = 0x2251, + .card = CX23885_BOARD_HAUPPAUGE_HVR1255, + }, { + .subvendor = 0x0070, ++ .subdevice = 0x2259, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1255, ++ }, { ++ .subvendor = 0x0070, + .subdevice = 0x2291, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { +@@ -419,6 +427,38 @@ struct cx23885_subid cx23885_subids[] = { + .subdevice = 0x2295, + .card = CX23885_BOARD_HAUPPAUGE_HVR1210, + }, { ++ .subvendor = 0x0070, ++ .subdevice = 0x2299, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, ++ }, { ++ .subvendor = 0x0070, ++ .subdevice = 0x229d, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ ++ }, { ++ .subvendor = 0x0070, ++ .subdevice = 0x22f0, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, ++ }, { ++ .subvendor = 0x0070, ++ .subdevice = 0x22f1, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1255, ++ }, { ++ .subvendor = 0x0070, ++ .subdevice = 0x22f2, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1275, ++ }, { ++ .subvendor = 0x0070, ++ .subdevice = 0x22f3, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ ++ }, { ++ .subvendor = 0x0070, ++ .subdevice = 0x22f4, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, ++ }, { ++ .subvendor = 0x0070, ++ .subdevice = 0x22f5, ++ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */ ++ }, { + .subvendor = 0x14f1, + .subdevice = 0x8651, + .card = CX23885_BOARD_MYGICA_X8506, +diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c +index 0dde57e..ff76f64 100644 +--- a/drivers/media/video/cx23885/cx23885-core.c ++++ b/drivers/media/video/cx23885/cx23885-core.c +@@ -1142,7 +1142,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) + + BUG_ON(in_interrupt()); + videobuf_waiton(&buf->vb, 0, 0); +- videobuf_dma_unmap(q, dma); ++ videobuf_dma_unmap(q->dev, dma); + videobuf_dma_free(dma); + btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +@@ -1953,8 +1953,12 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, + goto fail_irq; + } + +- err = request_irq(pci_dev->irq, cx23885_irq, +- IRQF_SHARED | IRQF_DISABLED, dev->name, dev); ++ if (!pci_enable_msi(pci_dev)) ++ err = request_irq(pci_dev->irq, cx23885_irq, ++ IRQF_DISABLED, dev->name, dev); ++ else ++ err = request_irq(pci_dev->irq, cx23885_irq, ++ IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", + dev->name, pci_dev->irq); +@@ -2000,6 +2004,7 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev) + + /* unregister stuff */ + free_irq(pci_dev->irq, dev); ++ pci_disable_msi(pci_dev); + + cx23885_dev_unregister(dev); + v4l2_device_unregister(v4l2_dev); +diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c +index 0a199d7..3d70af2 100644 +--- a/drivers/media/video/cx23885/cx23885-dvb.c ++++ b/drivers/media/video/cx23885/cx23885-dvb.c +@@ -991,7 +991,7 @@ static int dvb_register(struct cx23885_tsport *port) + ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, + &dev->pci->dev, adapter_nr, 0, + cx23885_dvb_fe_ioctl_override); +- if (!ret) ++ if (ret) + return ret; + + /* init CI & MAC */ +diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c +index 5de6ba9..d0b1613 100644 +--- a/drivers/media/video/cx23885/cx23885-input.c ++++ b/drivers/media/video/cx23885/cx23885-input.c +@@ -37,161 +37,55 @@ + + #include + #include +-#include ++#include + #include + + #include "cx23885.h" + +-#define RC5_BITS 14 +-#define RC5_HALF_BITS (2*RC5_BITS) +-#define RC5_HALF_BITS_MASK ((1 << RC5_HALF_BITS) - 1) +- +-#define RC5_START_BITS_NORMAL 0x3 /* Command range 0 - 63 */ +-#define RC5_START_BITS_EXTENDED 0x2 /* Command range 64 - 127 */ +- +-#define RC5_EXTENDED_COMMAND_OFFSET 64 +- + #define MODULE_NAME "cx23885" + +-static inline unsigned int rc5_command(u32 rc5_baseband) ++static void convert_measurement(u32 x, struct ir_raw_event *y) + { +- return RC5_INSTR(rc5_baseband) + +- ((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED) +- ? RC5_EXTENDED_COMMAND_OFFSET : 0); +-} +- +-static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev) +-{ +- struct card_ir *ir_input = dev->ir_input; +- unsigned int code, command; +- u32 rc5; +- +- /* Ignore codes that are too short to be valid RC-5 */ +- if (ir_input->last_bit < (RC5_HALF_BITS - 1)) +- return; +- +- /* The library has the manchester coding backwards; XOR to adapt. */ +- code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK; +- rc5 = ir_rc5_decode(code); +- +- switch (RC5_START(rc5)) { +- case RC5_START_BITS_NORMAL: +- break; +- case RC5_START_BITS_EXTENDED: +- /* Don't allow if the remote only emits standard commands */ +- if (ir_input->start == RC5_START_BITS_NORMAL) +- return; +- break; +- default: ++ if (x == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) { ++ y->pulse = false; ++ y->duration = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; + return; + } + +- if (ir_input->addr != RC5_ADDR(rc5)) +- return; +- +- /* Don't generate a keypress for RC-5 auto-repeated keypresses */ +- command = rc5_command(rc5); +- if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) || +- command != rc5_command(ir_input->last_rc5) || +- /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */ +- RC5_START(ir_input->last_rc5) == 0) { +- /* This keypress is differnet: not an auto repeat */ +- ir_input_nokey(ir_input->dev, &ir_input->ir); +- ir_input_keydown(ir_input->dev, &ir_input->ir, command); +- } +- ir_input->last_rc5 = rc5; +- +- /* Schedule when we should do the key up event: ir_input_nokey() */ +- mod_timer(&ir_input->timer_keyup, +- jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout)); ++ y->pulse = (x & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? true : false; ++ y->duration = x & V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; + } + +-static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev, +- u32 ns_pulse) ++static void cx23885_input_process_measurements(struct cx23885_dev *dev, ++ bool overrun) + { +- const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */ +- struct card_ir *ir_input = dev->ir_input; +- int i, level, quarterbits, halfbits; +- +- if (!ir_input->active) { +- ir_input->active = 1; +- /* assume an initial space that we may not detect or measure */ +- ir_input->code = 0; +- ir_input->last_bit = 0; +- } ++ struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir; ++ struct ir_raw_event kernel_ir_event; + +- if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) { +- ir_input->last_bit++; /* Account for the final space */ +- ir_input->active = 0; +- cx23885_input_process_raw_rc5(dev); +- return; +- } +- +- level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0; +- +- /* Skip any leading space to sync to the start bit */ +- if (ir_input->last_bit == 0 && level == 0) +- return; +- +- /* +- * With valid RC-5 we can get up to two consecutive half-bits in a +- * single pulse measurment. Experiments have shown that the duration +- * of a half-bit can vary. Make sure we always end up with an even +- * number of quarter bits at the same level (mark or space). +- */ +- ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS; +- quarterbits = ns_pulse / rc5_quarterbit_ns; +- if (quarterbits & 1) +- quarterbits++; +- halfbits = quarterbits / 2; +- +- for (i = 0; i < halfbits; i++) { +- ir_input->last_bit++; +- ir_input->code |= (level << ir_input->last_bit); +- +- if (ir_input->last_bit >= RC5_HALF_BITS-1) { +- ir_input->active = 0; +- cx23885_input_process_raw_rc5(dev); +- /* +- * If level is 1, a leading mark is invalid for RC5. +- * If level is 0, we scan past extra intial space. +- * Either way we don't want to reactivate collecting +- * marks or spaces here with any left over half-bits. +- */ +- break; +- } +- } +-} +- +-static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev, +- bool add_eom) +-{ +- struct card_ir *ir_input = dev->ir_input; +- struct ir_input_state *ir_input_state = &ir_input->ir; +- +- u32 ns_pulse[RC5_HALF_BITS+1]; +- ssize_t num = 0; ++ u32 sd_ir_data[64]; ++ ssize_t num; + int count, i; ++ bool handle = false; + + do { +- v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse, +- sizeof(ns_pulse), &num); ++ num = 0; ++ v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) sd_ir_data, ++ sizeof(sd_ir_data), &num); + + count = num / sizeof(u32); + +- /* Append an end of Rx seq, if the caller requested */ +- if (add_eom && count < ARRAY_SIZE(ns_pulse)) { +- ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END; +- count++; ++ for (i = 0; i < count; i++) { ++ convert_measurement(sd_ir_data[i], &kernel_ir_event); ++ ir_raw_event_store(kernel_ir->inp_dev, ++ &kernel_ir_event); ++ handle = true; + } +- +- /* Just drain the Rx FIFO, if we're called, but not RC-5 */ +- if (ir_input_state->ir_type != IR_TYPE_RC5) +- continue; +- +- for (i = 0; i < count; i++) +- cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]); + } while (num != 0); ++ ++ if (overrun) ++ ir_raw_event_reset(kernel_ir->inp_dev); ++ else if (handle) ++ ir_raw_event_handle(kernel_ir->inp_dev); + } + + void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) +@@ -230,7 +124,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) + } + + if (data_available) +- cx23885_input_process_pulse_widths_rc5(dev, overrun); ++ cx23885_input_process_measurements(dev, overrun); + + if (overrun) { + /* If there was a FIFO overrun, clear & restart the device */ +@@ -241,34 +135,15 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events) + } + } + +-static void cx23885_input_ir_start(struct cx23885_dev *dev) ++static int cx23885_input_ir_start(struct cx23885_dev *dev) + { +- struct card_ir *ir_input = dev->ir_input; +- struct ir_input_state *ir_input_state = &ir_input->ir; + struct v4l2_subdev_ir_parameters params; + + if (dev->sd_ir == NULL) +- return; ++ return -ENODEV; + + atomic_set(&dev->ir_input_stopping, 0); + +- /* keyup timer set up, if needed */ +- switch (dev->board) { +- case CX23885_BOARD_HAUPPAUGE_HVR1850: +- case CX23885_BOARD_HAUPPAUGE_HVR1290: +- setup_timer(&ir_input->timer_keyup, +- ir_rc5_timer_keyup, /* Not actually RC-5 specific */ +- (unsigned long) ir_input); +- if (ir_input_state->ir_type == IR_TYPE_RC5) { +- /* +- * RC-5 repeats a held key every +- * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms +- */ +- ir_input->rc5_key_timeout = 115; +- } +- break; +- } +- + v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms); + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1850: +@@ -299,11 +174,21 @@ static void cx23885_input_ir_start(struct cx23885_dev *dev) + break; + } + v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms); ++ return 0; ++} ++ ++static int cx23885_input_ir_open(void *priv) ++{ ++ struct cx23885_kernel_ir *kernel_ir = priv; ++ ++ if (kernel_ir->cx == NULL) ++ return -ENODEV; ++ ++ return cx23885_input_ir_start(kernel_ir->cx); + } + + static void cx23885_input_ir_stop(struct cx23885_dev *dev) + { +- struct card_ir *ir_input = dev->ir_input; + struct v4l2_subdev_ir_parameters params; + + if (dev->sd_ir == NULL) +@@ -327,21 +212,26 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev) + } + + flush_scheduled_work(); ++} + +- switch (dev->board) { +- case CX23885_BOARD_HAUPPAUGE_HVR1850: +- case CX23885_BOARD_HAUPPAUGE_HVR1290: +- del_timer_sync(&ir_input->timer_keyup); +- break; +- } ++static void cx23885_input_ir_close(void *priv) ++{ ++ struct cx23885_kernel_ir *kernel_ir = priv; ++ ++ if (kernel_ir->cx != NULL) ++ cx23885_input_ir_stop(kernel_ir->cx); + } + + int cx23885_input_init(struct cx23885_dev *dev) + { +- struct card_ir *ir; +- struct input_dev *input_dev; +- char *ir_codes = NULL; +- int ir_type, ir_addr, ir_start; ++ struct cx23885_kernel_ir *kernel_ir; ++ struct input_dev *inp_dev; ++ struct ir_dev_props *props; ++ ++ char *rc_map; ++ enum rc_driver_type driver_type; ++ unsigned long allowed_protos; ++ + int ret; + + /* +@@ -354,53 +244,59 @@ int cx23885_input_init(struct cx23885_dev *dev) + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1850: + case CX23885_BOARD_HAUPPAUGE_HVR1290: +- /* Parameters for the grey Hauppauge remote for the HVR-1850 */ +- ir_codes = RC_MAP_HAUPPAUGE_NEW; +- ir_type = IR_TYPE_RC5; +- ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */ +- ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */ ++ /* Integrated CX23888 IR controller */ ++ driver_type = RC_DRIVER_IR_RAW; ++ allowed_protos = IR_TYPE_ALL; ++ /* The grey Hauppauge RC-5 remote */ ++ rc_map = RC_MAP_RC5_HAUPPAUGE_NEW; + break; +- } +- if (ir_codes == NULL) ++ default: + return -ENODEV; +- +- ir = kzalloc(sizeof(*ir), GFP_KERNEL); +- input_dev = input_allocate_device(); +- if (!ir || !input_dev) { +- ret = -ENOMEM; +- goto err_out_free; + } + +- ir->dev = input_dev; +- ir->addr = ir_addr; +- ir->start = ir_start; ++ /* cx23885 board instance kernel IR state */ ++ kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL); ++ if (kernel_ir == NULL) ++ return -ENOMEM; + +- /* init input device */ +- snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)", +- cx23885_boards[dev->board].name); +- snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); ++ kernel_ir->cx = dev; ++ kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)", ++ cx23885_boards[dev->board].name); ++ kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0", ++ pci_name(dev->pci)); + +- ret = ir_input_init(input_dev, &ir->ir, ir_type); +- if (ret < 0) ++ /* input device */ ++ inp_dev = input_allocate_device(); ++ if (inp_dev == NULL) { ++ ret = -ENOMEM; + goto err_out_free; ++ } + +- input_dev->name = ir->name; +- input_dev->phys = ir->phys; +- input_dev->id.bustype = BUS_PCI; +- input_dev->id.version = 1; ++ kernel_ir->inp_dev = inp_dev; ++ inp_dev->name = kernel_ir->name; ++ inp_dev->phys = kernel_ir->phys; ++ inp_dev->id.bustype = BUS_PCI; ++ inp_dev->id.version = 1; + if (dev->pci->subsystem_vendor) { +- input_dev->id.vendor = dev->pci->subsystem_vendor; +- input_dev->id.product = dev->pci->subsystem_device; ++ inp_dev->id.vendor = dev->pci->subsystem_vendor; ++ inp_dev->id.product = dev->pci->subsystem_device; + } else { +- input_dev->id.vendor = dev->pci->vendor; +- input_dev->id.product = dev->pci->device; ++ inp_dev->id.vendor = dev->pci->vendor; ++ inp_dev->id.product = dev->pci->device; + } +- input_dev->dev.parent = &dev->pci->dev; +- +- dev->ir_input = ir; +- cx23885_input_ir_start(dev); +- +- ret = ir_input_register(ir->dev, ir_codes, NULL, MODULE_NAME); ++ inp_dev->dev.parent = &dev->pci->dev; ++ ++ /* kernel ir device properties */ ++ props = &kernel_ir->props; ++ props->driver_type = driver_type; ++ props->allowed_protos = allowed_protos; ++ props->priv = kernel_ir; ++ props->open = cx23885_input_ir_open; ++ props->close = cx23885_input_ir_close; ++ ++ /* Go */ ++ dev->kernel_ir = kernel_ir; ++ ret = ir_input_register(inp_dev, rc_map, props, MODULE_NAME); + if (ret) + goto err_out_stop; + +@@ -408,9 +304,12 @@ int cx23885_input_init(struct cx23885_dev *dev) + + err_out_stop: + cx23885_input_ir_stop(dev); +- dev->ir_input = NULL; ++ dev->kernel_ir = NULL; ++ /* TODO: double check clean-up of kernel_ir->inp_dev */ + err_out_free: +- kfree(ir); ++ kfree(kernel_ir->phys); ++ kfree(kernel_ir->name); ++ kfree(kernel_ir); + return ret; + } + +@@ -419,9 +318,11 @@ void cx23885_input_fini(struct cx23885_dev *dev) + /* Always stop the IR hardware from generating interrupts */ + cx23885_input_ir_stop(dev); + +- if (dev->ir_input == NULL) ++ if (dev->kernel_ir == NULL) + return; +- ir_input_unregister(dev->ir_input->dev); +- kfree(dev->ir_input); +- dev->ir_input = NULL; ++ ir_input_unregister(dev->kernel_ir->inp_dev); ++ kfree(dev->kernel_ir->phys); ++ kfree(dev->kernel_ir->name); ++ kfree(dev->kernel_ir); ++ dev->kernel_ir = NULL; + } +diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c +index 9a677eb..6ceabd4 100644 +--- a/drivers/media/video/cx23885/cx23885-ir.c ++++ b/drivers/media/video/cx23885/cx23885-ir.c +@@ -53,7 +53,7 @@ void cx23885_ir_rx_work_handler(struct work_struct *work) + if (events == 0) + return; + +- if (dev->ir_input) ++ if (dev->kernel_ir) + cx23885_input_rx_work_handler(dev, events); + } + +diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h +index 8d6a55e..a33f2b7 100644 +--- a/drivers/media/video/cx23885/cx23885.h ++++ b/drivers/media/video/cx23885/cx23885.h +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + #include "btcx-risc.h" + #include "cx23885-reg.h" +@@ -304,6 +305,15 @@ struct cx23885_tsport { + void *port_priv; + }; + ++struct cx23885_kernel_ir { ++ struct cx23885_dev *cx; ++ char *name; ++ char *phys; ++ ++ struct input_dev *inp_dev; ++ struct ir_dev_props props; ++}; ++ + struct cx23885_dev { + atomic_t refcount; + struct v4l2_device v4l2_dev; +@@ -363,7 +373,7 @@ struct cx23885_dev { + struct work_struct ir_tx_work; + unsigned long ir_tx_notifications; + +- struct card_ir *ir_input; ++ struct cx23885_kernel_ir *kernel_ir; + atomic_t ir_input_stopping; + + /* V4l */ +diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c +index 2918a6e..e8416b7 100644 +--- a/drivers/media/video/cx88/cx88-cards.c ++++ b/drivers/media/video/cx88/cx88-cards.c +@@ -45,6 +45,10 @@ static unsigned int latency = UNSET; + module_param(latency,int,0444); + MODULE_PARM_DESC(latency,"pci latency timer"); + ++static int disable_ir; ++module_param(disable_ir, int, 0444); ++MODULE_PARM_DESC(latency, "Disable IR support"); ++ + #define info_printk(core, fmt, arg...) \ + printk(KERN_INFO "%s: " fmt, core->name , ## arg) + +@@ -3498,7 +3502,10 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) + } + + cx88_card_setup(core); +- cx88_ir_init(core, pci); ++ if (!disable_ir) { ++ cx88_i2c_init_ir(core); ++ cx88_ir_init(core, pci); ++ } + + return core; + } +diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c +index fb39f11..375ad53 100644 +--- a/drivers/media/video/cx88/cx88-i2c.c ++++ b/drivers/media/video/cx88/cx88-i2c.c +@@ -181,6 +181,11 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) + } else + printk("%s: i2c register FAILED\n", core->name); + ++ return core->i2c_rc; ++} ++ ++void cx88_i2c_init_ir(struct cx88_core *core) ++{ + /* Instantiate the IR receiver device, if present */ + if (0 == core->i2c_rc) { + struct i2c_board_info info; +@@ -207,7 +212,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) + } + } + } +- return core->i2c_rc; + } + + /* ----------------------------------------------------------------------- */ +diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c +index e185289..eccc5e4 100644 +--- a/drivers/media/video/cx88/cx88-input.c ++++ b/drivers/media/video/cx88/cx88-input.c +@@ -30,6 +30,7 @@ + #include + + #include "cx88.h" ++#include + #include + + #define MODULE_NAME "cx88xx" +@@ -39,8 +40,8 @@ + struct cx88_IR { + struct cx88_core *core; + struct input_dev *input; +- struct ir_input_state ir; + struct ir_dev_props props; ++ u64 ir_type; + + int users; + +@@ -51,7 +52,6 @@ struct cx88_IR { + u32 sampling; + u32 samples[16]; + int scount; +- unsigned long release; + + /* poll external decoder */ + int polling; +@@ -125,29 +125,21 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) + + data = (data << 4) | ((gpio_key & 0xf0) >> 4); + +- ir_input_keydown(ir->input, &ir->ir, data); +- ir_input_nokey(ir->input, &ir->ir); ++ ir_keydown(ir->input, data, 0); + + } else if (ir->mask_keydown) { + /* bit set on keydown */ +- if (gpio & ir->mask_keydown) { +- ir_input_keydown(ir->input, &ir->ir, data); +- } else { +- ir_input_nokey(ir->input, &ir->ir); +- } ++ if (gpio & ir->mask_keydown) ++ ir_keydown(ir->input, data, 0); + + } else if (ir->mask_keyup) { + /* bit cleared on keydown */ +- if (0 == (gpio & ir->mask_keyup)) { +- ir_input_keydown(ir->input, &ir->ir, data); +- } else { +- ir_input_nokey(ir->input, &ir->ir); +- } ++ if (0 == (gpio & ir->mask_keyup)) ++ ir_keydown(ir->input, data, 0); + + } else { + /* can't distinguish keydown/up :-/ */ +- ir_input_keydown(ir->input, &ir->ir, data); +- ir_input_nokey(ir->input, &ir->ir); ++ ir_keydown(ir->input, data, 0); + } + } + +@@ -439,9 +431,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) + snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); + +- err = ir_input_init(input_dev, &ir->ir, ir_type); +- if (err < 0) +- goto err_out_free; ++ ir->ir_type = ir_type; + + input_dev->name = ir->name; + input_dev->phys = ir->phys; +@@ -516,8 +506,6 @@ void cx88_ir_irq(struct cx88_core *core) + } + if (!ir->scount) { + /* nothing to sample */ +- if (ir->ir.keypressed && time_after(jiffies, ir->release)) +- ir_input_nokey(ir->input, &ir->ir); + return; + } + +@@ -553,7 +541,7 @@ void cx88_ir_irq(struct cx88_core *core) + + if (ircode == 0) { /* key still pressed */ + ir_dprintk("pulse distance decoded repeat code\n"); +- ir->release = jiffies + msecs_to_jiffies(120); ++ ir_repeat(ir->input); + break; + } + +@@ -567,10 +555,8 @@ void cx88_ir_irq(struct cx88_core *core) + break; + } + +- ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f); +- +- ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f); +- ir->release = jiffies + msecs_to_jiffies(120); ++ ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0xff); ++ ir_keydown(ir->input, (ircode >> 16) & 0xff, 0); + break; + case CX88_BOARD_HAUPPAUGE: + case CX88_BOARD_HAUPPAUGE_DVB_T1: +@@ -606,16 +592,16 @@ void cx88_ir_irq(struct cx88_core *core) + if ( dev != 0x1e && dev != 0x1f ) + /* not a hauppauge remote */ + break; +- ir_input_keydown(ir->input, &ir->ir, code); +- ir->release = jiffies + msecs_to_jiffies(120); ++ ir_keydown(ir->input, code, toggle); + break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); + ir_dprintk("biphase decoded: %x\n", ircode); + if ((ircode & 0xfffff000) != 0x3000) + break; +- ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f); +- ir->release = jiffies + msecs_to_jiffies(120); ++ /* Note: bit 0x800 being the toggle is assumed, not checked ++ with real hardware */ ++ ir_keydown(ir->input, ircode & 0x3f, ircode & 0x0800 ? 1 : 0); + break; + } + +diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h +index bdb03d3..33d161a 100644 +--- a/drivers/media/video/cx88/cx88.h ++++ b/drivers/media/video/cx88/cx88.h +@@ -636,6 +636,7 @@ extern struct videobuf_queue_ops cx8800_vbi_qops; + /* cx88-i2c.c */ + + extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci); ++extern void cx88_i2c_init_ir(struct cx88_core *core); + + + /* ----------------------------------------------------------- */ +diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c +index 5c3fd94..6759cd5 100644 +--- a/drivers/media/video/em28xx/em28xx-input.c ++++ b/drivers/media/video/em28xx/em28xx-input.c +@@ -65,17 +65,14 @@ struct em28xx_ir_poll_result { + struct em28xx_IR { + struct em28xx *dev; + struct input_dev *input; +- struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* poll external decoder */ + int polling; + struct delayed_work work; +- unsigned int last_toggle:1; + unsigned int full_code:1; + unsigned int last_readcount; +- unsigned int repeat_interval; + + int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *); + +@@ -291,67 +288,39 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, + static void em28xx_ir_handle_key(struct em28xx_IR *ir) + { + int result; +- int do_sendkey = 0; + struct em28xx_ir_poll_result poll_result; + + /* read the registers containing the IR status */ + result = ir->get_key(ir, &poll_result); +- if (result < 0) { ++ if (unlikely(result < 0)) { + dprintk("ir->get_key() failed %d\n", result); + return; + } + +- dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x%02x\n", +- poll_result.toggle_bit, poll_result.read_count, +- ir->last_readcount, poll_result.rc_address, +- poll_result.rc_data[0]); +- +- if (ir->dev->chip_id == CHIP_ID_EM2874) { +- /* The em2874 clears the readcount field every time the +- register is read. The em2860/2880 datasheet says that it +- is supposed to clear the readcount, but it doesn't. So with +- the em2874, we are looking for a non-zero read count as +- opposed to a readcount that is incrementing */ +- ir->last_readcount = 0; +- } +- +- if (poll_result.read_count == 0) { +- /* The button has not been pressed since the last read */ +- } else if (ir->last_toggle != poll_result.toggle_bit) { +- /* A button has been pressed */ +- dprintk("button has been pressed\n"); +- ir->last_toggle = poll_result.toggle_bit; +- ir->repeat_interval = 0; +- do_sendkey = 1; +- } else if (poll_result.toggle_bit == ir->last_toggle && +- poll_result.read_count > 0 && +- poll_result.read_count != ir->last_readcount) { +- /* The button is still being held down */ +- dprintk("button being held down\n"); +- +- /* Debouncer for first keypress */ +- if (ir->repeat_interval++ > 9) { +- /* Start repeating after 1 second */ +- do_sendkey = 1; +- } +- } +- +- if (do_sendkey) { +- dprintk("sending keypress\n"); +- ++ if (unlikely(poll_result.read_count != ir->last_readcount)) { ++ dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__, ++ poll_result.toggle_bit, poll_result.read_count, ++ poll_result.rc_address, poll_result.rc_data[0]); + if (ir->full_code) +- ir_input_keydown(ir->input, &ir->ir, +- poll_result.rc_address << 8 | +- poll_result.rc_data[0]); ++ ir_keydown(ir->input, ++ poll_result.rc_address << 8 | ++ poll_result.rc_data[0], ++ poll_result.toggle_bit); + else +- ir_input_keydown(ir->input, &ir->ir, +- poll_result.rc_data[0]); +- +- ir_input_nokey(ir->input, &ir->ir); ++ ir_keydown(ir->input, ++ poll_result.rc_data[0], ++ poll_result.toggle_bit); ++ ++ if (ir->dev->chip_id == CHIP_ID_EM2874) ++ /* The em2874 clears the readcount field every time the ++ register is read. The em2860/2880 datasheet says that it ++ is supposed to clear the readcount, but it doesn't. So with ++ the em2874, we are looking for a non-zero read count as ++ opposed to a readcount that is incrementing */ ++ ir->last_readcount = 0; ++ else ++ ir->last_readcount = poll_result.read_count; + } +- +- ir->last_readcount = poll_result.read_count; +- return; + } + + static void em28xx_ir_work(struct work_struct *work) +@@ -466,11 +435,6 @@ int em28xx_ir_init(struct em28xx *dev) + usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); + strlcat(ir->phys, "/input0", sizeof(ir->phys)); + +- /* Set IR protocol */ +- err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER); +- if (err < 0) +- goto err_out_free; +- + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_USB; +diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c +index 20090e3..7b9ec6e 100644 +--- a/drivers/media/video/em28xx/em28xx-video.c ++++ b/drivers/media/video/em28xx/em28xx-video.c +@@ -654,12 +654,12 @@ static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb) + } + + if (buf != NULL && dev->capture_type == 2) { +- if (len > 4 && p[0] == 0x88 && p[1] == 0x88 && ++ if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 && + p[2] == 0x88 && p[3] == 0x88) { + p += 4; + len -= 4; + } +- if (len > 4 && p[0] == 0x22 && p[1] == 0x5a) { ++ if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) { + em28xx_isocdbg("Video frame %d, len=%i, %s\n", + p[2], len, (p[2] & 1) ? + "odd" : "even"); +diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h +index b252d1b..6216786 100644 +--- a/drivers/media/video/em28xx/em28xx.h ++++ b/drivers/media/video/em28xx/em28xx.h +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) + #include + #endif +diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c +index 830d47b..0cae5b8 100644 +--- a/drivers/media/video/hdpvr/hdpvr-core.c ++++ b/drivers/media/video/hdpvr/hdpvr-core.c +@@ -286,6 +286,8 @@ static int hdpvr_probe(struct usb_interface *interface, + goto error; + } + ++ dev->workqueue = 0; ++ + /* register v4l2_device early so it can be used for printks */ + if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) { + err("v4l2_device_register failed"); +@@ -380,6 +382,9 @@ static int hdpvr_probe(struct usb_interface *interface, + + error: + if (dev) { ++ /* Destroy single thread */ ++ if (dev->workqueue) ++ destroy_workqueue(dev->workqueue); + /* this frees allocated memory */ + hdpvr_delete(dev); + } +diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c +index 29d4397..27ae8bb 100644 +--- a/drivers/media/video/ir-kbd-i2c.c ++++ b/drivers/media/video/ir-kbd-i2c.c +@@ -47,7 +47,7 @@ + #include + #include + +-#include ++#include + #include + + /* ----------------------------------------------------------------------- */ +@@ -272,11 +272,8 @@ static void ir_key_poll(struct IR_i2c *ir) + return; + } + +- if (0 == rc) { +- ir_input_nokey(ir->input, &ir->ir); +- } else { +- ir_input_keydown(ir->input, &ir->ir, ir_key); +- } ++ if (rc) ++ ir_keydown(ir->input, ir_key, 0); + } + + static void ir_work(struct work_struct *work) +@@ -439,10 +436,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) + dev_name(&client->dev)); + + /* init + register input device */ +- err = ir_input_init(input_dev, &ir->ir, ir_type); +- if (err < 0) +- goto err_out_free; +- ++ ir->ir_type = ir_type; + input_dev->id.bustype = BUS_I2C; + input_dev->name = ir->name; + input_dev->phys = ir->phys; +diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c +index b482478..bba6115 100644 +--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c ++++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c +@@ -223,7 +223,10 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) + " pvr2_ioread_setup (setup) id=%p",cp); + pvr2_stream_kill(sp); + ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT); +- if (ret < 0) return ret; ++ if (ret < 0) { ++ mutex_unlock(&cp->mutex); ++ return ret; ++ } + for (idx = 0; idx < BUFFER_COUNT; idx++) { + bp = pvr2_stream_get_buffer(sp,idx); + pvr2_buffer_set_buffer(bp, +diff --git a/include/linux/input.h b/include/linux/input.h +index 6fcc910..fe2633c 100644 +--- a/include/linux/input.h ++++ b/include/linux/input.h +@@ -34,7 +34,7 @@ struct input_event { + * Protocol version. + */ + +-#define EV_VERSION 0x010000 ++#define EV_VERSION 0x010001 + + /* + * IOCTLs (0x00 - 0x7f) +@@ -56,12 +56,22 @@ struct input_absinfo { + __s32 resolution; + }; + ++struct keycode_table_entry { ++ __u32 keycode; /* e.g. KEY_A */ ++ __u32 index; /* Index for the given scan/key table, on EVIOCGKEYCODEBIG */ ++ __u32 len; /* Length of the scancode */ ++ __u32 reserved[2]; /* Reserved for future usage */ ++ char *scancode; /* scancode, in machine-endian */ ++}; ++ + #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ + #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ + #define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ + #define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */ + #define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */ + #define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */ ++#define EVIOCGKEYCODEBIG _IOR('E', 0x04, struct keycode_table_entry) /* get keycode */ ++#define EVIOCSKEYCODEBIG _IOW('E', 0x04, struct keycode_table_entry) /* set keycode */ + + #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ + #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ +@@ -1066,13 +1076,22 @@ struct ff_effect { + * @keycodemax: size of keycode table + * @keycodesize: size of elements in keycode table + * @keycode: map of scancodes to keycodes for this device +- * @setkeycode: optional method to alter current keymap, used to implement ++ * @setkeycode: optional legacy method to alter current keymap, used to ++ * implement sparse keymaps. Shouldn't be used on new drivers ++ * @getkeycode: optional legacy method to retrieve current keymap. ++ * Shouldn't be used on new drivers. ++ * @setkeycodebig: optional method to alter current keymap, used to implement + * sparse keymaps. If not supplied default mechanism will be used. + * The method is being called while holding event_lock and thus must + * not sleep +- * @getkeycode: optional method to retrieve current keymap. If not supplied +- * default mechanism will be used. The method is being called while +- * holding event_lock and thus must not sleep ++ * @getkeycodebig_from_index: optional method to retrieve current keymap from ++ * an array index. If not supplied default mechanism will be used. ++ * The method is being called while holding event_lock and thus must ++ * not sleep ++ * @getkeycodebig_from_scancode: optional method to retrieve current keymap ++ * from an scancode. If not supplied default mechanism will be used. ++ * The method is being called while holding event_lock and thus must ++ * not sleep + * @ff: force feedback structure associated with the device if device + * supports force feedback effects + * @repeat_key: stores key code of the last key pressed; used to implement +@@ -1147,6 +1166,12 @@ struct input_dev { + unsigned int scancode, unsigned int keycode); + int (*getkeycode)(struct input_dev *dev, + unsigned int scancode, unsigned int *keycode); ++ int (*setkeycodebig)(struct input_dev *dev, ++ struct keycode_table_entry *kt_entry); ++ int (*getkeycodebig_from_index)(struct input_dev *dev, ++ struct keycode_table_entry *kt_entry); ++ int (*getkeycodebig_from_scancode)(struct input_dev *dev, ++ struct keycode_table_entry *kt_entry); + + struct ff_device *ff; + +@@ -1422,6 +1447,10 @@ int input_get_keycode(struct input_dev *dev, + unsigned int scancode, unsigned int *keycode); + int input_set_keycode(struct input_dev *dev, + unsigned int scancode, unsigned int keycode); ++int input_get_keycode_big(struct input_dev *dev, ++ struct keycode_table_entry *kt_entry); ++int input_set_keycode_big(struct input_dev *dev, ++ struct keycode_table_entry *kt_entry); + + extern struct class input_class; + +diff --git a/include/media/ir-core.h b/include/media/ir-core.h +index ad1303f..513e60d 100644 +--- a/include/media/ir-core.h ++++ b/include/media/ir-core.h +@@ -47,15 +47,21 @@ enum rc_driver_type { + * is opened. + * @close: callback to allow drivers to disable polling/irq when IR input device + * is opened. ++ * @s_tx_mask: set transmitter mask (for devices with multiple tx outputs) ++ * @s_tx_carrier: set transmit carrier frequency ++ * @tx_ir: transmit IR + */ + struct ir_dev_props { + enum rc_driver_type driver_type; + unsigned long allowed_protos; + u32 scanmask; +- void *priv; ++ void *priv; + int (*change_protocol)(void *priv, u64 ir_type); + int (*open)(void *priv); + void (*close)(void *priv); ++ int (*s_tx_mask)(void *priv, u32 mask); ++ int (*s_tx_carrier)(void *priv, u32 carrier); ++ int (*tx_ir)(void *priv, int *txbuf, u32 n); + }; + + struct ir_input_dev { +diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h +index 0506e45..5e96d7a 100644 +--- a/include/media/ir-kbd-i2c.h ++++ b/include/media/ir-kbd-i2c.h +@@ -11,7 +11,7 @@ struct IR_i2c { + struct i2c_client *c; + struct input_dev *input; + struct ir_input_state ir; +- ++ u64 ir_type; + /* Used to avoid fast repeating */ + unsigned char old; + +diff --git a/include/media/lirc.h b/include/media/lirc.h +new file mode 100644 +index 0000000..42c467c +--- /dev/null ++++ b/include/media/lirc.h +@@ -0,0 +1,165 @@ ++/* ++ * lirc.h - linux infrared remote control header file ++ * last modified 2010/07/13 by Jarod Wilson ++ */ ++ ++#ifndef _LINUX_LIRC_H ++#define _LINUX_LIRC_H ++ ++#include ++#include ++ ++#define PULSE_BIT 0x01000000 ++#define PULSE_MASK 0x00FFFFFF ++ ++#define LIRC_MODE2_SPACE 0x00000000 ++#define LIRC_MODE2_PULSE 0x01000000 ++#define LIRC_MODE2_FREQUENCY 0x02000000 ++#define LIRC_MODE2_TIMEOUT 0x03000000 ++ ++#define LIRC_VALUE_MASK 0x00FFFFFF ++#define LIRC_MODE2_MASK 0xFF000000 ++ ++#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE) ++#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE) ++#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY) ++#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT) ++ ++#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK) ++#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK) ++ ++#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE) ++#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE) ++#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY) ++#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT) ++ ++/* used heavily by lirc userspace */ ++#define lirc_t int ++ ++/*** lirc compatible hardware features ***/ ++ ++#define LIRC_MODE2SEND(x) (x) ++#define LIRC_SEND2MODE(x) (x) ++#define LIRC_MODE2REC(x) ((x) << 16) ++#define LIRC_REC2MODE(x) ((x) >> 16) ++ ++#define LIRC_MODE_RAW 0x00000001 ++#define LIRC_MODE_PULSE 0x00000002 ++#define LIRC_MODE_MODE2 0x00000004 ++#define LIRC_MODE_LIRCCODE 0x00000010 ++ ++ ++#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW) ++#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE) ++#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2) ++#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE) ++ ++#define LIRC_CAN_SEND_MASK 0x0000003f ++ ++#define LIRC_CAN_SET_SEND_CARRIER 0x00000100 ++#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200 ++#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400 ++ ++#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW) ++#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE) ++#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2) ++#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE) ++ ++#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK) ++ ++#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16) ++#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16) ++ ++#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000 ++#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000 ++#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000 ++#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000 ++#define LIRC_CAN_SET_REC_FILTER 0x08000000 ++ ++#define LIRC_CAN_MEASURE_CARRIER 0x02000000 ++ ++#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK) ++#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK) ++ ++#define LIRC_CAN_NOTIFY_DECODE 0x01000000 ++ ++/*** IOCTL commands for lirc driver ***/ ++ ++#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32) ++ ++#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32) ++#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32) ++#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32) ++#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32) ++#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32) ++#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32) ++#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, __u32) ++ ++#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, __u32) ++#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, __u32) ++ ++#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, __u32) ++#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, __u32) ++#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, __u32) ++#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, __u32) ++ ++/* code length in bits, currently only for LIRC_MODE_LIRCCODE */ ++#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32) ++ ++#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32) ++#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32) ++/* Note: these can reset the according pulse_width */ ++#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32) ++#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32) ++#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32) ++#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32) ++#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, __u32) ++ ++/* ++ * when a timeout != 0 is set the driver will send a ++ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is ++ * never sent, timeout is disabled by default ++ */ ++#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, __u32) ++ ++/* 1 enables, 0 disables timeout reports in MODE2 */ ++#define LIRC_SET_REC_TIMEOUT_REPORTS _IOW('i', 0x00000019, __u32) ++ ++/* ++ * pulses shorter than this are filtered out by hardware (software ++ * emulation in lirc_dev?) ++ */ ++#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x0000001a, __u32) ++/* ++ * spaces shorter than this are filtered out by hardware (software ++ * emulation in lirc_dev?) ++ */ ++#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001b, __u32) ++/* ++ * if filter cannot be set independantly for pulse/space, this should ++ * be used ++ */ ++#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001c, __u32) ++ ++/* ++ * if enabled from the next key press on the driver will send ++ * LIRC_MODE2_FREQUENCY packets ++ */ ++#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32) ++ ++/* ++ * to set a range use ++ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the ++ * lower bound first and later ++ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound ++ */ ++ ++#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, __u32) ++#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32) ++ ++#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020) ++ ++#define LIRC_SETUP_START _IO('i', 0x00000021) ++#define LIRC_SETUP_END _IO('i', 0x00000022) ++ ++#endif +diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h +new file mode 100644 +index 0000000..b1f6066 +--- /dev/null ++++ b/include/media/lirc_dev.h +@@ -0,0 +1,225 @@ ++/* ++ * LIRC base driver ++ * ++ * by Artur Lipowski ++ * This code is licensed under GNU GPL ++ * ++ */ ++ ++#ifndef _LINUX_LIRC_DEV_H ++#define _LINUX_LIRC_DEV_H ++ ++#define MAX_IRCTL_DEVICES 4 ++#define BUFLEN 16 ++ ++#define mod(n, div) ((n) % (div)) ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct lirc_buffer { ++ wait_queue_head_t wait_poll; ++ spinlock_t fifo_lock; ++ unsigned int chunk_size; ++ unsigned int size; /* in chunks */ ++ /* Using chunks instead of bytes pretends to simplify boundary checking ++ * And should allow for some performance fine tunning later */ ++ struct kfifo fifo; ++ u8 fifo_initialized; ++}; ++ ++static inline void lirc_buffer_clear(struct lirc_buffer *buf) ++{ ++ unsigned long flags; ++ ++ if (buf->fifo_initialized) { ++ spin_lock_irqsave(&buf->fifo_lock, flags); ++ kfifo_reset(&buf->fifo); ++ spin_unlock_irqrestore(&buf->fifo_lock, flags); ++ } else ++ WARN(1, "calling %s on an uninitialized lirc_buffer\n", ++ __func__); ++} ++ ++static inline int lirc_buffer_init(struct lirc_buffer *buf, ++ unsigned int chunk_size, ++ unsigned int size) ++{ ++ int ret; ++ ++ init_waitqueue_head(&buf->wait_poll); ++ spin_lock_init(&buf->fifo_lock); ++ buf->chunk_size = chunk_size; ++ buf->size = size; ++ ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL); ++ if (ret == 0) ++ buf->fifo_initialized = 1; ++ ++ return ret; ++} ++ ++static inline void lirc_buffer_free(struct lirc_buffer *buf) ++{ ++ if (buf->fifo_initialized) { ++ kfifo_free(&buf->fifo); ++ buf->fifo_initialized = 0; ++ } else ++ WARN(1, "calling %s on an uninitialized lirc_buffer\n", ++ __func__); ++} ++ ++static inline int lirc_buffer_len(struct lirc_buffer *buf) ++{ ++ int len; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&buf->fifo_lock, flags); ++ len = kfifo_len(&buf->fifo); ++ spin_unlock_irqrestore(&buf->fifo_lock, flags); ++ ++ return len; ++} ++ ++static inline int lirc_buffer_full(struct lirc_buffer *buf) ++{ ++ return lirc_buffer_len(buf) == buf->size * buf->chunk_size; ++} ++ ++static inline int lirc_buffer_empty(struct lirc_buffer *buf) ++{ ++ return !lirc_buffer_len(buf); ++} ++ ++static inline int lirc_buffer_available(struct lirc_buffer *buf) ++{ ++ return buf->size - (lirc_buffer_len(buf) / buf->chunk_size); ++} ++ ++static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf, ++ unsigned char *dest) ++{ ++ unsigned int ret = 0; ++ ++ if (lirc_buffer_len(buf) >= buf->chunk_size) ++ ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size, ++ &buf->fifo_lock); ++ return ret; ++ ++} ++ ++static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, ++ unsigned char *orig) ++{ ++ unsigned int ret; ++ ++ ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size, ++ &buf->fifo_lock); ++ ++ return ret; ++} ++ ++struct lirc_driver { ++ char name[40]; ++ int minor; ++ unsigned long code_length; ++ unsigned int buffer_size; /* in chunks holding one code each */ ++ int sample_rate; ++ unsigned long features; ++ ++ unsigned int chunk_size; ++ ++ void *data; ++ int min_timeout; ++ int max_timeout; ++ int (*add_to_buf) (void *data, struct lirc_buffer *buf); ++ struct lirc_buffer *rbuf; ++ int (*set_use_inc) (void *data); ++ void (*set_use_dec) (void *data); ++ struct file_operations *fops; ++ struct device *dev; ++ struct module *owner; ++}; ++ ++/* name: ++ * this string will be used for logs ++ * ++ * minor: ++ * indicates minor device (/dev/lirc) number for registered driver ++ * if caller fills it with negative value, then the first free minor ++ * number will be used (if available) ++ * ++ * code_length: ++ * length of the remote control key code expressed in bits ++ * ++ * sample_rate: ++ * ++ * data: ++ * it may point to any driver data and this pointer will be passed to ++ * all callback functions ++ * ++ * add_to_buf: ++ * add_to_buf will be called after specified period of the time or ++ * triggered by the external event, this behavior depends on value of ++ * the sample_rate this function will be called in user context. This ++ * routine should return 0 if data was added to the buffer and ++ * -ENODATA if none was available. This should add some number of bits ++ * evenly divisible by code_length to the buffer ++ * ++ * rbuf: ++ * if not NULL, it will be used as a read buffer, you will have to ++ * write to the buffer by other means, like irq's (see also ++ * lirc_serial.c). ++ * ++ * set_use_inc: ++ * set_use_inc will be called after device is opened ++ * ++ * set_use_dec: ++ * set_use_dec will be called after device is closed ++ * ++ * fops: ++ * file_operations for drivers which don't fit the current driver model. ++ * ++ * Some ioctl's can be directly handled by lirc_dev if the driver's ++ * ioctl function is NULL or if it returns -ENOIOCTLCMD (see also ++ * lirc_serial.c). ++ * ++ * owner: ++ * the module owning this struct ++ * ++ */ ++ ++ ++/* following functions can be called ONLY from user context ++ * ++ * returns negative value on error or minor number ++ * of the registered device if success ++ * contents of the structure pointed by p is copied ++ */ ++extern int lirc_register_driver(struct lirc_driver *d); ++ ++/* returns negative value on error or 0 if success ++*/ ++extern int lirc_unregister_driver(int minor); ++ ++/* Returns the private data stored in the lirc_driver ++ * associated with the given device file pointer. ++ */ ++void *lirc_get_pdata(struct file *file); ++ ++/* default file operations ++ * used by drivers if they override only some operations ++ */ ++int lirc_dev_fop_open(struct inode *inode, struct file *file); ++int lirc_dev_fop_close(struct inode *inode, struct file *file); ++unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait); ++long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++ssize_t lirc_dev_fop_read(struct file *file, char *buffer, size_t length, ++ loff_t *ppos); ++ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, size_t length, ++ loff_t *ppos); ++ ++#endif +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index c78e99a..a329858 100644 +--- a/include/media/rc-map.h ++++ b/include/media/rc-map.h +@@ -17,8 +17,13 @@ + #define IR_TYPE_RC6 (1 << 2) /* Philips RC6 protocol */ + #define IR_TYPE_JVC (1 << 3) /* JVC protocol */ + #define IR_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */ ++#define IR_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */ + #define IR_TYPE_OTHER (1u << 31) + ++#define IR_TYPE_ALL (IR_TYPE_RC5 | IR_TYPE_NEC | IR_TYPE_RC6 | \ ++ IR_TYPE_JVC | IR_TYPE_SONY | IR_TYPE_LIRC | \ ++ IR_TYPE_OTHER) ++ + struct ir_scancode { + u32 scancode; + u32 keycode; +@@ -87,6 +92,7 @@ void rc_map_init(void); + #define RC_MAP_KAIOMY "rc-kaiomy" + #define RC_MAP_KWORLD_315U "rc-kworld-315u" + #define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog" ++#define RC_MAP_LIRC "rc-lirc" + #define RC_MAP_MANLI "rc-manli" + #define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus" + #define RC_MAP_MSI_TVANYWHERE "rc-msi-tvanywhere" +@@ -107,6 +113,7 @@ void rc_map_init(void); + #define RC_MAP_PV951 "rc-pv951" + #define RC_MAP_RC5_HAUPPAUGE_NEW "rc-rc5-hauppauge-new" + #define RC_MAP_RC5_TV "rc-rc5-tv" ++#define RC_MAP_RC6_MCE "rc-rc6-mce" + #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" + #define RC_MAP_TBS_NEC "rc-tbs-nec" + #define RC_MAP_TERRATEC_CINERGY_XS "rc-terratec-cinergy-xs" diff --git a/packages/linux/patches/014-linux-2.6.33-01-add_lirc_drivers-20100407-0.1.diff b/packages/linux/patches/lirc-staging-2.6.36.diff similarity index 65% rename from packages/linux/patches/014-linux-2.6.33-01-add_lirc_drivers-20100407-0.1.diff rename to packages/linux/patches/lirc-staging-2.6.36.diff index 4504de19e0..360ac45ab9 100644 --- a/packages/linux/patches/014-linux-2.6.33-01-add_lirc_drivers-20100407-0.1.diff +++ b/packages/linux/patches/lirc-staging-2.6.36.diff @@ -1,41 +1,76 @@ -diff -Naur linux-2.6.33.2/drivers/input/Kconfig linux-2.6.33.2.patch/drivers/input/Kconfig ---- linux-2.6.33.2/drivers/input/Kconfig 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/Kconfig 2010-04-07 22:05:13.550124631 +0200 -@@ -183,6 +183,8 @@ + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/lirc/Kconfig | 110 +++ + drivers/staging/lirc/Makefile | 19 + + drivers/staging/lirc/TODO | 8 + + drivers/staging/lirc/lirc_bt829.c | 383 +++++++++ + drivers/staging/lirc/lirc_ene0100.c | 646 ++++++++++++++ + drivers/staging/lirc/lirc_ene0100.h | 169 ++++ + drivers/staging/lirc/lirc_i2c.c | 536 ++++++++++++ + drivers/staging/lirc/lirc_igorplugusb.c | 555 ++++++++++++ + drivers/staging/lirc/lirc_imon.c | 1058 +++++++++++++++++++++++ + drivers/staging/lirc/lirc_it87.c | 1019 +++++++++++++++++++++++ + drivers/staging/lirc/lirc_it87.h | 116 +++ + drivers/staging/lirc/lirc_ite8709.c | 542 ++++++++++++ + drivers/staging/lirc/lirc_parallel.c | 705 ++++++++++++++++ + drivers/staging/lirc/lirc_parallel.h | 26 + + drivers/staging/lirc/lirc_sasem.c | 933 +++++++++++++++++++++ + drivers/staging/lirc/lirc_serial.c | 1313 +++++++++++++++++++++++++++++ + drivers/staging/lirc/lirc_sir.c | 1282 ++++++++++++++++++++++++++++ + drivers/staging/lirc/lirc_streamzap.c | 821 ++++++++++++++++++ + drivers/staging/lirc/lirc_ttusbir.c | 397 +++++++++ + drivers/staging/lirc/lirc_zilog.c | 1387 +++++++++++++++++++++++++++++++ + 22 files changed, 12028 insertions(+), 0 deletions(-) + +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 984a754..9296517 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -147,5 +147,7 @@ source "drivers/staging/mrst-touchscreen/Kconfig" - source "drivers/input/touchscreen/Kconfig" + source "drivers/staging/msm/Kconfig" -+source "drivers/input/lirc/Kconfig" ++source "drivers/staging/lirc/Kconfig" + - source "drivers/input/misc/Kconfig" - - endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/Kconfig linux-2.6.33.2.patch/drivers/input/lirc/Kconfig ---- linux-2.6.33.2/drivers/input/lirc/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/Kconfig 2010-04-07 22:05:13.551124752 +0200 -@@ -0,0 +1,116 @@ + endif # !STAGING_EXCLUDE_BUILD + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index 9fa2513..9e9b068 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -54,3 +54,4 @@ obj-$(CONFIG_ADIS16255) += adis16255/ + obj-$(CONFIG_FB_XGI) += xgifb/ + obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/ + obj-$(CONFIG_MSM_STAGING) += msm/ ++obj-$(CONFIG_LIRC_STAGING) += lirc/ +diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig +new file mode 100644 +index 0000000..968c2ad +--- /dev/null ++++ b/drivers/staging/lirc/Kconfig +@@ -0,0 +1,110 @@ +# +# LIRC driver(s) configuration +# -+menuconfig INPUT_LIRC -+ tristate "Linux Infrared Remote Control IR receiver/transmitter drivers" ++menuconfig LIRC_STAGING ++ bool "Linux Infrared Remote Control IR receiver/transmitter drivers" + help + Say Y here, and all supported Linux Infrared Remote Control IR and + RF receiver and transmitter drivers will be displayed. When paired + with a remote control and the lirc daemon, the receiver drivers + allow control of your Linux system via remote control. + -+if INPUT_LIRC ++if LIRC_STAGING + +config LIRC_BT829 + tristate "BT829 based hardware" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + Driver for the IR interface on BT829-based hardware + +config LIRC_ENE0100 + tristate "ENE KB3924/ENE0100 CIR Port Reciever" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + This is a driver for CIR port handled by ENE KB3924 embedded + controller found on some notebooks. @@ -43,20 +78,20 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/Kconfig linux-2.6.33.2.patch/driver + +config LIRC_I2C + tristate "I2C Based IR Receivers" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + Driver for I2C-based IR receivers, such as those commonly + found onboard Hauppauge PVR-150/250/350 video capture cards + +config LIRC_IGORPLUGUSB + tristate "Igor Cesko's USB IR Receiver" -+ depends on INPUT_LIRC && USB ++ depends on LIRC_STAGING && USB + help + Driver for Igor Cesko's USB IR Receiver + +config LIRC_IMON + tristate "Legacy SoundGraph iMON Receiver and Display" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + Driver for the original SoundGraph iMON IR Receiver and Display + @@ -64,37 +99,31 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/Kconfig linux-2.6.33.2.patch/driver + +config LIRC_IT87 + tristate "ITE IT87XX CIR Port Receiver" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + Driver for the ITE IT87xx IR Receiver + +config LIRC_ITE8709 + tristate "ITE8709 CIR Port Receiver" -+ depends on INPUT_LIRC && PNP ++ depends on LIRC_STAGING && PNP + help + Driver for the ITE8709 IR Receiver + -+config LIRC_MCEUSB -+ tristate "Windows Media Center Ed. USB IR Transceiver" -+ depends on INPUT_LIRC && USB -+ help -+ Driver for Windows Media Center Ed. USB IR Transceivers -+ +config LIRC_PARALLEL + tristate "Homebrew Parallel Port Receiver" -+ depends on INPUT_LIRC && !SMP ++ depends on LIRC_STAGING && !SMP + help + Driver for Homebrew Parallel Port Receivers + +config LIRC_SASEM + tristate "Sasem USB IR Remote" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module + +config LIRC_SERIAL + tristate "Homebrew Serial Port Receiver" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + Driver for Homebrew Serial Port Receivers + @@ -107,32 +136,73 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/Kconfig linux-2.6.33.2.patch/driver + +config LIRC_SIR + tristate "Built-in SIR IrDA port" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + Driver for the SIR IrDA port + +config LIRC_STREAMZAP + tristate "Streamzap PC Receiver" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + Driver for the Streamzap PC Receiver + +config LIRC_TTUSBIR + tristate "Technotrend USB IR Receiver" -+ depends on INPUT_LIRC && USB ++ depends on LIRC_STAGING && USB + help + Driver for the Technotrend USB IR Receiver + +config LIRC_ZILOG + tristate "Zilog/Hauppauge IR Transmitter" -+ depends on INPUT_LIRC ++ depends on LIRC_STAGING + help + Driver for the Zilog/Hauppauge IR Transmitter, found on + PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards +endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_bt829.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_bt829.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_bt829.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_bt829.c 2010-04-06 23:47:20.000000000 +0200 +diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile +new file mode 100644 +index 0000000..a019182 +--- /dev/null ++++ b/drivers/staging/lirc/Makefile +@@ -0,0 +1,19 @@ ++# Makefile for the lirc drivers. ++# ++ ++# Each configuration option enables a list of files. ++ ++obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o ++obj-$(CONFIG_LIRC_ENE0100) += lirc_ene0100.o ++obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o ++obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o ++obj-$(CONFIG_LIRC_IMON) += lirc_imon.o ++obj-$(CONFIG_LIRC_IT87) += lirc_it87.o ++obj-$(CONFIG_LIRC_ITE8709) += lirc_ite8709.o ++obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o ++obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o ++obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o ++obj-$(CONFIG_LIRC_SIR) += lirc_sir.o ++obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap.o ++obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o ++obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o +diff --git a/drivers/staging/lirc/TODO b/drivers/staging/lirc/TODO +new file mode 100644 +index 0000000..b6cb593 +--- /dev/null ++++ b/drivers/staging/lirc/TODO +@@ -0,0 +1,8 @@ ++- All drivers should either be ported to ir-core, or dropped entirely ++ (see drivers/media/IR/mceusb.c vs. lirc_mceusb.c in lirc cvs for an ++ example of a previously completed port). ++ ++Please send patches to: ++Jarod Wilson ++Greg Kroah-Hartman ++ +diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/lirc/lirc_bt829.c +new file mode 100644 +index 0000000..d0f34b5 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_bt829.c @@ -0,0 +1,383 @@ +/* + * Remote control driver for the TV-card based on bt829 @@ -162,7 +232,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_bt829.c linux-2.6.33.2.patch/d +#include +#include + -+#include "lirc_dev.h" ++#include + +static int poll_main(void); +static int atir_init_start(void); @@ -517,1095 +587,11 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_bt829.c linux-2.6.33.2.patch/d + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_dev.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_dev.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.c 2010-04-07 21:56:14.000000000 +0200 -@@ -0,0 +1,850 @@ -+/* -+ * LIRC base driver -+ * -+ * by Artur Lipowski -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef CONFIG_COMPAT -+#include -+#endif -+ -+#include -+#include "lirc_dev.h" -+ -+static int debug; -+ -+#define IRCTL_DEV_NAME "BaseRemoteCtl" -+#define NOPLUG -1 -+#define LOGHEAD "lirc_dev (%s[%d]): " -+ -+static dev_t lirc_base_dev; -+ -+struct irctl { -+ struct lirc_driver d; -+ int attached; -+ int open; -+ -+ struct mutex irctl_lock; -+ struct lirc_buffer *buf; -+ unsigned int chunk_size; -+ -+ struct task_struct *task; -+ long jiffies_to_wait; -+ -+ struct cdev cdev; -+}; -+ -+static DEFINE_MUTEX(lirc_dev_lock); -+ -+static struct irctl *irctls[MAX_IRCTL_DEVICES]; -+ -+/* Only used for sysfs but defined to void otherwise */ -+static struct class *lirc_class; -+ -+/* helper function -+ * initializes the irctl structure -+ */ -+static void init_irctl(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) -+{ -+ dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); -+ -+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); -+ -+ if (ir->buf != ir->d.rbuf) { -+ lirc_buffer_free(ir->buf); -+ kfree(ir->buf); -+ } -+ ir->buf = NULL; -+} -+ -+/* helper function -+ * reads key codes from driver and puts them into buffer -+ * returns 0 on success -+ */ -+static int add_to_buf(struct irctl *ir) -+{ -+ if (ir->d.add_to_buf) { -+ int res = -ENODATA; -+ int got_data = 0; -+ -+ /* -+ * service the device as long as it is returning -+ * data and we have space -+ */ -+get_data: -+ res = ir->d.add_to_buf(ir->d.data, ir->buf); -+ if (res == 0) { -+ got_data++; -+ goto get_data; -+ } -+ -+ if (res == -ENODEV) -+ kthread_stop(ir->task); -+ -+ return got_data ? 0 : res; -+ } -+ -+ return 0; -+} -+ -+/* main function of the polling thread -+ */ -+static int lirc_thread(void *irctl) -+{ -+ struct irctl *ir = irctl; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n", -+ ir->d.name, ir->d.minor); -+ -+ do { -+ if (ir->open) { -+ if (ir->jiffies_to_wait) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(ir->jiffies_to_wait); -+ } -+ if (kthread_should_stop()) -+ break; -+ if (!add_to_buf(ir)) -+ wake_up_interruptible(&ir->buf->wait_poll); -+ } else { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule(); -+ } -+ } while (!kthread_should_stop()); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n", -+ ir->d.name, ir->d.minor); -+ -+ return 0; -+} -+ -+ -+static struct file_operations fops = { -+ .owner = THIS_MODULE, -+ .read = lirc_dev_fop_read, -+ .write = lirc_dev_fop_write, -+ .poll = lirc_dev_fop_poll, -+ .ioctl = lirc_dev_fop_ioctl, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = lirc_dev_fop_compat_ioctl, -+#endif -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int lirc_cdev_add(struct irctl *ir) -+{ -+ int retval; -+ struct lirc_driver *d = &ir->d; -+ -+ if (d->fops) { -+ cdev_init(&ir->cdev, d->fops); -+ ir->cdev.owner = d->owner; -+ } else { -+ cdev_init(&ir->cdev, &fops); -+ ir->cdev.owner = THIS_MODULE; -+ } -+ kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor); -+ -+ retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); -+ if (retval) -+ kobject_put(&ir->cdev.kobj); -+ -+ return retval; -+} -+ -+int lirc_register_driver(struct lirc_driver *d) -+{ -+ struct irctl *ir; -+ int minor; -+ int bytes_in_key; -+ unsigned int chunk_size; -+ unsigned int buffer_size; -+ int err; -+ -+ if (!d) { -+ printk(KERN_ERR "lirc_dev: lirc_register_driver: " -+ "driver pointer must be not NULL!\n"); -+ err = -EBADRQC; -+ 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", -+ MAX_IRCTL_DEVICES-1, d->minor); -+ err = -EBADRQC; -+ goto out; -+ } -+ -+ if (1 > d->code_length || (BUFLEN * 8) < d->code_length) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "code length in bits for minor (%d) " -+ "must be less than %d!\n", -+ d->minor, BUFLEN * 8); -+ err = -EBADRQC; -+ goto out; -+ } -+ -+ dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n", -+ d->sample_rate); -+ if (d->sample_rate) { -+ if (2 > d->sample_rate || HZ < d->sample_rate) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "sample_rate must be between 2 and %d!\n", HZ); -+ err = -EBADRQC; -+ goto out; -+ } -+ if (!d->add_to_buf) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "add_to_buf cannot be NULL when " -+ "sample_rate is set\n"); -+ err = -EBADRQC; -+ goto out; -+ } -+ } else if (!(d->fops && d->fops->read) && !d->rbuf) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "fops->read and rbuf cannot all be NULL!\n"); -+ err = -EBADRQC; -+ goto out; -+ } else if (!d->rbuf) { -+ if (!(d->fops && d->fops->read && d->fops->poll && -+ d->fops->ioctl)) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "neither read, poll nor ioctl can be NULL!\n"); -+ err = -EBADRQC; -+ goto out; -+ } -+ } -+ -+ mutex_lock(&lirc_dev_lock); -+ -+ minor = d->minor; -+ -+ if (minor < 0) { -+ /* find first free slot for driver */ -+ for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) -+ if (!irctls[minor]) -+ break; -+ if (MAX_IRCTL_DEVICES == minor) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "no free slots for drivers!\n"); -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ } else if (irctls[minor]) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "minor (%d) just registered!\n", minor); -+ err = -EBUSY; -+ goto out_lock; -+ } -+ -+ ir = kzalloc(sizeof(struct irctl), GFP_KERNEL); -+ if (!ir) { -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ init_irctl(ir); -+ irctls[minor] = ir; -+ d->minor = minor; -+ -+ if (d->sample_rate) { -+ ir->jiffies_to_wait = HZ / d->sample_rate; -+ } else { -+ /* it means - wait for external event in task queue */ -+ ir->jiffies_to_wait = 0; -+ } -+ -+ /* some safety check 8-) */ -+ d->name[sizeof(d->name)-1] = '\0'; -+ -+ bytes_in_key = BITS_TO_LONGS(d->code_length) + -+ (d->code_length % 8 ? 1 : 0); -+ buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; -+ chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; -+ -+ if (d->rbuf) { -+ ir->buf = d->rbuf; -+ } else { -+ ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!ir->buf) { -+ err = -ENOMEM; -+ goto out_lock; -+ } -+ err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); -+ if (err) { -+ kfree(ir->buf); -+ goto out_lock; -+ } -+ } -+ ir->chunk_size = ir->buf->chunk_size; -+ -+ if (d->features == 0) -+ 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, -+ "lirc%u", ir->d.minor); -+ -+ if (d->sample_rate) { -+ /* try to fire up polling thread */ -+ ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev"); -+ if (IS_ERR(ir->task)) { -+ dev_err(d->dev, "lirc_dev: lirc_register_driver: " -+ "cannot run poll thread for minor = %d\n", -+ d->minor); -+ err = -ECHILD; -+ goto out_sysfs; -+ } -+ } -+ -+ err = lirc_cdev_add(ir); -+ if (err) -+ goto out_sysfs; -+ -+ ir->attached = 1; -+ mutex_unlock(&lirc_dev_lock); -+ -+ dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", -+ ir->d.name, ir->d.minor); -+ return minor; -+ -+out_sysfs: -+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); -+out_lock: -+ mutex_unlock(&lirc_dev_lock); -+out: -+ return err; -+} -+EXPORT_SYMBOL(lirc_register_driver); -+ -+int lirc_unregister_driver(int minor) -+{ -+ struct irctl *ir; -+ -+ 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); -+ return -EBADRQC; -+ } -+ -+ ir = irctls[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); -+ mutex_unlock(&lirc_dev_lock); -+ return -ENOENT; -+ } -+ -+ /* end up polling thread */ -+ if (ir->task) -+ kthread_stop(ir->task); -+ -+ dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", -+ ir->d.name, ir->d.minor); -+ -+ ir->attached = 0; -+ if (ir->open) { -+ dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", -+ ir->d.name, ir->d.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); -+ mutex_unlock(&ir->irctl_lock); -+ cdev_del(&ir->cdev); -+ } else { -+ cleanup(ir); -+ cdev_del(&ir->cdev); -+ kfree(ir); -+ irctls[minor] = NULL; -+ } -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lirc_unregister_driver); -+ -+int lirc_dev_fop_open(struct inode *inode, struct file *file) -+{ -+ struct irctl *ir; -+ int retval = 0; -+ -+ if (iminor(inode) >= MAX_IRCTL_DEVICES) { -+ printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n", -+ iminor(inode)); -+ return -ENODEV; -+ } -+ -+ if (mutex_lock_interruptible(&lirc_dev_lock)) -+ return -ERESTARTSYS; -+ -+ ir = irctls[iminor(inode)]; -+ if (!ir) { -+ retval = -ENODEV; -+ goto error; -+ } -+ -+ dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); -+ -+ if (ir->d.minor == NOPLUG) { -+ retval = -ENODEV; -+ goto error; -+ } -+ -+ if (ir->open) { -+ retval = -EBUSY; -+ goto error; -+ } -+ -+ if (try_module_get(ir->d.owner)) { -+ ++ir->open; -+ retval = ir->d.set_use_inc(ir->d.data); -+ -+ if (retval) { -+ module_put(ir->d.owner); -+ --ir->open; -+ } else { -+ lirc_buffer_clear(ir->buf); -+ } -+ if (ir->task) -+ wake_up_process(ir->task); -+ } -+ -+error: -+ if (ir) -+ dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n", -+ ir->d.name, ir->d.minor, retval); -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return retval; -+} -+EXPORT_SYMBOL(lirc_dev_fop_open); -+ -+int lirc_dev_fop_close(struct inode *inode, struct file *file) -+{ -+ struct irctl *ir = irctls[iminor(inode)]; -+ -+ 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; -+ if (ir->attached) { -+ ir->d.set_use_dec(ir->d.data); -+ module_put(ir->d.owner); -+ } else { -+ cleanup(ir); -+ irctls[ir->d.minor] = NULL; -+ kfree(ir); -+ } -+ -+ mutex_unlock(&lirc_dev_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lirc_dev_fop_close); -+ -+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; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); -+ -+ if (!ir->attached) { -+ mutex_unlock(&ir->irctl_lock); -+ return POLLERR; -+ } -+ -+ poll_wait(file, &ir->buf->wait_poll, wait); -+ -+ if (ir->buf) -+ if (lirc_buffer_empty(ir->buf)) -+ ret = 0; -+ else -+ ret = POLLIN | POLLRDNORM; -+ else -+ ret = POLLERR; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n", -+ ir->d.name, ir->d.minor, ret); -+ -+ return ret; -+} -+EXPORT_SYMBOL(lirc_dev_fop_poll); -+ -+int lirc_dev_fop_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ unsigned long mode; -+ int result = 0; -+ struct irctl *ir = irctls[iminor(inode)]; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", -+ ir->d.name, ir->d.minor, cmd); -+ -+ if (ir->d.minor == NOPLUG || !ir->attached) { -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", -+ ir->d.name, ir->d.minor); -+ return -ENODEV; -+ } -+ -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ result = put_user(ir->d.features, (unsigned long *)arg); -+ break; -+ case LIRC_GET_REC_MODE: -+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = put_user(LIRC_REC2MODE -+ (ir->d.features & LIRC_CAN_REC_MASK), -+ (unsigned long *)arg); -+ break; -+ case LIRC_SET_REC_MODE: -+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) -+ return -ENOSYS; -+ -+ result = get_user(mode, (unsigned long *)arg); -+ if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) -+ result = -EINVAL; -+ /* -+ * FIXME: We should actually set the mode somehow but -+ * for now, lirc_serial doesn't support mode changing either -+ */ -+ break; -+ case LIRC_GET_LENGTH: -+ result = put_user(ir->d.code_length, (unsigned long *)arg); -+ break; -+ case LIRC_GET_MIN_TIMEOUT: -+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || -+ ir->d.min_timeout == 0) -+ return -ENOSYS; -+ -+ result = put_user(ir->d.min_timeout, (int *) arg); -+ break; -+ case LIRC_GET_MAX_TIMEOUT: -+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || -+ ir->d.max_timeout == 0) -+ return -ENOSYS; -+ -+ result = put_user(ir->d.max_timeout, (int *) arg); -+ break; -+ default: -+ result = -EINVAL; -+ } -+ -+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n", -+ ir->d.name, ir->d.minor, result); -+ -+ return result; -+} -+EXPORT_SYMBOL(lirc_dev_fop_ioctl); -+ -+#ifdef CONFIG_COMPAT -+#define LIRC_GET_FEATURES_COMPAT32 _IOR('i', 0x00000000, __u32) -+ -+#define LIRC_GET_SEND_MODE_COMPAT32 _IOR('i', 0x00000001, __u32) -+#define LIRC_GET_REC_MODE_COMPAT32 _IOR('i', 0x00000002, __u32) -+ -+#define LIRC_GET_LENGTH_COMPAT32 _IOR('i', 0x0000000f, __u32) -+ -+#define LIRC_SET_SEND_MODE_COMPAT32 _IOW('i', 0x00000011, __u32) -+#define LIRC_SET_REC_MODE_COMPAT32 _IOW('i', 0x00000012, __u32) -+ -+long lirc_dev_fop_compat_ioctl(struct file *file, -+ unsigned int cmd32, -+ unsigned long arg) -+{ -+ mm_segment_t old_fs; -+ int ret; -+ unsigned long val; -+ unsigned int cmd; -+ -+ switch (cmd32) { -+ case LIRC_GET_FEATURES_COMPAT32: -+ case LIRC_GET_SEND_MODE_COMPAT32: -+ case LIRC_GET_REC_MODE_COMPAT32: -+ case LIRC_GET_LENGTH_COMPAT32: -+ case LIRC_SET_SEND_MODE_COMPAT32: -+ case LIRC_SET_REC_MODE_COMPAT32: -+ /* -+ * These commands expect (unsigned long *) arg -+ * but the 32-bit app supplied (__u32 *). -+ * Conversion is required. -+ */ -+ if (get_user(val, (__u32 *)compat_ptr(arg))) -+ return -EFAULT; -+ lock_kernel(); -+ /* -+ * tell lirc_dev_fop_ioctl that it's safe to use the pointer -+ * to val which is in kernel address space and not in -+ * user address space. -+ */ -+ old_fs = get_fs(); -+ set_fs(KERNEL_DS); -+ -+ cmd = _IOC(_IOC_DIR(cmd32), _IOC_TYPE(cmd32), _IOC_NR(cmd32), -+ (_IOC_TYPECHECK(unsigned long))); -+ ret = lirc_dev_fop_ioctl(file->f_path.dentry->d_inode, file, -+ cmd, (unsigned long)(&val)); -+ -+ set_fs(old_fs); -+ unlock_kernel(); -+ switch (cmd) { -+ case LIRC_GET_FEATURES: -+ case LIRC_GET_SEND_MODE: -+ case LIRC_GET_REC_MODE: -+ case LIRC_GET_LENGTH: -+ if (!ret && put_user(val, (__u32 *)compat_ptr(arg))) -+ return -EFAULT; -+ break; -+ } -+ return ret; -+ -+ case LIRC_GET_SEND_CARRIER: -+ case LIRC_GET_REC_CARRIER: -+ case LIRC_GET_SEND_DUTY_CYCLE: -+ case LIRC_GET_REC_DUTY_CYCLE: -+ case LIRC_GET_REC_RESOLUTION: -+ case LIRC_SET_SEND_CARRIER: -+ case LIRC_SET_REC_CARRIER: -+ case LIRC_SET_SEND_DUTY_CYCLE: -+ case LIRC_SET_REC_DUTY_CYCLE: -+ case LIRC_SET_TRANSMITTER_MASK: -+ case LIRC_SET_REC_DUTY_CYCLE_RANGE: -+ case LIRC_SET_REC_CARRIER_RANGE: -+ /* -+ * These commands expect (unsigned int *)arg -+ * so no problems here. Just handle the locking. -+ */ -+ lock_kernel(); -+ cmd = cmd32; -+ ret = lirc_dev_fop_ioctl(file->f_path.dentry->d_inode, -+ file, cmd, arg); -+ unlock_kernel(); -+ return ret; -+ default: -+ /* unknown */ -+ printk(KERN_ERR "lirc_dev: %s(%s:%d): Unknown cmd %08x\n", -+ __func__, current->comm, current->pid, cmd32); -+ return -ENOIOCTLCMD; -+ } -+} -+EXPORT_SYMBOL(lirc_dev_fop_compat_ioctl); -+#endif -+ -+ -+ssize_t lirc_dev_fop_read(struct file *file, -+ char *buffer, -+ size_t length, -+ loff_t *ppos) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ unsigned char buf[ir->chunk_size]; -+ int ret = 0, written = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); -+ -+ if (mutex_lock_interruptible(&ir->irctl_lock)) -+ return -ERESTARTSYS; -+ if (!ir->attached) { -+ mutex_unlock(&ir->irctl_lock); -+ return -ENODEV; -+ } -+ -+ if (length % ir->chunk_size) { -+ dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n", -+ ir->d.name, ir->d.minor); -+ mutex_unlock(&ir->irctl_lock); -+ return -EINVAL; -+ } -+ -+ /* -+ * we add ourselves to the task queue before buffer check -+ * to avoid losing scan code (in case when queue is awaken somewhere -+ * between while condition checking and scheduling) -+ */ -+ add_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * while we didn't provide 'length' bytes, device is opened in blocking -+ * mode and 'copy_to_user' is happy, wait for data. -+ */ -+ while (written < length && ret == 0) { -+ if (lirc_buffer_empty(ir->buf)) { -+ /* According to the read(2) man page, 'written' can be -+ * returned as less than 'length', instead of blocking -+ * again, returning -EWOULDBLOCK, or returning -+ * -ERESTARTSYS */ -+ if (written) -+ break; -+ if (file->f_flags & O_NONBLOCK) { -+ ret = -EWOULDBLOCK; -+ break; -+ } -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ -+ mutex_unlock(&ir->irctl_lock); -+ schedule(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ if (mutex_lock_interruptible(&ir->irctl_lock)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ -+ if (!ir->attached) { -+ ret = -ENODEV; -+ break; -+ } -+ } else { -+ lirc_buffer_read(ir->buf, buf); -+ ret = copy_to_user((void *)buffer+written, buf, -+ ir->buf->chunk_size); -+ written += ir->buf->chunk_size; -+ } -+ } -+ -+ remove_wait_queue(&ir->buf->wait_poll, &wait); -+ set_current_state(TASK_RUNNING); -+ mutex_unlock(&ir->irctl_lock); -+ -+ dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", -+ ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret); -+ -+ return ret ? ret : written; -+} -+EXPORT_SYMBOL(lirc_dev_fop_read); -+ -+void *lirc_get_pdata(struct file *file) -+{ -+ void *data = NULL; -+ -+ if (file && file->f_dentry && file->f_dentry->d_inode && -+ file->f_dentry->d_inode->i_rdev) { -+ struct irctl *ir; -+ ir = irctls[iminor(file->f_dentry->d_inode)]; -+ data = ir->d.data; -+ } -+ -+ return data; -+} -+EXPORT_SYMBOL(lirc_get_pdata); -+ -+ -+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, -+ size_t length, loff_t *ppos) -+{ -+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; -+ -+ dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); -+ -+ if (!ir->attached) -+ return -ENODEV; -+ -+ return -EINVAL; -+} -+EXPORT_SYMBOL(lirc_dev_fop_write); -+ -+ -+static int __init lirc_dev_init(void) -+{ -+ int retval; -+ -+ lirc_class = class_create(THIS_MODULE, "lirc"); -+ if (IS_ERR(lirc_class)) { -+ retval = PTR_ERR(lirc_class); -+ printk(KERN_ERR "lirc_dev: class_create failed\n"); -+ goto error; -+ } -+ -+ retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES, -+ IRCTL_DEV_NAME); -+ if (retval) { -+ class_destroy(lirc_class); -+ printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n"); -+ goto error; -+ } -+ -+ -+ printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, " -+ "major %d \n", MAJOR(lirc_base_dev)); -+ -+error: -+ return retval; -+} -+ -+ -+ -+static void __exit lirc_dev_exit(void) -+{ -+ class_destroy(lirc_class); -+ unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES); -+ printk(KERN_INFO "lirc_dev: module unloaded\n"); -+} -+ -+module_init(lirc_dev_init); -+module_exit(lirc_dev_exit); -+ -+MODULE_DESCRIPTION("LIRC base driver module"); -+MODULE_AUTHOR("Artur Lipowski"); -+MODULE_LICENSE("GPL"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_dev.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_dev.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_dev.h 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,228 @@ -+/* -+ * LIRC base driver -+ * -+ * by Artur Lipowski -+ * This code is licensed under GNU GPL -+ * -+ */ -+ -+#ifndef _LINUX_LIRC_DEV_H -+#define _LINUX_LIRC_DEV_H -+ -+#define MAX_IRCTL_DEVICES 4 -+#define BUFLEN 16 -+ -+#define mod(n, div) ((n) % (div)) -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct lirc_buffer { -+ wait_queue_head_t wait_poll; -+ spinlock_t fifo_lock; -+ unsigned int chunk_size; -+ unsigned int size; /* in chunks */ -+ /* Using chunks instead of bytes pretends to simplify boundary checking -+ * And should allow for some performance fine tunning later */ -+ struct kfifo fifo; -+ u8 fifo_initialized; -+}; -+ -+static inline void lirc_buffer_clear(struct lirc_buffer *buf) -+{ -+ unsigned long flags; -+ -+ if (buf->fifo_initialized) { -+ spin_lock_irqsave(&buf->fifo_lock, flags); -+ kfifo_reset(&buf->fifo); -+ spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ } else -+ WARN(1, "calling %s on an uninitialized lirc_buffer\n", -+ __func__); -+} -+ -+static inline int lirc_buffer_init(struct lirc_buffer *buf, -+ unsigned int chunk_size, -+ unsigned int size) -+{ -+ int ret; -+ -+ init_waitqueue_head(&buf->wait_poll); -+ spin_lock_init(&buf->fifo_lock); -+ buf->chunk_size = chunk_size; -+ buf->size = size; -+ ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL); -+ if (ret == 0) -+ buf->fifo_initialized = 1; -+ -+ return ret; -+} -+ -+static inline void lirc_buffer_free(struct lirc_buffer *buf) -+{ -+ if (buf->fifo_initialized) { -+ kfifo_free(&buf->fifo); -+ buf->fifo_initialized = 0; -+ } else -+ WARN(1, "calling %s on an uninitialized lirc_buffer\n", -+ __func__); -+} -+ -+static inline int lirc_buffer_len(struct lirc_buffer *buf) -+{ -+ int len; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&buf->fifo_lock, flags); -+ len = kfifo_len(&buf->fifo); -+ spin_unlock_irqrestore(&buf->fifo_lock, flags); -+ -+ return len; -+} -+ -+static inline int lirc_buffer_full(struct lirc_buffer *buf) -+{ -+ return lirc_buffer_len(buf) == buf->size * buf->chunk_size; -+} -+ -+static inline int lirc_buffer_empty(struct lirc_buffer *buf) -+{ -+ return !lirc_buffer_len(buf); -+} -+ -+static inline int lirc_buffer_available(struct lirc_buffer *buf) -+{ -+ return buf->size - (lirc_buffer_len(buf) / buf->chunk_size); -+} -+ -+static inline unsigned int lirc_buffer_read(struct lirc_buffer *buf, -+ unsigned char *dest) -+{ -+ unsigned int ret = 0; -+ -+ if (lirc_buffer_len(buf) >= buf->chunk_size) -+ ret = kfifo_out_locked(&buf->fifo, dest, buf->chunk_size, -+ &buf->fifo_lock); -+ return ret; -+ -+} -+ -+static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, -+ unsigned char *orig) -+{ -+ unsigned int ret; -+ -+ ret = kfifo_in_locked(&buf->fifo, orig, buf->chunk_size, -+ &buf->fifo_lock); -+ -+ return ret; -+} -+ -+struct lirc_driver { -+ char name[40]; -+ int minor; -+ unsigned long code_length; -+ unsigned int buffer_size; /* in chunks holding one code each */ -+ int sample_rate; -+ unsigned long features; -+ -+ unsigned int chunk_size; -+ -+ void *data; -+ int min_timeout; -+ int max_timeout; -+ int (*add_to_buf) (void *data, struct lirc_buffer *buf); -+ struct lirc_buffer *rbuf; -+ int (*set_use_inc) (void *data); -+ void (*set_use_dec) (void *data); -+ struct file_operations *fops; -+ struct device *dev; -+ struct module *owner; -+}; -+ -+/* name: -+ * this string will be used for logs -+ * -+ * minor: -+ * indicates minor device (/dev/lirc) number for registered driver -+ * if caller fills it with negative value, then the first free minor -+ * number will be used (if available) -+ * -+ * code_length: -+ * length of the remote control key code expressed in bits -+ * -+ * sample_rate: -+ * -+ * data: -+ * it may point to any driver data and this pointer will be passed to -+ * all callback functions -+ * -+ * add_to_buf: -+ * add_to_buf will be called after specified period of the time or -+ * triggered by the external event, this behavior depends on value of -+ * the sample_rate this function will be called in user context. This -+ * routine should return 0 if data was added to the buffer and -+ * -ENODATA if none was available. This should add some number of bits -+ * evenly divisible by code_length to the buffer -+ * -+ * rbuf: -+ * if not NULL, it will be used as a read buffer, you will have to -+ * write to the buffer by other means, like irq's (see also -+ * lirc_serial.c). -+ * -+ * set_use_inc: -+ * set_use_inc will be called after device is opened -+ * -+ * set_use_dec: -+ * set_use_dec will be called after device is closed -+ * -+ * fops: -+ * file_operations for drivers which don't fit the current driver model. -+ * -+ * Some ioctl's can be directly handled by lirc_dev if the driver's -+ * ioctl function is NULL or if it returns -ENOIOCTLCMD (see also -+ * lirc_serial.c). -+ * -+ * owner: -+ * the module owning this struct -+ * -+ */ -+ -+ -+/* following functions can be called ONLY from user context -+ * -+ * returns negative value on error or minor number -+ * of the registered device if success -+ * contents of the structure pointed by p is copied -+ */ -+extern int lirc_register_driver(struct lirc_driver *d); -+ -+/* returns negative value on error or 0 if success -+*/ -+extern int lirc_unregister_driver(int minor); -+ -+/* Returns the private data stored in the lirc_driver -+ * associated with the given device file pointer. -+ */ -+void *lirc_get_pdata(struct file *file); -+ -+/* default file operations -+ * used by drivers if they override only some operations -+ */ -+int lirc_dev_fop_open(struct inode *inode, struct file *file); -+int lirc_dev_fop_close(struct inode *inode, struct file *file); -+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait); -+int lirc_dev_fop_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg); -+ssize_t lirc_dev_fop_read(struct file *file, char *buffer, size_t length, -+ loff_t *ppos); -+ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, size_t length, -+ loff_t *ppos); -+long lirc_dev_fop_compat_ioctl(struct file *file, unsigned int cmd32, -+ unsigned long arg); -+ -+#endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.c 2010-04-06 23:47:21.000000000 +0200 +diff --git a/drivers/staging/lirc/lirc_ene0100.c b/drivers/staging/lirc/lirc_ene0100.c +new file mode 100644 +index 0000000..a152c52 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_ene0100.c @@ -0,0 +1,646 @@ +/* + * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) @@ -2253,9 +1239,11 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.c linux-2.6.33.2.patch + +module_init(ene_init); +module_exit(ene_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ene0100.h 2010-04-06 23:47:21.000000000 +0200 +diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/lirc/lirc_ene0100.h +new file mode 100644 +index 0000000..825045d +--- /dev/null ++++ b/drivers/staging/lirc/lirc_ene0100.h @@ -0,0 +1,169 @@ +/* + * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) @@ -2278,8 +1266,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.h linux-2.6.33.2.patch + * USA + */ + -+#include -+#include "lirc_dev.h" ++#include ++#include + +/* hardware address */ +#define ENE_STATUS 0 /* hardware status - unused */ @@ -2426,9 +1414,11 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ene0100.h linux-2.6.33.2.patch + + struct timeval gap_start; +}; -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_i2c.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_i2c.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_i2c.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_i2c.c 2010-04-06 23:47:21.000000000 +0200 +diff --git a/drivers/staging/lirc/lirc_i2c.c b/drivers/staging/lirc/lirc_i2c.c +new file mode 100644 +index 0000000..6df2c0e +--- /dev/null ++++ b/drivers/staging/lirc/lirc_i2c.c @@ -0,0 +1,536 @@ +/* + * lirc_i2c.c @@ -2487,7 +1477,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_i2c.c linux-2.6.33.2.patch/dri +#include +#include + -+#include "lirc_dev.h" ++#include + +struct IR { + struct lirc_driver l; @@ -2966,9 +1956,11 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_i2c.c linux-2.6.33.2.patch/dri + +module_init(lirc_i2c_init); +module_exit(lirc_i2c_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_igorplugusb.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_igorplugusb.c 2010-04-06 23:47:21.000000000 +0200 +diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c +new file mode 100644 +index 0000000..bce600e +--- /dev/null ++++ b/drivers/staging/lirc/lirc_igorplugusb.c @@ -0,0 +1,555 @@ +/* + * lirc_igorplugusb - USB remote support for LIRC @@ -3021,8 +2013,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c linux-2.6.33.2.p +#include +#include + -+#include -+#include "lirc_dev.h" ++#include ++#include + + +/* module identification */ @@ -3378,7 +2370,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c linux-2.6.33.2.p + goto mem_failure_switch; + } + -+ ir->buf_in = usb_buffer_alloc(dev, ++ ir->buf_in = usb_alloc_coherent(dev, + DEVICE_BUFLEN+DEVICE_HEADERLEN, + GFP_ATOMIC, &ir->dma_in); + if (!ir->buf_in) { @@ -3410,7 +2402,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c linux-2.6.33.2.p + + switch (mem_failure) { + case 9: -+ usb_buffer_free(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN, ++ usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN, + ir->buf_in, ir->dma_in); + case 3: + kfree(driver); @@ -3468,7 +2460,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c linux-2.6.33.2.p + ir->usbdev = NULL; + wake_up_all(&ir->wait_out); + -+ usb_buffer_free(dev, ir->len_in, ir->buf_in, ir->dma_in); ++ usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); + + unregister_from_lirc(ir); +} @@ -3525,10 +2517,12 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_igorplugusb.c linux-2.6.33.2.p +module_param(sample_rate, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); + -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_imon.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_imon.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_imon.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1053 @@ +diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c +new file mode 100644 +index 0000000..43856d6 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_imon.c +@@ -0,0 +1,1058 @@ +/* + * lirc_imon.c: LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD + * including the iMON PAD model @@ -3559,8 +2553,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/dr +#include +#include + -+#include -+#include "lirc_dev.h" ++#include ++#include + + +#define MOD_AUTHOR "Venky Raju " @@ -3606,6 +2600,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/dr +static void __exit imon_exit(void); + +/*** G L O B A L S ***/ ++#define IMON_DATA_BUF_SZ 35 + +struct imon_context { + struct usb_device *usbdev; @@ -3634,7 +2629,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/dr + } rx; + + struct tx_t { -+ unsigned char data_buf[35]; /* user data buffer */ ++ unsigned char data_buf[IMON_DATA_BUF_SZ]; /* user data buffer */ + struct completion finished; /* wait for write to finish */ + atomic_t busy; /* write in progress */ + int status; /* status of tx completion */ @@ -3911,6 +2906,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/dr + struct imon_context *context; + const unsigned char vfd_packet6[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; ++ int *data_buf; + + context = (struct imon_context *)file->private_data; + if (!context) { @@ -3926,22 +2922,25 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/dr + goto exit; + } + -+ if (n_bytes <= 0 || n_bytes > 32) { ++ if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) { + err("%s: invalid payload size", __func__); + retval = -EINVAL; + goto exit; + } + -+ if (copy_from_user(context->tx.data_buf, buf, n_bytes)) { -+ retval = -EFAULT; ++ data_buf = memdup_user(buf, n_bytes); ++ if (IS_ERR(data_buf)) { ++ retval = PTR_ERR(data_buf); + goto exit; + } + ++ memcpy(context->tx.data_buf, data_buf, n_bytes); ++ + /* Pad with spaces */ -+ for (i = n_bytes; i < 32; ++i) ++ for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i) + context->tx.data_buf[i] = ' '; + -+ for (i = 32; i < 35; ++i) ++ for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i) + context->tx.data_buf[i] = 0xFF; + + offset = 0; @@ -3961,7 +2960,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/dr + offset += 7; + } + -+ } while (offset < 35); ++ } while (offset < IMON_DATA_BUF_SZ); + + if (context->vfd_proto_6p) { + /* Send packet #6 */ @@ -4582,10 +3581,12 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_imon.c linux-2.6.33.2.patch/dr + +module_init(imon_init); +module_exit(imon_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_it87.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.c 2010-04-07 21:56:14.000000000 +0200 -@@ -0,0 +1,1021 @@ +diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c +new file mode 100644 +index 0000000..781abc3 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_it87.c +@@ -0,0 +1,1019 @@ +/* + * LIRC driver for ITE IT8712/IT8705 CIR port + * @@ -4644,8 +3645,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/dr +#include +#include + -+#include -+#include "lirc_dev.h" ++#include ++#include + +#include "lirc_it87.h" + @@ -4664,7 +3665,6 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/dr +static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN; + +#define RBUF_LEN 1024 -+#define WBUF_LEN 1024 + +#define LIRC_DRIVER_NAME "lirc_it87" + @@ -4701,7 +3701,6 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/dr + +static int rx_buf[RBUF_LEN]; +unsigned int rx_tail, rx_head; -+static int tx_buf[WBUF_LEN]; + +static struct pnp_driver it87_pnp_driver; + @@ -4715,8 +3714,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/dr + size_t count, loff_t *ppos); +static ssize_t lirc_write(struct file *file, const char *buf, + size_t n, loff_t *pos); -+static int lirc_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg); ++static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); +static void add_read_queue(int flag, unsigned long val); +static int init_chrdev(void); +static void drop_chrdev(void); @@ -4796,11 +3794,13 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/dr + size_t n, loff_t *pos) +{ + int i = 0; ++ int *tx_buf; + -+ if (n % sizeof(int) || (n / sizeof(int)) > WBUF_LEN) ++ if (n % sizeof(int)) + return -EINVAL; -+ if (copy_from_user(tx_buf, buf, n)) -+ return -EFAULT; ++ tx_buf = memdup_user(buf, n); ++ if (IS_ERR(tx_buf)) ++ return PTR_ERR(tx_buf); + n /= sizeof(int); + init_send(); + while (1) { @@ -4820,8 +3820,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/dr +} + + -+static int lirc_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg) ++static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + unsigned long value = 0; @@ -4924,7 +3923,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/dr + .read = lirc_read, + .write = lirc_write, + .poll = lirc_poll, -+ .ioctl = lirc_ioctl, ++ .unlocked_ioctl = lirc_ioctl, + .open = lirc_open, + .release = lirc_close, +}; @@ -5607,9 +4606,11 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.c linux-2.6.33.2.patch/dr +MODULE_PARM_DESC(it87_freq, + "Carrier demodulator frequency (kHz), (default: 38)"); +#endif -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_it87.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_it87.h 2010-04-06 23:47:21.000000000 +0200 +diff --git a/drivers/staging/lirc/lirc_it87.h b/drivers/staging/lirc/lirc_it87.h +new file mode 100644 +index 0000000..cf021c8 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_it87.h @@ -0,0 +1,116 @@ +/* lirc_it87.h */ +/* SECTION: Definitions */ @@ -5727,10 +4728,12 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_it87.h linux-2.6.33.2.patch/dr +#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul) + +/********************************* ITE IT87xx ************************/ -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ite8709.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_ite8709.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_ite8709.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ite8709.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,540 @@ +diff --git a/drivers/staging/lirc/lirc_ite8709.c b/drivers/staging/lirc/lirc_ite8709.c +new file mode 100644 +index 0000000..9352f45 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_ite8709.c +@@ -0,0 +1,542 @@ +/* + * LIRC driver for ITE8709 CIR port + * @@ -5759,8 +4762,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ite8709.c linux-2.6.33.2.patch +#include +#include + -+#include -+#include "lirc_dev.h" ++#include ++#include + +#define LIRC_DRIVER_NAME "lirc_ite8709" + @@ -6255,15 +5258,17 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ite8709.c linux-2.6.33.2.patch + .id_table = pnp_dev_table, +}; + -+int init_module(void) ++static int __init ite8709_init_module(void) +{ + return pnp_register_driver(&ite8709_pnp_driver); +} ++module_init(ite8709_init_module); + -+void cleanup_module(void) ++static void __exit ite8709_cleanup_module(void) +{ + pnp_unregister_driver(&ite8709_pnp_driver); +} ++module_exit(ite8709_cleanup_module); + +MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port"); +MODULE_AUTHOR("Grégory Lardière"); @@ -6271,1399 +5276,12 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ite8709.c linux-2.6.33.2.patch + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_mceusb.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_mceusb.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_mceusb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_mceusb.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1385 @@ -+/* -+ * LIRC driver for Windows Media Center Edition USB Infrared Transceivers -+ * -+ * (C) by Martin A. Blatter -+ * -+ * Transmitter support and reception code cleanup. -+ * (C) by Daniel Melander -+ * -+ * Original lirc_mceusb driver for 1st-gen device: -+ * Copyright (c) 2003-2004 Dan Conti -+ * -+ * Original lirc_mceusb driver deprecated in favor of this driver, which -+ * supports the 1st-gen device now too. Transmit and receive support for -+ * the 1st-gen device added June-September 2009, -+ * by Jarod Wilson and Patrick Calhoun -+ * -+ * Derived from ATI USB driver by Paul Miller and the original -+ * MCE USB driver by Dan Conti (and now including chunks of the latter -+ * relevant to the 1st-gen device initialization) -+ * -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "lirc_dev.h" -+ -+#define DRIVER_VERSION "1.90" -+#define DRIVER_AUTHOR "Daniel Melander , " \ -+ "Martin Blatter , " \ -+ "Dan Conti " -+#define DRIVER_DESC "Windows Media Center Edition USB IR Transceiver " \ -+ "driver for LIRC" -+#define DRIVER_NAME "lirc_mceusb" -+ -+#define USB_BUFLEN 32 /* USB reception buffer length */ -+#define LIRCBUF_SIZE 256 /* LIRC work buffer length */ -+ -+/* 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 0x7F /* Pulse mask */ -+ -+ -+/* module parameters */ -+#ifdef CONFIG_USB_DEBUG -+static int debug = 1; -+#else -+static int debug; -+#endif -+ -+/* general constants */ -+#define SEND_FLAG_IN_PROGRESS 1 -+#define SEND_FLAG_COMPLETE 2 -+#define RECV_FLAG_IN_PROGRESS 3 -+#define RECV_FLAG_COMPLETE 4 -+ -+#define MCEUSB_INBOUND 1 -+#define MCEUSB_OUTBOUND 2 -+ -+#define VENDOR_PHILIPS 0x0471 -+#define VENDOR_SMK 0x0609 -+#define VENDOR_TATUNG 0x1460 -+#define VENDOR_GATEWAY 0x107b -+#define VENDOR_SHUTTLE 0x1308 -+#define VENDOR_SHUTTLE2 0x051c -+#define VENDOR_MITSUMI 0x03ee -+#define VENDOR_TOPSEED 0x1784 -+#define VENDOR_RICAVISION 0x179d -+#define VENDOR_ITRON 0x195d -+#define VENDOR_FIC 0x1509 -+#define VENDOR_LG 0x043e -+#define VENDOR_MICROSOFT 0x045e -+#define VENDOR_FORMOSA 0x147a -+#define VENDOR_FINTEK 0x1934 -+#define VENDOR_PINNACLE 0x2304 -+#define VENDOR_ECS 0x1019 -+#define VENDOR_WISTRON 0x0fb8 -+#define VENDOR_COMPRO 0x185b -+#define VENDOR_NORTHSTAR 0x04eb -+#define VENDOR_REALTEK 0x0bda -+#define VENDOR_TIVO 0x105a -+ -+static struct usb_device_id mceusb_dev_table[] = { -+ /* Original Microsoft MCE IR Transceiver (often HP-branded) */ -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ /* Philips Infrared Transceiver - Sahara branded */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0608) }, -+ /* Philips Infrared Transceiver - HP branded */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, -+ /* Philips SRM5100 */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, -+ /* Philips Infrared Transceiver - Omaura */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x060f) }, -+ /* Philips Infrared Transceiver - Spinel plus */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0613) }, -+ /* Philips eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_PHILIPS, 0x0815) }, -+ /* Realtek MCE IR Receiver */ -+ { USB_DEVICE(VENDOR_REALTEK, 0x0161) }, -+ /* SMK/Toshiba G83C0004D410 */ -+ { USB_DEVICE(VENDOR_SMK, 0x031d) }, -+ /* SMK eHome Infrared Transceiver (Sony VAIO) */ -+ { USB_DEVICE(VENDOR_SMK, 0x0322) }, -+ /* bundled with Hauppauge PVR-150 */ -+ { USB_DEVICE(VENDOR_SMK, 0x0334) }, -+ /* SMK eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SMK, 0x0338) }, -+ /* Tatung eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TATUNG, 0x9150) }, -+ /* Shuttle eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) }, -+ /* Shuttle eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) }, -+ /* Gateway eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_GATEWAY, 0x3009) }, -+ /* Mitsumi */ -+ { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, -+ /* Topseed HP eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a) }, -+ /* Topseed eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011) }, -+ /* Ricavision internal Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, -+ /* Itron ione Libra Q-11 */ -+ { USB_DEVICE(VENDOR_ITRON, 0x7002) }, -+ /* FIC eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FIC, 0x9242) }, -+ /* LG eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_LG, 0x9803) }, -+ /* Microsoft MCE Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) }, -+ /* Formosa eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe015) }, -+ /* Formosa21 / eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe016) }, -+ /* Formosa aim / Trust MCE Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe017) }, -+ /* Formosa Industrial Computing / Beanbag Emulation Device */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe018) }, -+ /* Formosa21 / eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) }, -+ /* Formosa Industrial Computing AIM IR605/A */ -+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, -+ /* Fintek eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, -+ /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ -+ { USB_DEVICE(VENDOR_FINTEK, 0x0702) }, -+ /* Pinnacle Remote Kit */ -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ /* Elitegroup Computer Systems IR */ -+ { USB_DEVICE(VENDOR_ECS, 0x0f38) }, -+ /* Wistron Corp. eHome Infrared Receiver */ -+ { USB_DEVICE(VENDOR_WISTRON, 0x0002) }, -+ /* Compro K100 */ -+ { USB_DEVICE(VENDOR_COMPRO, 0x3020) }, -+ /* Compro K100 v2 */ -+ { USB_DEVICE(VENDOR_COMPRO, 0x3082) }, -+ /* Northstar Systems, Inc. eHome Infrared Transceiver */ -+ { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, -+ /* TiVo PC IR Receiver */ -+ { USB_DEVICE(VENDOR_TIVO, 0x2000) }, -+ /* Terminating entry */ -+ { } -+}; -+ -+static struct usb_device_id gen3_list[] = { -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, -+ {} -+}; -+ -+static struct usb_device_id pinnacle_list[] = { -+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, -+ {} -+}; -+ -+static struct usb_device_id microsoft_gen1_list[] = { -+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, -+ {} -+}; -+ -+static struct usb_device_id transmitter_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 { -+ -+ /* usb */ -+ struct usb_device *usbdev; -+ struct urb *urb_in; -+ int devnum; -+ struct usb_endpoint_descriptor *usb_ep_in; -+ struct usb_endpoint_descriptor *usb_ep_out; -+ -+ /* buffers and dma */ -+ unsigned char *buf_in; -+ unsigned int len_in; -+ dma_addr_t dma_in; -+ dma_addr_t dma_out; -+ unsigned int overflow_len; -+ -+ /* lirc */ -+ struct lirc_driver *d; -+ int lircdata; -+ unsigned char is_pulse; -+ struct { -+ u32 connected:1; -+ u32 gen3:1; -+ u32 transmitter_mask_inverted:1; -+ u32 microsoft_gen1:1; -+ u32 reserved:28; -+ } flags; -+ -+ unsigned char transmitter_mask; -+ unsigned int carrier_freq; -+ -+ /* handle sending (init strings) */ -+ int send_flags; -+ wait_queue_head_t wait_out; -+ -+ struct mutex dev_lock; -+}; -+ -+/* -+ * MCE Device Command Strings -+ * Device command responses vary from device to device... -+ * - DEVICE_RESET resets the hardware to its default state -+ * - GET_REVISION fetches the hardware/software revision, common -+ * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42 -+ * - GET_CARRIER_FREQ gets the carrier mode and frequency of the -+ * device, with replies in the form of 9f 06 MM FF, where MM is 0-3, -+ * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is -+ * ((clk / frequency) - 1) -+ * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us, -+ * response in the form of 9f 0c msb lsb -+ * - GET_TX_BITMASK fetches the transmitter bitmask, replies in -+ * the form of 9f 08 bm, where bm is the bitmask -+ * - GET_RX_SENSOR fetches the RX sensor setting -- long-range -+ * general use one or short-range learning one, in the form of -+ * 9f 14 ss, where ss is either 01 for long-range or 02 for short -+ * - SET_CARRIER_FREQ sets a new carrier mode and frequency -+ * - SET_TX_BITMASK sets the transmitter bitmask -+ * - 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_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}; -+/* sub in desired values in lower byte or bytes for full command */ -+//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 void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, -+ int len, bool out) -+{ -+ char codes[USB_BUFLEN * 3 + 1]; -+ char inout[9]; -+ int i; -+ u8 cmd, subcmd, data1, data2; -+ struct device *dev = ir->d->dev; -+ -+ if (len <= 0) -+ return; -+ -+ if (ir->flags.microsoft_gen1 && len <= 2) -+ return; -+ -+ for (i = 0; i < len && i < USB_BUFLEN; i++) -+ snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF); -+ -+ dev_info(dev, "%sbound data: %s (length=%d)\n", -+ (out ? "out" : " in"), codes, len); -+ -+ if (out) -+ strcpy(inout, "Request\0"); -+ else -+ strcpy(inout, "Got\0"); -+ -+ cmd = buf[0] & 0xff; -+ subcmd = buf[1] & 0xff; -+ data1 = buf[2] & 0xff; -+ data2 = buf[3] & 0xff; -+ -+ switch (cmd) { -+ case 0x00: -+ if (subcmd == 0xff && data1 == 0xaa) -+ dev_info(dev, "Device reset requested\n"); -+ else -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ case 0xff: -+ switch (subcmd) { -+ case 0x0b: -+ 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[4], buf[5]); -+ break; -+ case 0xaa: -+ dev_info(dev, "Device reset requested\n"); -+ break; -+ case 0xfe: -+ dev_info(dev, "Previous command not supported\n"); -+ break; -+ case 0x18: -+ case 0x1b: -+ default: -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ } -+ break; -+ case 0x9f: -+ switch (subcmd) { -+ case 0x03: -+ dev_info(dev, "Ping\n"); -+ break; -+ case 0x04: -+ dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", -+ data1, data2); -+ break; -+ case 0x06: -+ dev_info(dev, "%s carrier mode and freq of 0x%02x 0x%02x\n", -+ inout, data1, data2); -+ break; -+ case 0x07: -+ dev_info(dev, "Get carrier mode and freq\n"); -+ break; -+ case 0x08: -+ dev_info(dev, "%s transmit blaster mask of 0x%02x\n", -+ inout, data1); -+ break; -+ case 0x0c: -+ /* 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: -+ dev_info(dev, "Get receive timeout\n"); -+ break; -+ case 0x13: -+ dev_info(dev, "Get transmit blaster mask\n"); -+ break; -+ case 0x14: -+ dev_info(dev, "%s %s-range receive sensor in use\n", -+ inout, data1 == 0x02 ? "short" : "long"); -+ break; -+ case 0x15: -+ 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: -+ dev_info(dev, "Error! Hardware is likely wedged...\n"); -+ break; -+ case 0x05: -+ case 0x09: -+ case 0x0f: -+ default: -+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n", -+ cmd, subcmd); -+ break; -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static void usb_async_callback(struct urb *urb, struct pt_regs *regs) -+{ -+ struct mceusb_dev *ir; -+ int len; -+ -+ if (!urb) -+ return; -+ -+ ir = urb->context; -+ if (ir) { -+ len = urb->actual_length; -+ -+ dev_dbg(ir->d->dev, "callback called (status=%d len=%d)\n", -+ urb->status, len); -+ -+ if (debug) -+ mceusb_dev_printdata(ir, urb->transfer_buffer, len, true); -+ } -+ -+} -+ -+/* request incoming or send outgoing usb packet - used to initialize remote */ -+static void mce_request_packet(struct mceusb_dev *ir, -+ struct usb_endpoint_descriptor *ep, -+ unsigned char *data, int size, int urb_type) -+{ -+ int res; -+ struct urb *async_urb; -+ unsigned char *async_buf; -+ -+ if (urb_type == MCEUSB_OUTBOUND) { -+ async_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (unlikely(!async_urb)) { -+ dev_err(ir->d->dev, "Error, couldn't allocate urb!\n"); -+ return; -+ } -+ -+ async_buf = kzalloc(size, GFP_KERNEL); -+ if (!async_buf) { -+ dev_err(ir->d->dev, "Error, couldn't allocate buf!\n"); -+ usb_free_urb(async_urb); -+ return; -+ } -+ -+ /* outbound data */ -+ usb_fill_int_urb(async_urb, ir->usbdev, -+ usb_sndintpipe(ir->usbdev, ep->bEndpointAddress), -+ async_buf, size, (usb_complete_t) usb_async_callback, -+ ir, ep->bInterval); -+ memcpy(async_buf, data, size); -+ -+ } else if (urb_type == MCEUSB_INBOUND) { -+ /* standard request */ -+ async_urb = ir->urb_in; -+ ir->send_flags = RECV_FLAG_IN_PROGRESS; -+ -+ } else { -+ dev_err(ir->d->dev, "Error! Unknown urb type %d\n", urb_type); -+ return; -+ } -+ -+ dev_dbg(ir->d->dev, "receive request called (size=%#x)\n", size); -+ -+ async_urb->transfer_buffer_length = size; -+ async_urb->dev = ir->usbdev; -+ -+ res = usb_submit_urb(async_urb, GFP_ATOMIC); -+ if (res) { -+ dev_dbg(ir->d->dev, "receive request FAILED! (res=%d)\n", res); -+ return; -+ } -+ dev_dbg(ir->d->dev, "receive request complete (res=%d)\n", res); -+} -+ -+static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) -+{ -+ mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_OUTBOUND); -+} -+ -+static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size) -+{ -+ mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_INBOUND); -+} -+ -+static int unregister_from_lirc(struct mceusb_dev *ir) -+{ -+ struct lirc_driver *d = ir->d; -+ int devnum; -+ int rtn; -+ -+ devnum = ir->devnum; -+ dev_dbg(ir->d->dev, "unregister from lirc called\n"); -+ -+ rtn = lirc_unregister_driver(d->minor); -+ if (rtn > 0) { -+ dev_info(ir->d->dev, "error in lirc_unregister minor: %d\n" -+ "Trying again...\n", d->minor); -+ if (rtn == -EBUSY) { -+ dev_info(ir->d->dev, "device is opened, will " -+ "unregister on close\n"); -+ return -EAGAIN; -+ } -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(HZ); -+ -+ rtn = lirc_unregister_driver(d->minor); -+ if (rtn > 0) -+ dev_info(ir->d->dev, "lirc_unregister failed\n"); -+ } -+ -+ if (rtn) { -+ dev_info(ir->d->dev, "didn't free resources\n"); -+ return -EAGAIN; -+ } -+ -+ dev_info(ir->d->dev, "usb remote disconnected\n"); -+ -+ lirc_buffer_free(d->rbuf); -+ kfree(d->rbuf); -+ kfree(d); -+ kfree(ir); -+ return 0; -+} -+ -+static int mceusb_ir_open(void *data) -+{ -+ struct mceusb_dev *ir = data; -+ -+ if (!ir) { -+ printk(KERN_WARNING DRIVER_NAME -+ "[?]: %s called with no context\n", __func__); -+ return -EIO; -+ } -+ -+ dev_dbg(ir->d->dev, "mceusb IR device opened\n"); -+ -+ if (!ir->flags.connected) { -+ if (!ir->usbdev) -+ return -ENOENT; -+ ir->flags.connected = 1; -+ } -+ -+ return 0; -+} -+ -+static void mceusb_ir_close(void *data) -+{ -+ struct mceusb_dev *ir = data; -+ -+ if (!ir) { -+ printk(KERN_WARNING DRIVER_NAME -+ "[?]: %s called with no context\n", __func__); -+ return; -+ } -+ -+ dev_dbg(ir->d->dev, "mceusb IR device closed\n"); -+ -+ if (ir->flags.connected) { -+ mutex_lock(&ir->dev_lock); -+ ir->flags.connected = 0; -+ mutex_unlock(&ir->dev_lock); -+ } -+} -+ -+static void send_packet_to_lirc(struct mceusb_dev *ir) -+{ -+ if (ir->lircdata) { -+ lirc_buffer_write(ir->d->rbuf, -+ (unsigned char *) &ir->lircdata); -+ wake_up(&ir->d->rbuf->wait_poll); -+ ir->lircdata = 0; -+ } -+} -+ -+static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) -+{ -+ int i, j; -+ int packet_len = 0; -+ int start_index = 0; -+ -+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ -+ if (ir->flags.microsoft_gen1) -+ start_index = 2; -+ -+ /* this should only trigger w/the 1st-gen mce receiver */ -+ for (i = start_index; i < (start_index + ir->overflow_len) && -+ i < buf_len; i++) { -+ /* rising/falling flank */ -+ if (ir->is_pulse != (ir->buf_in[i] & MCE_PULSE_BIT)) { -+ send_packet_to_lirc(ir); -+ ir->is_pulse = ir->buf_in[i] & MCE_PULSE_BIT; -+ } -+ -+ /* accumulate mce pulse/space values */ -+ ir->lircdata += (ir->buf_in[i] & MCE_PULSE_MASK) * -+ MCE_TIME_UNIT; -+ ir->lircdata |= (ir->is_pulse ? PULSE_BIT : 0); -+ } -+ start_index += ir->overflow_len; -+ ir->overflow_len = 0; -+ -+ for (i = start_index; i < buf_len; i++) { -+ /* decode mce packets of the form (84),AA,BB,CC,DD */ -+ -+ /* data headers */ -+ if (ir->buf_in[i] >= 0x80 && ir->buf_in[i] <= 0x9e) { -+ /* decode packet data */ -+ packet_len = ir->buf_in[i] & MCE_PACKET_LENGTH_MASK; -+ ir->overflow_len = i + 1 + packet_len - buf_len; -+ for (j = 1; j <= packet_len && (i + j < buf_len); j++) { -+ /* rising/falling flank */ -+ if (ir->is_pulse != -+ (ir->buf_in[i + j] & MCE_PULSE_BIT)) { -+ send_packet_to_lirc(ir); -+ ir->is_pulse = -+ ir->buf_in[i + j] & -+ MCE_PULSE_BIT; -+ } -+ -+ /* accumulate mce pulse/space values */ -+ ir->lircdata += -+ (ir->buf_in[i + j] & MCE_PULSE_MASK) * -+ MCE_TIME_UNIT; -+ ir->lircdata |= (ir->is_pulse ? PULSE_BIT : 0); -+ } -+ -+ i += packet_len; -+ -+ /* status header (0x9F) */ -+ } else if (ir->buf_in[i] == MCE_CONTROL_HEADER) { -+ /* -+ * A transmission containing one or more consecutive ir -+ * commands always ends with a GAP of 100ms followed by -+ * the sequence 0x9F 0x01 0x01 0x9F 0x15 0x00 0x00 0x80 -+ */ -+ -+#if 0 -+ Uncomment this if the last 100ms "infinity"-space should be transmitted -+ to lirc directly instead of at the beginning of the next transmission. -+ Changes pulse/space order. -+ -+ if (++i < buf_len && ir->buf_in[i] == 0x01) -+ send_packet_to_lirc(ir); -+ -+#endif -+ -+ /* end decode loop */ -+ dev_dbg(ir->d->dev, "[%d] %s: found control header\n", -+ ir->devnum, __func__); -+ ir->overflow_len = 0; -+ break; -+ } else { -+ dev_dbg(ir->d->dev, "[%d] %s: stray packet?\n", -+ ir->devnum, __func__); -+ ir->overflow_len = 0; -+ } -+ } -+ -+ return; -+} -+ -+static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) -+{ -+ struct mceusb_dev *ir; -+ int buf_len; -+ -+ if (!urb) -+ return; -+ -+ ir = urb->context; -+ if (!ir) { -+ usb_unlink_urb(urb); -+ return; -+ } -+ -+ 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->d->dev, "setup answer received %d bytes\n", -+ buf_len); -+ } -+ -+ switch (urb->status) { -+ /* success */ -+ case 0: -+ mceusb_process_ir_data(ir, buf_len); -+ break; -+ -+ case -ECONNRESET: -+ case -ENOENT: -+ case -ESHUTDOWN: -+ usb_unlink_urb(urb); -+ return; -+ -+ case -EPIPE: -+ default: -+ break; -+ } -+ -+ usb_submit_urb(urb, GFP_ATOMIC); -+} -+ -+ -+static ssize_t mceusb_transmit_ir(struct file *file, const char *buf, -+ size_t n, loff_t *ppos) -+{ -+ int i, count = 0, cmdcount = 0; -+ struct mceusb_dev *ir = NULL; -+ int wbuf[LIRCBUF_SIZE]; /* Workbuffer with values from lirc */ -+ unsigned char cmdbuf[MCE_CMDBUF_SIZE]; /* MCE command buffer */ -+ unsigned long signal_duration = 0; /* Singnal length in us */ -+ struct timeval start_time, end_time; -+ -+ do_gettimeofday(&start_time); -+ -+ /* Retrieve lirc_driver data for the device */ -+ ir = lirc_get_pdata(file); -+ if (!ir || !ir->usb_ep_out) -+ return -EFAULT; -+ -+ if (n % sizeof(int)) -+ return -EINVAL; -+ count = n / sizeof(int); -+ -+ /* Check if command is within limits */ -+ if (count > LIRCBUF_SIZE || count%2 == 0) -+ return -EINVAL; -+ if (copy_from_user(wbuf, buf, n)) -+ return -EFAULT; -+ -+ /* MCE tx init header */ -+ cmdbuf[cmdcount++] = MCE_CONTROL_HEADER; -+ cmdbuf[cmdcount++] = 0x08; -+ cmdbuf[cmdcount++] = ir->transmitter_mask; -+ -+ /* Generate mce packet data */ -+ for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) { -+ signal_duration += wbuf[i]; -+ wbuf[i] = wbuf[i] / MCE_TIME_UNIT; -+ -+ do { /* loop to support long pulses/spaces > 127*50us=6.35ms */ -+ -+ /* Insert mce packet header every 4th entry */ -+ if ((cmdcount < MCE_CMDBUF_SIZE) && -+ (cmdcount - MCE_TX_HEADER_LENGTH) % -+ MCE_CODE_LENGTH == 0) -+ cmdbuf[cmdcount++] = MCE_PACKET_HEADER; -+ -+ /* Insert mce packet data */ -+ if (cmdcount < MCE_CMDBUF_SIZE) -+ cmdbuf[cmdcount++] = -+ (wbuf[i] < MCE_PULSE_BIT ? -+ wbuf[i] : MCE_MAX_PULSE_LENGTH) | -+ (i & 1 ? 0x00 : MCE_PULSE_BIT); -+ else -+ return -EINVAL; -+ } while ((wbuf[i] > MCE_MAX_PULSE_LENGTH) && -+ (wbuf[i] -= MCE_MAX_PULSE_LENGTH)); -+ } -+ -+ /* 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; -+ -+ /* Check if we have room for the empty packet at the end */ -+ if (cmdcount >= MCE_CMDBUF_SIZE) -+ return -EINVAL; -+ -+ /* All mce commands end with an empty packet (0x80) */ -+ cmdbuf[cmdcount++] = 0x80; -+ -+ /* Transmit the command to the mce device */ -+ mce_async_out(ir, cmdbuf, cmdcount); -+ -+ /* -+ * The lircd gap calculation expects the write function to -+ * wait the time it takes for the ircommand to be sent before -+ * it returns. -+ */ -+ do_gettimeofday(&end_time); -+ signal_duration -= (end_time.tv_usec - start_time.tv_usec) + -+ (end_time.tv_sec - start_time.tv_sec) * 1000000; -+ -+ /* delay with the closest number of ticks */ -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(usecs_to_jiffies(signal_duration)); -+ -+ return n; -+} -+ -+static void set_transmitter_mask(struct mceusb_dev *ir, unsigned int mask) -+{ -+ if (ir->flags.transmitter_mask_inverted) -+ ir->transmitter_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1; -+ else -+ ir->transmitter_mask = mask; -+} -+ -+ -+/* Sets the send carrier frequency */ -+static int set_send_carrier(struct mceusb_dev *ir, int carrier) -+{ -+ int clk = 10000000; -+ int prescaler = 0, divisor = 0; -+ unsigned char cmdbuf[] = { 0x9F, 0x06, 0x01, 0x80 }; -+ -+ /* Carrier is changed */ -+ if (ir->carrier_freq != carrier) { -+ -+ if (carrier <= 0) { -+ ir->carrier_freq = carrier; -+ dev_dbg(ir->d->dev, "SET_CARRIER disabling carrier " -+ "modulation\n"); -+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); -+ return carrier; -+ } -+ -+ for (prescaler = 0; prescaler < 4; ++prescaler) { -+ divisor = (clk >> (2 * prescaler)) / carrier; -+ if (divisor <= 0xFF) { -+ ir->carrier_freq = carrier; -+ cmdbuf[2] = prescaler; -+ cmdbuf[3] = divisor; -+ dev_dbg(ir->d->dev, "SET_CARRIER requesting " -+ "%d Hz\n", carrier); -+ -+ /* Transmit new carrier to mce device */ -+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); -+ return carrier; -+ } -+ } -+ -+ return -EINVAL; -+ -+ } -+ -+ return carrier; -+} -+ -+ -+static int mceusb_lirc_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg) -+{ -+ int result; -+ unsigned int ivalue; -+ unsigned long lvalue; -+ struct mceusb_dev *ir = NULL; -+ -+ /* Retrieve lirc_driver data for the device */ -+ ir = lirc_get_pdata(filep); -+ if (!ir || !ir->usb_ep_out) -+ return -EFAULT; -+ -+ -+ switch (cmd) { -+ case LIRC_SET_TRANSMITTER_MASK: -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ switch (ivalue) { -+ case 0x01: /* Transmitter 1 => 0x04 */ -+ case 0x02: /* Transmitter 2 => 0x02 */ -+ case 0x03: /* Transmitter 1 & 2 => 0x06 */ -+ set_transmitter_mask(ir, ivalue); -+ break; -+ -+ default: /* Unsupported transmitter mask */ -+ return MCE_MAX_CHANNELS; -+ } -+ -+ dev_dbg(ir->d->dev, ": SET_TRANSMITTERS mask=%d\n", ivalue); -+ break; -+ -+ case LIRC_GET_SEND_MODE: -+ -+ result = put_user(LIRC_SEND2MODE(LIRC_CAN_SEND_PULSE & -+ LIRC_CAN_SEND_MASK), -+ (unsigned long *) arg); -+ -+ if (result) -+ return result; -+ break; -+ -+ case LIRC_SET_SEND_MODE: -+ -+ result = get_user(lvalue, (unsigned long *) arg); -+ -+ if (result) -+ return result; -+ if (lvalue != (LIRC_MODE_PULSE&LIRC_CAN_SEND_MASK)) -+ return -EINVAL; -+ break; -+ -+ case LIRC_SET_SEND_CARRIER: -+ -+ result = get_user(ivalue, (unsigned int *) arg); -+ if (result) -+ return result; -+ -+ set_send_carrier(ir, ivalue); -+ break; -+ -+ default: -+ return lirc_dev_fop_ioctl(node, filep, cmd, arg); -+ } -+ -+ return 0; -+} -+ -+static struct file_operations lirc_fops = { -+ .owner = THIS_MODULE, -+ .write = mceusb_transmit_ir, -+ .ioctl = mceusb_lirc_ioctl, -+ .read = lirc_dev_fop_read, -+ .poll = lirc_dev_fop_poll, -+ .open = lirc_dev_fop_open, -+ .release = lirc_dev_fop_close, -+}; -+ -+static int mceusb_gen1_init(struct mceusb_dev *ir) -+{ -+ int i, ret; -+ char junk[64], data[8]; -+ int partial = 0; -+ -+ /* -+ * Clear off the first few messages. These look like calibration -+ * or test data, I can't really tell. This also flushes in case -+ * we have random ir data queued up. -+ */ -+ for (i = 0; i < 40; i++) -+ usb_bulk_msg(ir->usbdev, -+ usb_rcvbulkpipe(ir->usbdev, -+ ir->usb_ep_in->bEndpointAddress), -+ junk, 64, &partial, HZ * 10); -+ -+ ir->is_pulse = 1; -+ -+ memset(data, 0, 8); -+ -+ /* Get Status */ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ USB_REQ_GET_STATUS, USB_DIR_IN, -+ 0, 0, data, 2, HZ * 3); -+ -+ /* ret = usb_get_status( ir->usbdev, 0, 0, data ); */ -+ dev_dbg(ir->d->dev, "%s - ret = %d status = 0x%x 0x%x\n", __func__, -+ ret, data[0], data[1]); -+ -+ /* -+ * This is a strange one. They issue a set address to the device -+ * on the receive control pipe and expect a certain value pair back -+ */ -+ memset(data, 0, 8); -+ -+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), -+ USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, -+ data, 2, HZ * 3); -+ dev_dbg(ir->d->dev, "%s - ret = %d, devnum = %d\n", -+ __func__, ret, ir->usbdev->devnum); -+ dev_dbg(ir->d->dev, "%s - data[0] = %d, data[1] = %d\n", -+ __func__, data[0], data[1]); -+ -+ /* set feature: bit rate 38400 bps */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, -+ 0xc04e, 0x0000, NULL, 0, HZ * 3); -+ -+ dev_dbg(ir->d->dev, "%s - ret = %d\n", __func__, ret); -+ -+ /* bRequest 4: set char length to 8 bits */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ 4, USB_TYPE_VENDOR, -+ 0x0808, 0x0000, NULL, 0, HZ * 3); -+ dev_dbg(ir->d->dev, "%s - retB = %d\n", __func__, ret); -+ -+ /* bRequest 2: set handshaking to use DTR/DSR */ -+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), -+ 2, USB_TYPE_VENDOR, -+ 0x0000, 0x0100, NULL, 0, HZ * 3); -+ dev_dbg(ir->d->dev, "%s - retC = %d\n", __func__, ret); -+ -+ return ret; -+ -+}; -+ -+static int mceusb_dev_probe(struct usb_interface *intf, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct usb_host_interface *idesc; -+ struct usb_endpoint_descriptor *ep = NULL; -+ struct usb_endpoint_descriptor *ep_in = NULL; -+ struct usb_endpoint_descriptor *ep_out = NULL; -+ struct usb_host_config *config; -+ struct mceusb_dev *ir = NULL; -+ struct lirc_driver *driver = NULL; -+ struct lirc_buffer *rbuf = NULL; -+ int devnum, pipe, maxp; -+ int minor = 0; -+ int i; -+ char buf[63], name[128] = ""; -+ int mem_failure = 0; -+ bool is_gen3; -+ bool is_microsoft_gen1; -+ bool is_pinnacle; -+ -+ dev_dbg(&intf->dev, ": %s called\n", __func__); -+ -+ usb_reset_device(dev); -+ -+ config = dev->actconfig; -+ -+ 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; -+ -+ is_pinnacle = usb_match_id(intf, pinnacle_list) ? 1 : 0; -+ -+ /* step through the endpoints to find first bulk in and out endpoint */ -+ for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { -+ ep = &idesc->endpoint[i].desc; -+ -+ if ((ep_in == NULL) -+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ == USB_DIR_IN) -+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_BULK) -+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_INT))) { -+ -+ dev_dbg(&intf->dev, ": acceptable inbound endpoint " -+ "found\n"); -+ ep_in = ep; -+ ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; -+ if (!is_pinnacle) -+ /* -+ * Ideally, we'd use what the device offers up, -+ * but that leads to non-functioning first and -+ * second-gen devices, and many devices have an -+ * invalid bInterval of 0. Pinnacle devices -+ * don't work witha bInterval of 1 though. -+ */ -+ ep_in->bInterval = 1; -+ } -+ -+ if ((ep_out == NULL) -+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) -+ == USB_DIR_OUT) -+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_BULK) -+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) -+ == USB_ENDPOINT_XFER_INT))) { -+ -+ dev_dbg(&intf->dev, ": acceptable outbound endpoint " -+ "found\n"); -+ ep_out = ep; -+ ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; -+ if (!is_pinnacle) -+ /* -+ * Ideally, we'd use what the device offers up, -+ * but that leads to non-functioning first and -+ * second-gen devices, and many devices have an -+ * invalid bInterval of 0. Pinnacle devices -+ * don't work witha bInterval of 1 though. -+ */ -+ ep_out->bInterval = 1; -+ } -+ } -+ if (ep_in == NULL) { -+ dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n"); -+ return -ENODEV; -+ } -+ -+ devnum = dev->devnum; -+ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress); -+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); -+ -+ mem_failure = 0; -+ ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL); -+ if (!ir) -+ goto mem_alloc_fail; -+ -+ driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); -+ if (!driver) -+ goto mem_alloc_fail; -+ -+ rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); -+ if (!rbuf) -+ goto mem_alloc_fail; -+ -+ if (lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE)) -+ goto mem_alloc_fail; -+ -+ ir->buf_in = usb_buffer_alloc(dev, maxp, GFP_ATOMIC, &ir->dma_in); -+ if (!ir->buf_in) -+ goto buf_in_alloc_fail; -+ -+ ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); -+ if (!ir->urb_in) -+ goto urb_in_alloc_fail; -+ -+ strcpy(driver->name, DRIVER_NAME); -+ driver->minor = -1; -+ driver->features = LIRC_CAN_SEND_PULSE | -+ LIRC_CAN_SET_TRANSMITTER_MASK | -+ LIRC_CAN_REC_MODE2 | -+ LIRC_CAN_SET_SEND_CARRIER; -+ driver->data = ir; -+ driver->rbuf = rbuf; -+ driver->set_use_inc = &mceusb_ir_open; -+ driver->set_use_dec = &mceusb_ir_close; -+ driver->code_length = sizeof(int) * 8; -+ driver->fops = &lirc_fops; -+ driver->dev = &intf->dev; -+ driver->owner = THIS_MODULE; -+ -+ mutex_init(&ir->dev_lock); -+ init_waitqueue_head(&ir->wait_out); -+ -+ minor = lirc_register_driver(driver); -+ if (minor < 0) -+ goto lirc_register_fail; -+ -+ driver->minor = minor; -+ ir->d = driver; -+ ir->devnum = devnum; -+ ir->usbdev = dev; -+ ir->len_in = maxp; -+ ir->overflow_len = 0; -+ ir->flags.connected = 0; -+ ir->flags.gen3 = is_gen3; -+ ir->flags.microsoft_gen1 = is_microsoft_gen1; -+ ir->flags.transmitter_mask_inverted = -+ usb_match_id(intf, transmitter_mask_list) ? 0 : 1; -+ -+ ir->lircdata = PULSE_MASK; -+ ir->is_pulse = 0; -+ -+ /* ir->flags.transmitter_mask_inverted must be set */ -+ set_transmitter_mask(ir, MCE_DEFAULT_TX_MASK); -+ /* Saving usb interface data for use by the transmitter routine */ -+ ir->usb_ep_in = ep_in; -+ ir->usb_ep_out = ep_out; -+ -+ if (dev->descriptor.iManufacturer -+ && usb_string(dev, dev->descriptor.iManufacturer, -+ buf, sizeof(buf)) > 0) -+ strlcpy(name, buf, sizeof(name)); -+ if (dev->descriptor.iProduct -+ && usb_string(dev, dev->descriptor.iProduct, -+ buf, sizeof(buf)) > 0) -+ snprintf(name + strlen(name), sizeof(name) - strlen(name), -+ " %s", buf); -+ -+ /* inbound data */ -+ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, -+ maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval); -+ ir->urb_in->transfer_dma = ir->dma_in; -+ ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ -+ if (is_pinnacle) { -+ int usbret; -+ -+ /* -+ * I have no idea why but this reset seems to be crucial to -+ * getting the device to do outbound IO correctly - without -+ * this the device seems to hang, ignoring all input - although -+ * IR signals are correctly sent from the device, no input is -+ * interpreted by the device and the host never does the -+ * completion routine -+ */ -+ usbret = usb_reset_configuration(dev); -+ dev_info(ir->d->dev, "usb reset config ret %x\n", usbret); -+ } -+ -+ /* initialize device */ -+ if (ir->flags.gen3) { -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* device reset */ -+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get the carrier and frequency */ -+ mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get the transmitter bitmask */ -+ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get receiver timeout value */ -+ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get receiver sensor setting */ -+ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ } else if (ir->flags.microsoft_gen1) { -+ /* original ms mce device requires some additional setup */ -+ mceusb_gen1_init(ir); -+ -+ } else { -+ mce_sync_in(ir, NULL, maxp); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* device reset */ -+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* get hw/sw revision? */ -+ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION)); -+ mce_sync_in(ir, NULL, maxp); -+ -+ /* unknown what this actually returns... */ -+ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN)); -+ mce_sync_in(ir, NULL, maxp); -+ } -+ -+ /* -+ * if we don't issue the correct number of receives (mce_sync_in()) -+ * for each outbound, then the first few ir pulses will be interpreted -+ * by the usb_async_callback routine - we should ensure we have the -+ * right amount OR less - as the mceusb_dev_recv routine will handle -+ * the control packets OK - they start with 0x9f - but the async -+ * callback doesn't handle ir pulse packets -+ */ -+ mce_sync_in(ir, NULL, maxp); -+ -+ usb_set_intfdata(intf, ir); -+ -+ dev_info(ir->d->dev, "Registered %s on usb%d:%d\n", name, -+ dev->bus->busnum, devnum); -+ -+ return 0; -+ -+ /* Error-handling path */ -+lirc_register_fail: -+ usb_free_urb(ir->urb_in); -+urb_in_alloc_fail: -+ usb_buffer_free(dev, maxp, ir->buf_in, ir->dma_in); -+buf_in_alloc_fail: -+ lirc_buffer_free(rbuf); -+mem_alloc_fail: -+ kfree(rbuf); -+ kfree(driver); -+ kfree(ir); -+ dev_info(&intf->dev, "out of memory (code=%d)\n", mem_failure); -+ -+ return -ENOMEM; -+} -+ -+ -+static void mceusb_dev_disconnect(struct usb_interface *intf) -+{ -+ struct usb_device *dev = interface_to_usbdev(intf); -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ -+ usb_set_intfdata(intf, NULL); -+ -+ if (!ir || !ir->d) -+ return; -+ -+ ir->usbdev = NULL; -+ wake_up_all(&ir->wait_out); -+ -+ mutex_lock(&ir->dev_lock); -+ usb_kill_urb(ir->urb_in); -+ usb_free_urb(ir->urb_in); -+ usb_buffer_free(dev, ir->len_in, ir->buf_in, ir->dma_in); -+ mutex_unlock(&ir->dev_lock); -+ -+ unregister_from_lirc(ir); -+} -+ -+static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ dev_info(ir->d->dev, "suspend\n"); -+ usb_kill_urb(ir->urb_in); -+ return 0; -+} -+ -+static int mceusb_dev_resume(struct usb_interface *intf) -+{ -+ struct mceusb_dev *ir = usb_get_intfdata(intf); -+ dev_info(ir->d->dev, "resume\n"); -+ if (usb_submit_urb(ir->urb_in, GFP_ATOMIC)) -+ return -EIO; -+ return 0; -+} -+ -+static struct usb_driver mceusb_dev_driver = { -+ .name = DRIVER_NAME, -+ .probe = mceusb_dev_probe, -+ .disconnect = mceusb_dev_disconnect, -+ .suspend = mceusb_dev_suspend, -+ .resume = mceusb_dev_resume, -+ .reset_resume = mceusb_dev_resume, -+ .id_table = mceusb_dev_table -+}; -+ -+static int __init mceusb_dev_init(void) -+{ -+ int i; -+ -+ printk(KERN_INFO DRIVER_NAME ": " DRIVER_DESC " " DRIVER_VERSION "\n"); -+ printk(KERN_INFO DRIVER_NAME ": " DRIVER_AUTHOR "\n"); -+ if (debug) -+ printk(KERN_DEBUG DRIVER_NAME ": debug mode enabled\n"); -+ -+ i = usb_register(&mceusb_dev_driver); -+ if (i < 0) { -+ printk(KERN_ERR DRIVER_NAME -+ ": usb register failed, result = %d\n", i); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void __exit mceusb_dev_exit(void) -+{ -+ usb_deregister(&mceusb_dev_driver); -+} -+ -+module_init(mceusb_dev_init); -+module_exit(mceusb_dev_exit); -+ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, mceusb_dev_table); -+/* this was originally lirc_mceusb2, lirc_mceusb and lirc_mceusb2 merged now */ -+MODULE_ALIAS("lirc_mceusb2"); -+ -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug enabled or not"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,709 @@ +diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c +new file mode 100644 +index 0000000..df12e7b +--- /dev/null ++++ b/drivers/staging/lirc/lirc_parallel.c +@@ -0,0 +1,705 @@ +/* + * lirc_parallel.c + * @@ -7714,8 +5332,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c linux-2.6.33.2.patc +#include +#include + -+#include -+#include "lirc_dev.h" ++#include ++#include + +#include "lirc_parallel.h" + @@ -7743,10 +5361,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c linux-2.6.33.2.patc +unsigned int default_timer = LIRC_TIMER; +#endif + -+#define WBUF_SIZE (256) +#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */ + -+static int wbuf[WBUF_SIZE]; +static int rbuf[RBUF_SIZE]; + +DECLARE_WAIT_QUEUE_HEAD(lirc_wait); @@ -8048,20 +5664,19 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c linux-2.6.33.2.patc + unsigned int level, newlevel; + unsigned long flags; + int counttimer; ++ int *wbuf; + + if (!is_claimed) + return -EBUSY; + -+ if (n % sizeof(int)) -+ return -EINVAL; -+ + count = n / sizeof(int); + -+ if (count > WBUF_SIZE || count % 2 == 0) ++ if (n % sizeof(int) || count % 2 == 0) + return -EINVAL; + -+ if (copy_from_user(wbuf, buf, n)) -+ return -EFAULT; ++ wbuf = memdup_user(buf, n); ++ if (IS_ERR(wbuf)) ++ return PTR_ERR(wbuf); + +#ifdef LIRC_TIMER + if (timer == 0) { @@ -8130,8 +5745,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c linux-2.6.33.2.patc + return 0; +} + -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) ++static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + int result; + unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK | @@ -8215,7 +5829,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c linux-2.6.33.2.patc + .read = lirc_read, + .write = lirc_write, + .poll = lirc_poll, -+ .ioctl = lirc_ioctl, ++ .unlocked_ioctl = lirc_ioctl, + .open = lirc_open, + .release = lirc_close +}; @@ -8373,9 +5987,11 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.c linux-2.6.33.2.patc + +module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.h linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.h ---- linux-2.6.33.2/drivers/input/lirc/lirc_parallel.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_parallel.h 2010-04-06 23:47:21.000000000 +0200 +diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/lirc/lirc_parallel.h +new file mode 100644 +index 0000000..4bed6af +--- /dev/null ++++ b/drivers/staging/lirc/lirc_parallel.h @@ -0,0 +1,26 @@ +/* lirc_parallel.h */ + @@ -8403,10 +6019,12 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_parallel.h linux-2.6.33.2.patc +#define LIRC_PARALLEL_TRANSMITTER_MASK ((1< +#include + -+#include -+#include "lirc_dev.h" ++#include ++#include + + +#define MOD_AUTHOR "Oliver Stabel , " \ @@ -8480,8 +6098,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sasem.c linux-2.6.33.2.patch/d + +/* VFD file_operations function prototypes */ +static int vfd_open(struct inode *inode, struct file *file); -+static int vfd_ioctl(struct inode *inode, struct file *file, -+ unsigned cmd, unsigned long arg); ++static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg); +static int vfd_close(struct inode *inode, struct file *file); +static ssize_t vfd_write(struct file *file, const char *buf, + size_t n_bytes, loff_t *pos); @@ -8495,6 +6112,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sasem.c linux-2.6.33.2.patch/d +static void __exit sasem_exit(void); + +/*** G L O B A L S ***/ ++#define SASEM_DATA_BUF_SZ 32 + +struct sasem_context { + @@ -8515,7 +6133,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sasem.c linux-2.6.33.2.patch/d + unsigned char usb_tx_buf[8]; + + struct tx_t { -+ unsigned char data_buf[32]; /* user data buffer */ ++ unsigned char data_buf[SASEM_DATA_BUF_SZ]; /* user data buffer */ + struct completion finished; /* wait for write to finish */ + atomic_t busy; /* write in progress */ + int status; /* status of tx completion */ @@ -8532,7 +6150,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sasem.c linux-2.6.33.2.patch/d + .owner = THIS_MODULE, + .open = &vfd_open, + .write = &vfd_write, -+ .ioctl = &vfd_ioctl, ++ .unlocked_ioctl = &vfd_ioctl, + .release = &vfd_close, +}; + @@ -8653,8 +6271,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sasem.c linux-2.6.33.2.patch/d + * Called when the VFD device (e.g. /dev/usb/lcd) + * is closed by the application. + */ -+static int vfd_ioctl(struct inode *inode, struct file *file, -+ unsigned cmd, unsigned long arg) ++static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg) +{ + struct sasem_context *context = NULL; + @@ -8773,6 +6390,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sasem.c linux-2.6.33.2.patch/d + int i; + int retval = 0; + struct sasem_context *context; ++ int *data_buf; + + context = (struct sasem_context *) file->private_data; + if (!context) { @@ -8788,18 +6406,20 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sasem.c linux-2.6.33.2.patch/d + goto exit; + } + -+ if (n_bytes <= 0 || n_bytes > 32) { ++ if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) { + err("%s: invalid payload size", __func__); + retval = -EINVAL; + goto exit; + } + -+ retval = copy_from_user(context->tx.data_buf, buf, n_bytes); -+ if (retval < 0) -+ goto exit; ++ data_buf = memdup_user(buf, n_bytes); ++ if (PTR_ERR(data_buf)) ++ return PTR_ERR(data_buf); ++ ++ memcpy(context->tx.data_buf, data_buf, n_bytes); + + /* Pad with spaces */ -+ for (i = n_bytes; i < 32; ++i) ++ for (i = n_bytes; i < SASEM_DATA_BUF_SZ; ++i) + context->tx.data_buf[i] = ' '; + + /* Nine 8 byte packets to be sent */ @@ -9338,10 +6958,12 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sasem.c linux-2.6.33.2.patch/d + +module_init(sasem_init); +module_exit(sasem_exit); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_serial.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_serial.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_serial.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1317 @@ +diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c +new file mode 100644 +index 0000000..d2ea3f0 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_serial.c +@@ -0,0 +1,1313 @@ +/* + * lirc_serial.c + * @@ -9424,8 +7046,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/ +#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ +#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ + -+#include -+#include "lirc_dev.h" ++#include ++#include + +#define LIRC_DRIVER_NAME "lirc_serial" + @@ -9578,14 +7200,11 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/ +/* This MUST be a power of two! It has to be larger than 1 as well. */ + +#define RBUF_LEN 256 -+#define WBUF_LEN 256 + +static struct timeval lasttv = {0, 0}; + +static struct lirc_buffer rbuf; + -+static int wbuf[WBUF_LEN]; -+ +static unsigned int freq = 38000; +static unsigned int duty_cycle = 50; + @@ -10304,17 +7923,17 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/ + int i, count; + unsigned long flags; + long delta = 0; ++ int *wbuf; + -+ if (!(hardware[type].features&LIRC_CAN_SEND_PULSE)) ++ if (!(hardware[type].features & LIRC_CAN_SEND_PULSE)) + return -EBADF; + -+ if (n % sizeof(int)) -+ return -EINVAL; + count = n / sizeof(int); -+ if (count > WBUF_LEN || count % 2 == 0) ++ if (n % sizeof(int) || count % 2 == 0) + return -EINVAL; -+ if (copy_from_user(wbuf, buf, n)) -+ return -EFAULT; ++ wbuf = memdup_user(buf, n); ++ if (PTR_ERR(wbuf)) ++ return PTR_ERR(wbuf); + spin_lock_irqsave(&hardware[type].lock, flags); + if (type == LIRC_IRDEO) { + /* DTR, RTS down */ @@ -10322,7 +7941,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/ + } + for (i = 0; i < count; i++) { + if (i%2) -+ hardware[type].send_space(wbuf[i]-delta); ++ hardware[type].send_space(wbuf[i] - delta); + else + delta = hardware[type].send_pulse(wbuf[i]); + } @@ -10331,8 +7950,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/ + return n; +} + -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) ++static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + int result; + unsigned long value; @@ -10393,7 +8011,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/ + break; + + default: -+ return lirc_dev_fop_ioctl(node, filep, cmd, arg); ++ return lirc_dev_fop_ioctl(filep, cmd, arg); + } + return 0; +} @@ -10401,7 +8019,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/ +static struct file_operations lirc_fops = { + .owner = THIS_MODULE, + .write = lirc_write, -+ .ioctl = lirc_ioctl, ++ .unlocked_ioctl = lirc_ioctl, + .read = lirc_dev_fop_read, + .poll = lirc_dev_fop_poll, + .open = lirc_dev_fop_open, @@ -10659,10 +8277,12 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_serial.c linux-2.6.33.2.patch/ + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_sir.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_sir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_sir.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1283 @@ +diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c +new file mode 100644 +index 0000000..97146d1 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_sir.c +@@ -0,0 +1,1282 @@ +/* + * LIRC SIR driver, (C) 2000 Milan Pikula + * @@ -10728,8 +8348,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/dri + +#include + -+#include -+#include "lirc_dev.h" ++#include ++#include + +/* SECTION: Definitions */ + @@ -10837,7 +8457,6 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/dri + +static int rx_buf[RBUF_LEN]; +static unsigned int rx_tail, rx_head; -+static int tx_buf[WBUF_LEN]; + +static int debug; +#define dprintk(fmt, args...) \ @@ -10855,8 +8474,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/dri + loff_t *ppos); +static ssize_t lirc_write(struct file *file, const char *buf, size_t n, + loff_t *pos); -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg); ++static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); +static void add_read_queue(int flag, unsigned long val); +static int init_chrdev(void); +static void drop_chrdev(void); @@ -10960,26 +8578,28 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/dri + loff_t *pos) +{ + unsigned long flags; -+ int i; ++ int i, count; ++ int *tx_buf; + -+ if (n % sizeof(int) || (n / sizeof(int)) > WBUF_LEN) ++ count = n / sizeof(int); ++ if (n % sizeof(int) || count % 2 == 0) + return -EINVAL; -+ if (copy_from_user(tx_buf, buf, n)) -+ return -EFAULT; ++ tx_buf = memdup_user(buf, n); ++ if (IS_ERR(tx_buf)) ++ return PTR_ERR(tx_buf); + i = 0; -+ n /= sizeof(int); +#ifdef LIRC_ON_SA1100 + /* disable receiver */ + Ser2UTCR3 = 0; +#endif + local_irq_save(flags); + while (1) { -+ if (i >= n) ++ if (i >= count) + break; + if (tx_buf[i]) + send_pulse(tx_buf[i]); + i++; -+ if (i >= n) ++ if (i >= count) + break; + if (tx_buf[i]) + send_space(tx_buf[i]); @@ -10995,11 +8615,10 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/dri + /* enable receiver */ + Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE; +#endif -+ return n; ++ return count; +} + -+static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) ++static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + unsigned long value = 0; @@ -11122,7 +8741,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/dri + .read = lirc_read, + .write = lirc_write, + .poll = lirc_poll, -+ .ioctl = lirc_ioctl, ++ .unlocked_ioctl = lirc_ioctl, + .open = lirc_dev_fop_open, + .release = lirc_dev_fop_close, +}; @@ -11946,9 +9565,11 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_sir.c linux-2.6.33.2.patch/dri + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_streamzap.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_streamzap.c 2010-04-06 23:47:21.000000000 +0200 +diff --git a/drivers/staging/lirc/lirc_streamzap.c b/drivers/staging/lirc/lirc_streamzap.c +new file mode 100644 +index 0000000..5b46ac4 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_streamzap.c @@ -0,0 +1,821 @@ +/* + * Streamzap Remote Control driver @@ -11990,8 +9611,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.pat +#include +#include + -+#include -+#include "lirc_dev.h" ++#include ++#include + +#define DRIVER_VERSION "1.28" +#define DRIVER_NAME "lirc_streamzap" @@ -12104,8 +9725,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.pat +static void usb_streamzap_irq(struct urb *urb); +static int streamzap_use_inc(void *data); +static void streamzap_use_dec(void *data); -+static int streamzap_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg); ++static long streamzap_ioctl(struct file *filep, unsigned int cmd, ++ unsigned long arg); +static int streamzap_suspend(struct usb_interface *intf, pm_message_t message); +static int streamzap_resume(struct usb_interface *intf); + @@ -12385,7 +10006,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.pat + +static struct file_operations streamzap_fops = { + .owner = THIS_MODULE, -+ .ioctl = streamzap_ioctl, ++ .unlocked_ioctl = streamzap_ioctl, + .read = lirc_dev_fop_read, + .write = lirc_dev_fop_write, + .poll = lirc_dev_fop_poll, @@ -12458,7 +10079,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.pat + /* Allocate the USB buffer and IRQ URB */ + + sz->buf_in_len = sz->endpoint->wMaxPacketSize; -+ sz->buf_in = usb_buffer_alloc(sz->udev, sz->buf_in_len, ++ sz->buf_in = usb_alloc_coherent(sz->udev, sz->buf_in_len, + GFP_ATOMIC, &sz->dma_in); + if (sz->buf_in == NULL) + goto free_sz; @@ -12565,7 +10186,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.pat + + if (sz) { + usb_free_urb(sz->urb_in); -+ usb_buffer_free(udev, sz->buf_in_len, sz->buf_in, sz->dma_in); ++ usb_free_coherent(udev, sz->buf_in_len, sz->buf_in, sz->dma_in); + kfree(sz); + } + @@ -12622,8 +10243,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.pat + sz->in_use--; +} + -+static int streamzap_ioctl(struct inode *node, struct file *filep, -+ unsigned int cmd, unsigned long arg) ++static long streamzap_ioctl(struct file *filep, unsigned int cmd, ++ unsigned long arg) +{ + int result = 0; + int val; @@ -12645,7 +10266,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.pat + } + break; + default: -+ return lirc_dev_fop_ioctl(node, filep, cmd, arg); ++ return lirc_dev_fop_ioctl(filep, cmd, arg); + } + return result; +} @@ -12682,7 +10303,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.pat + + usb_free_urb(sz->urb_in); + -+ usb_buffer_free(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); ++ usb_free_coherent(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); + + minor = sz->driver->minor; + kfree(sz->driver->rbuf); @@ -12771,9 +10392,11 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_streamzap.c linux-2.6.33.2.pat + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging messages"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ttusbir.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_ttusbir.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_ttusbir.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_ttusbir.c 2010-04-06 23:47:21.000000000 +0200 +diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/lirc/lirc_ttusbir.c +new file mode 100644 +index 0000000..1f1da47 +--- /dev/null ++++ b/drivers/staging/lirc/lirc_ttusbir.c @@ -0,0 +1,397 @@ +/* + * lirc_ttusbir.c @@ -12815,8 +10438,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ttusbir.c linux-2.6.33.2.patch +#include +#include + -+#include -+#include "lirc_dev.h" ++#include ++#include + +MODULE_DESCRIPTION("TechnoTrend USB IR device driver for LIRC"); +MODULE_AUTHOR("Stefan Macher (st_maker-lirc@yahoo.de)"); @@ -13172,10 +10795,12 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_ttusbir.c linux-2.6.33.2.patch + +module_init(ttusbir_init_module); +module_exit(ttusbir_exit_module); -diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c linux-2.6.33.2.patch/drivers/input/lirc/lirc_zilog.c ---- linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/lirc_zilog.c 2010-04-06 23:47:21.000000000 +0200 -@@ -0,0 +1,1388 @@ +diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c +new file mode 100644 +index 0000000..1b013bf +--- /dev/null ++++ b/drivers/staging/lirc/lirc_zilog.c +@@ -0,0 +1,1387 @@ +/* + * i2c IR lirc driver for devices with zilog IR processors + * @@ -13235,8 +10860,8 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c linux-2.6.33.2.patch/d +#include +#include + -+#include "lirc_dev.h" -+#include ++#include ++#include + +struct IR { + struct lirc_driver l; @@ -14170,8 +11795,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c linux-2.6.33.2.patch/d + return ret; +} + -+static int ioctl(struct inode *node, struct file *filep, unsigned int cmd, -+ unsigned long arg) ++static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + struct IR *ir = (struct IR *)filep->private_data; + int result; @@ -14317,7 +11941,7 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c linux-2.6.33.2.patch/d + .read = read, + .write = write, + .poll = poll, -+ .ioctl = ioctl, ++ .unlocked_ioctl = ioctl, + .open = open, + .release = close +}; @@ -14564,2772 +12188,3 @@ diff -Naur linux-2.6.33.2/drivers/input/lirc/lirc_zilog.c linux-2.6.33.2.patch/d + +module_param(disable_tx, bool, 0644); +MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device"); -diff -Naur linux-2.6.33.2/drivers/input/lirc/Makefile linux-2.6.33.2.patch/drivers/input/lirc/Makefile ---- linux-2.6.33.2/drivers/input/lirc/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/lirc/Makefile 2010-04-07 22:05:13.630122819 +0200 -@@ -0,0 +1,21 @@ -+# Makefile for the lirc drivers. -+# -+ -+# Each configuration option enables a list of files. -+ -+obj-$(CONFIG_INPUT_LIRC) += lirc_dev.o -+obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o -+obj-$(CONFIG_LIRC_ENE0100) += lirc_ene0100.o -+obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o -+obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o -+obj-$(CONFIG_LIRC_IMON) += lirc_imon.o -+obj-$(CONFIG_LIRC_IT87) += lirc_it87.o -+obj-$(CONFIG_LIRC_ITE8709) += lirc_ite8709.o -+obj-$(CONFIG_LIRC_MCEUSB) += lirc_mceusb.o -+obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o -+obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o -+obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o -+obj-$(CONFIG_LIRC_SIR) += lirc_sir.o -+obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap.o -+obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o -+obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o -diff -Naur linux-2.6.33.2/drivers/input/Makefile linux-2.6.33.2.patch/drivers/input/Makefile ---- linux-2.6.33.2/drivers/input/Makefile 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/Makefile 2010-04-07 22:05:13.630122819 +0200 -@@ -26,3 +26,5 @@ - obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o - - obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o -+ -+obj-$(CONFIG_INPUT_LIRC) += lirc/ -diff -Naur linux-2.6.33.2/drivers/input/misc/imon.c linux-2.6.33.2.patch/drivers/input/misc/imon.c ---- linux-2.6.33.2/drivers/input/misc/imon.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/drivers/input/misc/imon.c 2010-04-07 22:05:13.633152235 +0200 -@@ -0,0 +1,2537 @@ -+/* -+ * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD -+ * -+ * Copyright(C) 2009 Jarod Wilson -+ * Portions based on the original lirc_imon driver, -+ * Copyright(C) 2004 Venky Raju(dev@venky.ws) -+ * -+ * imon is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MOD_AUTHOR "Jarod Wilson " -+#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" -+#define MOD_NAME "imon" -+#define MOD_VERSION "0.8" -+ -+#define DISPLAY_MINOR_BASE 144 -+#define DEVICE_NAME "lcd%d" -+ -+#define BUF_CHUNK_SIZE 8 -+#define BUF_SIZE 128 -+ -+#define BIT_DURATION 250 /* each bit received is 250us */ -+ -+#define IMON_CLOCK_ENABLE_PACKETS 2 -+#define IMON_KEY_RELEASE_OFFSET 1000 -+ -+/*** P R O T O T Y P E S ***/ -+ -+/* USB Callback prototypes */ -+static int imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id); -+static void imon_disconnect(struct usb_interface *interface); -+static void usb_rx_callback_intf0(struct urb *urb); -+static void usb_rx_callback_intf1(struct urb *urb); -+static void usb_tx_callback(struct urb *urb); -+ -+/* suspend/resume support */ -+static int imon_resume(struct usb_interface *intf); -+static int imon_suspend(struct usb_interface *intf, pm_message_t message); -+ -+/* Display file_operations function prototypes */ -+static int display_open(struct inode *inode, struct file *file); -+static int display_close(struct inode *inode, struct file *file); -+ -+/* VFD write operation */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/* LCD file_operations override function prototypes */ -+static ssize_t lcd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos); -+ -+/*** G L O B A L S ***/ -+ -+struct imon_context { -+ struct device *dev; -+ struct usb_device *usbdev_intf0; -+ /* Newer devices have two interfaces */ -+ struct usb_device *usbdev_intf1; -+ bool display_supported; /* not all controllers do */ -+ bool display_isopen; /* display port has been opened */ -+ bool ir_isassociating; /* IR port open for association */ -+ bool dev_present_intf0; /* USB device presence, interface 0 */ -+ bool dev_present_intf1; /* USB device presence, interface 1 */ -+ struct mutex lock; /* to lock this object */ -+ wait_queue_head_t remove_ok; /* For unexpected USB disconnects */ -+ -+ struct usb_endpoint_descriptor *rx_endpoint_intf0; -+ struct usb_endpoint_descriptor *rx_endpoint_intf1; -+ struct usb_endpoint_descriptor *tx_endpoint; -+ struct urb *rx_urb_intf0; -+ struct urb *rx_urb_intf1; -+ struct urb *tx_urb; -+ bool tx_control; -+ unsigned char usb_rx_buf[8]; -+ unsigned char usb_tx_buf[8]; -+ -+ struct tx_t { -+ unsigned char data_buf[35]; /* user data buffer */ -+ struct completion finished; /* wait for write to finish */ -+ bool busy; /* write in progress */ -+ int status; /* status of tx completion */ -+ } tx; -+ -+ u16 vendor; /* usb vendor ID */ -+ u16 product; /* usb product ID */ -+ int ir_protocol; /* iMON or MCE (RC6) IR protocol? */ -+ struct input_dev *idev; /* input device for remote */ -+ struct input_dev *touch; /* input device for touchscreen */ -+ int ki; /* current input keycode key index */ -+ u16 kc; /* current input keycode */ -+ u16 last_keycode; /* last reported input keycode */ -+ u8 mce_toggle_bit; /* last mce toggle bit */ -+ int display_type; /* store the display type */ -+ bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */ -+ int touch_x; /* x coordinate on touchscreen */ -+ int touch_y; /* y coordinate on touchscreen */ -+ char name_idev[128]; /* input device name */ -+ char phys_idev[64]; /* input device phys path */ -+ struct timer_list itimer; /* input device timer, need for rc6 */ -+ char name_touch[128]; /* touch screen name */ -+ char phys_touch[64]; /* touch screen phys path */ -+ struct timer_list ttimer; /* touch screen timer */ -+}; -+ -+#define TOUCH_TIMEOUT (HZ/30) -+#define MCE_TIMEOUT_MS 200 -+ -+/* vfd character device file operations */ -+static const struct file_operations vfd_fops = { -+ .owner = THIS_MODULE, -+ .open = &display_open, -+ .write = &vfd_write, -+ .release = &display_close -+}; -+ -+/* lcd character device file operations */ -+static const struct file_operations lcd_fops = { -+ .owner = THIS_MODULE, -+ .open = &display_open, -+ .write = &lcd_write, -+ .release = &display_close -+}; -+ -+enum { -+ IMON_DISPLAY_TYPE_AUTO = 0, -+ IMON_DISPLAY_TYPE_VFD = 1, -+ IMON_DISPLAY_TYPE_LCD = 2, -+ IMON_DISPLAY_TYPE_VGA = 3, -+ IMON_DISPLAY_TYPE_NONE = 4, -+}; -+ -+enum { -+ IMON_IR_PROTOCOL_IMON = 0, -+ IMON_IR_PROTOCOL_MCE = 1, -+ IMON_IR_PROTOCOL_IMON_NOPAD = 2, -+}; -+ -+enum { -+ IMON_BUTTON_IMON = 0, -+ IMON_BUTTON_MCE = 1, -+ IMON_BUTTON_PANEL = 2, -+}; -+ -+/* -+ * USB Device ID for iMON USB Control Boards -+ * -+ * The Windows drivers contain 6 different inf files, more or less one for -+ * each new device until the 0x0034-0x0046 devices, which all use the same -+ * driver. Some of the devices in the 34-46 range haven't been definitively -+ * identified yet. Early devices have either a TriGem Computer, Inc. or a -+ * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later -+ * devices use the SoundGraph vendor ID (0x15c2). This driver only supports -+ * the ffdc and later devices, which do onboard decoding. -+ */ -+static struct usb_device_id imon_usb_id_table[] = { -+ /* -+ * Several devices with this same device ID, all use iMON_PAD.inf -+ * SoundGraph iMON PAD (IR & VFD) -+ * SoundGraph iMON PAD (IR & LCD) -+ * SoundGraph iMON Knob (IR only) -+ */ -+ { USB_DEVICE(0x15c2, 0xffdc) }, -+ -+ /* -+ * Newer devices, all driven by the latest iMON Windows driver, full -+ * list of device IDs extracted via 'strings Setup/data1.hdr |grep 15c2' -+ * Need user input to fill in details on unknown devices. -+ */ -+ /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */ -+ { USB_DEVICE(0x15c2, 0x0034) }, -+ /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ -+ { USB_DEVICE(0x15c2, 0x0035) }, -+ /* SoundGraph iMON OEM VFD (IR & VFD) */ -+ { USB_DEVICE(0x15c2, 0x0036) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x0037) }, -+ /* SoundGraph iMON OEM LCD (IR & LCD) */ -+ { USB_DEVICE(0x15c2, 0x0038) }, -+ /* SoundGraph iMON UltraBay (IR & LCD) */ -+ { USB_DEVICE(0x15c2, 0x0039) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003a) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003b) }, -+ /* SoundGraph iMON OEM Inside (IR only) */ -+ { USB_DEVICE(0x15c2, 0x003c) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003d) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003e) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x003f) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x0040) }, -+ /* SoundGraph iMON MINI (IR only) */ -+ { USB_DEVICE(0x15c2, 0x0041) }, -+ /* Antec Veris Multimedia Station EZ External (IR only) */ -+ { USB_DEVICE(0x15c2, 0x0042) }, -+ /* Antec Veris Multimedia Station Basic Internal (IR only) */ -+ { USB_DEVICE(0x15c2, 0x0043) }, -+ /* Antec Veris Multimedia Station Elite (IR & VFD) */ -+ { USB_DEVICE(0x15c2, 0x0044) }, -+ /* Antec Veris Multimedia Station Premiere (IR & LCD) */ -+ { USB_DEVICE(0x15c2, 0x0045) }, -+ /* device specifics unknown */ -+ { USB_DEVICE(0x15c2, 0x0046) }, -+ {} -+}; -+ -+/* iMON LCD models use a different write op */ -+static struct usb_device_id lcd_device_list[] = { -+ { USB_DEVICE(0x15c2, 0xffdc) }, -+ { USB_DEVICE(0x15c2, 0x0038) }, -+ { USB_DEVICE(0x15c2, 0x0039) }, -+ { USB_DEVICE(0x15c2, 0x0045) }, -+ {} -+}; -+ -+/* Some iMON devices have no lcd/vfd, don't set one up */ -+static struct usb_device_id ir_only_list[] = { -+ /* the first imon lcd and the knob share this device id. :\ */ -+ /*{ USB_DEVICE(0x15c2, 0xffdc) },*/ -+ { USB_DEVICE(0x15c2, 0x003c) }, -+ { USB_DEVICE(0x15c2, 0x0041) }, -+ { USB_DEVICE(0x15c2, 0x0042) }, -+ { USB_DEVICE(0x15c2, 0x0043) }, -+ {} -+}; -+ -+/* iMON devices with VGA touchscreens */ -+static struct usb_device_id imon_touchscreen_list[] = { -+ { USB_DEVICE(0x15c2, 0x0034) }, -+ { USB_DEVICE(0x15c2, 0x0035) }, -+ {} -+}; -+ -+/* USB Device data */ -+static struct usb_driver imon_driver = { -+ .name = MOD_NAME, -+ .probe = imon_probe, -+ .disconnect = imon_disconnect, -+ .suspend = imon_suspend, -+ .resume = imon_resume, -+ .id_table = imon_usb_id_table, -+}; -+ -+static struct usb_class_driver imon_vfd_class = { -+ .name = DEVICE_NAME, -+ .fops = &vfd_fops, -+ .minor_base = DISPLAY_MINOR_BASE, -+}; -+ -+static struct usb_class_driver imon_lcd_class = { -+ .name = DEVICE_NAME, -+ .fops = &lcd_fops, -+ .minor_base = DISPLAY_MINOR_BASE, -+}; -+ -+/* -+ * standard imon remote key table, which isn't really entirely -+ * "standard", as different receivers decode the same key on the -+ * same remote to different hex codes... ugh. -+ */ -+static const struct key_entry imon_remote_key_table[] = { -+ /* keys sorted mostly by frequency of use to optimize lookups */ -+ { KE_KEY, 0x2a8195b7, { KEY_REWIND } }, -+ { KE_KEY, 0x298315b7, { KEY_REWIND } }, -+ { KE_KEY, 0x2b8115b7, { KEY_FASTFORWARD } }, -+ { KE_KEY, 0x2b8315b7, { KEY_FASTFORWARD } }, -+ { KE_KEY, 0x2b9115b7, { KEY_PREVIOUS } }, -+ { KE_KEY, 0x298195b7, { KEY_NEXT } }, -+ -+ { KE_KEY, 0x2a8115b7, { KEY_PLAY } }, -+ { KE_KEY, 0x2a8315b7, { KEY_PLAY } }, -+ { KE_KEY, 0x2a9115b7, { KEY_PAUSE } }, -+ { KE_KEY, 0x2b9715b7, { KEY_STOP } }, -+ { KE_KEY, 0x298115b7, { KEY_RECORD } }, -+ -+ { KE_KEY, 0x01008000, { KEY_UP } }, -+ { KE_KEY, 0x01007f00, { KEY_DOWN } }, -+ { KE_KEY, 0x01000080, { KEY_LEFT } }, -+ { KE_KEY, 0x0100007f, { KEY_RIGHT } }, -+ -+ { KE_KEY, 0x2aa515b7, { KEY_UP } }, -+ { KE_KEY, 0x289515b7, { KEY_DOWN } }, -+ { KE_KEY, 0x29a515b7, { KEY_LEFT } }, -+ { KE_KEY, 0x2ba515b7, { KEY_RIGHT } }, -+ -+ { KE_KEY, 0x0200002c, { KEY_SPACE } }, /* Select/Space */ -+ { KE_KEY, 0x2a9315b7, { KEY_SPACE } }, /* Select/Space */ -+ { KE_KEY, 0x02000028, { KEY_ENTER } }, -+ { KE_KEY, 0x28a195b7, { KEY_ENTER } }, -+ { KE_KEY, 0x288195b7, { KEY_EXIT } }, -+ { KE_KEY, 0x02000029, { KEY_ESC } }, -+ { KE_KEY, 0x2bb715b7, { KEY_ESC } }, -+ { KE_KEY, 0x0200002a, { KEY_BACKSPACE } }, -+ { KE_KEY, 0x28a115b7, { KEY_BACKSPACE } }, -+ -+ { KE_KEY, 0x2b9595b7, { KEY_MUTE } }, -+ { KE_KEY, 0x28a395b7, { KEY_VOLUMEUP } }, -+ { KE_KEY, 0x28a595b7, { KEY_VOLUMEDOWN } }, -+ { KE_KEY, 0x289395b7, { KEY_CHANNELUP } }, -+ { KE_KEY, 0x288795b7, { KEY_CHANNELDOWN } }, -+ -+ { KE_KEY, 0x0200001e, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x0200001f, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x02000020, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x02000021, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x02000022, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x02000023, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x02000024, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x02000025, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x02000026, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x02000027, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x28b595b7, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x2bb195b7, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x28b195b7, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x2a8595b7, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x299595b7, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x2aa595b7, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x2b9395b7, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x2a8515b7, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x2aa115b7, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x2ba595b7, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x02200025, { KEY_NUMERIC_STAR } }, -+ { KE_KEY, 0x28b515b7, { KEY_NUMERIC_STAR } }, -+ { KE_KEY, 0x02200020, { KEY_NUMERIC_POUND } }, -+ { KE_KEY, 0x29a115b7, { KEY_NUMERIC_POUND } }, -+ -+ { KE_KEY, 0x2b8515b7, { KEY_VIDEO } }, -+ { KE_KEY, 0x299195b7, { KEY_AUDIO } }, -+ { KE_KEY, 0x2ba115b7, { KEY_CAMERA } }, -+ { KE_KEY, 0x28a515b7, { KEY_TV } }, -+ { KE_KEY, 0x29a395b7, { KEY_DVD } }, -+ { KE_KEY, 0x29a295b7, { KEY_DVD } }, -+ -+ /* the Menu key between DVD and Subtitle on the RM-200... */ -+ { KE_KEY, 0x2ba385b7, { KEY_MENU } }, -+ { KE_KEY, 0x2ba395b7, { KEY_MENU } }, -+ -+ { KE_KEY, 0x288515b7, { KEY_BOOKMARKS } }, -+ { KE_KEY, 0x2ab715b7, { KEY_MEDIA } }, /* Thumbnail */ -+ { KE_KEY, 0x298595b7, { KEY_SUBTITLE } }, -+ { KE_KEY, 0x2b8595b7, { KEY_LANGUAGE } }, -+ -+ { KE_KEY, 0x29a595b7, { KEY_ZOOM } }, -+ { KE_KEY, 0x2aa395b7, { KEY_SCREEN } }, /* FullScreen */ -+ -+ { KE_KEY, 0x299115b7, { KEY_KEYBOARD } }, -+ { KE_KEY, 0x299135b7, { KEY_KEYBOARD } }, -+ -+ { KE_KEY, 0x01010000, { BTN_LEFT } }, -+ { KE_KEY, 0x01020000, { BTN_RIGHT } }, -+ { KE_KEY, 0x01010080, { BTN_LEFT } }, -+ { KE_KEY, 0x01020080, { BTN_RIGHT } }, -+ { KE_KEY, 0x688301b7, { BTN_LEFT } }, -+ { KE_KEY, 0x688481b7, { BTN_RIGHT } }, -+ -+ { KE_KEY, 0x2a9395b7, { KEY_CYCLEWINDOWS } }, /* TaskSwitcher */ -+ { KE_KEY, 0x2b8395b7, { KEY_TIME } }, /* Timer */ -+ -+ { KE_KEY, 0x289115b7, { KEY_POWER } }, -+ { KE_KEY, 0x29b195b7, { KEY_EJECTCD } }, /* the one next to play */ -+ { KE_KEY, 0x299395b7, { KEY_EJECTCLOSECD } }, /* eject (by TaskSw) */ -+ -+ { KE_KEY, 0x02800000, { KEY_CONTEXT_MENU } }, /* Left Menu */ -+ { KE_KEY, 0x2b8195b7, { KEY_CONTEXT_MENU } }, /* Left Menu*/ -+ { KE_KEY, 0x02000065, { KEY_COMPOSE } }, /* RightMenu */ -+ { KE_KEY, 0x28b715b7, { KEY_COMPOSE } }, /* RightMenu */ -+ { KE_KEY, 0x2ab195b7, { KEY_PROG1 } }, /* Go or MultiMon */ -+ { KE_KEY, 0x29b715b7, { KEY_DASHBOARD } }, /* AppLauncher */ -+ { KE_END, 0 } -+}; -+ -+/* mce-mode imon mce remote key table */ -+static const struct key_entry imon_mce_key_table[] = { -+ /* keys sorted mostly by frequency of use to optimize lookups */ -+ { KE_KEY, 0x800ff415, { KEY_REWIND } }, -+ { KE_KEY, 0x800ff414, { KEY_FASTFORWARD } }, -+ { KE_KEY, 0x800ff41b, { KEY_PREVIOUS } }, -+ { KE_KEY, 0x800ff41a, { KEY_NEXT } }, -+ -+ { KE_KEY, 0x800ff416, { KEY_PLAY } }, -+ { KE_KEY, 0x800ff418, { KEY_PAUSE } }, -+ { KE_KEY, 0x800ff419, { KEY_STOP } }, -+ { KE_KEY, 0x800ff417, { KEY_RECORD } }, -+ -+ { KE_KEY, 0x02000052, { KEY_UP } }, -+ { KE_KEY, 0x02000051, { KEY_DOWN } }, -+ { KE_KEY, 0x02000050, { KEY_LEFT } }, -+ { KE_KEY, 0x0200004f, { KEY_RIGHT } }, -+ -+ { KE_KEY, 0x800ff41e, { KEY_UP } }, -+ { KE_KEY, 0x800ff41f, { KEY_DOWN } }, -+ { KE_KEY, 0x800ff420, { KEY_LEFT } }, -+ { KE_KEY, 0x800ff421, { KEY_RIGHT } }, -+ -+ /* 0x800ff40b also KEY_NUMERIC_POUND on some receivers */ -+ { KE_KEY, 0x800ff40b, { KEY_ENTER } }, -+ { KE_KEY, 0x02000028, { KEY_ENTER } }, -+/* the OK and Enter buttons decode to the same value on some remotes -+ { KE_KEY, 0x02000028, { KEY_OK } }, */ -+ { KE_KEY, 0x800ff422, { KEY_OK } }, -+ { KE_KEY, 0x0200002a, { KEY_EXIT } }, -+ { KE_KEY, 0x800ff423, { KEY_EXIT } }, -+ { KE_KEY, 0x02000029, { KEY_DELETE } }, -+ /* 0x800ff40a also KEY_NUMERIC_STAR on some receivers */ -+ { KE_KEY, 0x800ff40a, { KEY_DELETE } }, -+ -+ { KE_KEY, 0x800ff40e, { KEY_MUTE } }, -+ { KE_KEY, 0x800ff410, { KEY_VOLUMEUP } }, -+ { KE_KEY, 0x800ff411, { KEY_VOLUMEDOWN } }, -+ { KE_KEY, 0x800ff412, { KEY_CHANNELUP } }, -+ { KE_KEY, 0x800ff413, { KEY_CHANNELDOWN } }, -+ -+ { KE_KEY, 0x0200001e, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x0200001f, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x02000020, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x02000021, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x02000022, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x02000023, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x02000024, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x02000025, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x02000026, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x02000027, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x800ff401, { KEY_NUMERIC_1 } }, -+ { KE_KEY, 0x800ff402, { KEY_NUMERIC_2 } }, -+ { KE_KEY, 0x800ff403, { KEY_NUMERIC_3 } }, -+ { KE_KEY, 0x800ff404, { KEY_NUMERIC_4 } }, -+ { KE_KEY, 0x800ff405, { KEY_NUMERIC_5 } }, -+ { KE_KEY, 0x800ff406, { KEY_NUMERIC_6 } }, -+ { KE_KEY, 0x800ff407, { KEY_NUMERIC_7 } }, -+ { KE_KEY, 0x800ff408, { KEY_NUMERIC_8 } }, -+ { KE_KEY, 0x800ff409, { KEY_NUMERIC_9 } }, -+ { KE_KEY, 0x800ff400, { KEY_NUMERIC_0 } }, -+ -+ { KE_KEY, 0x02200025, { KEY_NUMERIC_STAR } }, -+ { KE_KEY, 0x02200020, { KEY_NUMERIC_POUND } }, -+ /* 0x800ff41d also KEY_BLUE on some receivers */ -+ { KE_KEY, 0x800ff41d, { KEY_NUMERIC_STAR } }, -+ /* 0x800ff41c also KEY_PREVIOUS on some receivers */ -+ { KE_KEY, 0x800ff41c, { KEY_NUMERIC_POUND } }, -+ -+ { KE_KEY, 0x800ff446, { KEY_TV } }, -+ { KE_KEY, 0x800ff447, { KEY_AUDIO } }, /* My Music */ -+ { KE_KEY, 0x800ff448, { KEY_PVR } }, /* RecordedTV */ -+ { KE_KEY, 0x800ff449, { KEY_CAMERA } }, -+ { KE_KEY, 0x800ff44a, { KEY_VIDEO } }, -+ /* 0x800ff424 also KEY_MENU on some receivers */ -+ { KE_KEY, 0x800ff424, { KEY_DVD } }, -+ /* 0x800ff425 also KEY_GREEN on some receivers */ -+ { KE_KEY, 0x800ff425, { KEY_TUNER } }, /* LiveTV */ -+ { KE_KEY, 0x800ff450, { KEY_RADIO } }, -+ -+ { KE_KEY, 0x800ff44c, { KEY_LANGUAGE } }, -+ { KE_KEY, 0x800ff427, { KEY_ZOOM } }, /* Aspect */ -+ -+ { KE_KEY, 0x800ff45b, { KEY_RED } }, -+ { KE_KEY, 0x800ff45c, { KEY_GREEN } }, -+ { KE_KEY, 0x800ff45d, { KEY_YELLOW } }, -+ { KE_KEY, 0x800ff45e, { KEY_BLUE } }, -+ -+ { KE_KEY, 0x800ff466, { KEY_RED } }, -+ /* { KE_KEY, 0x800ff425, { KEY_GREEN } }, */ -+ { KE_KEY, 0x800ff468, { KEY_YELLOW } }, -+ /* { KE_KEY, 0x800ff41d, { KEY_BLUE } }, */ -+ -+ { KE_KEY, 0x800ff40f, { KEY_INFO } }, -+ { KE_KEY, 0x800ff426, { KEY_EPG } }, /* Guide */ -+ { KE_KEY, 0x800ff45a, { KEY_SUBTITLE } }, /* Caption/Teletext */ -+ { KE_KEY, 0x800ff44d, { KEY_TITLE } }, -+ -+ { KE_KEY, 0x800ff40c, { KEY_POWER } }, -+ { KE_KEY, 0x800ff40d, { KEY_PROG1 } }, /* Windows MCE button */ -+ { KE_END, 0 } -+ -+}; -+ -+/* imon receiver front panel/knob key table */ -+static const struct { -+ u64 hw_code; -+ u16 keycode; -+} imon_panel_key_table[] = { -+ { 0x000000000f00ffee, KEY_PROG1 }, /* Go */ -+ { 0x000000001f00ffee, KEY_AUDIO }, -+ { 0x000000002000ffee, KEY_VIDEO }, -+ { 0x000000002100ffee, KEY_CAMERA }, -+ { 0x000000002700ffee, KEY_DVD }, -+ { 0x000000002300ffee, KEY_TV }, -+ { 0x000000000500ffee, KEY_PREVIOUS }, -+ { 0x000000000700ffee, KEY_REWIND }, -+ { 0x000000000400ffee, KEY_STOP }, -+ { 0x000000003c00ffee, KEY_PLAYPAUSE }, -+ { 0x000000000800ffee, KEY_FASTFORWARD }, -+ { 0x000000000600ffee, KEY_NEXT }, -+ { 0x000000010000ffee, KEY_RIGHT }, -+ { 0x000001000000ffee, KEY_LEFT }, -+ { 0x000000003d00ffee, KEY_SELECT }, -+ { 0x000100000000ffee, KEY_VOLUMEUP }, -+ { 0x010000000000ffee, KEY_VOLUMEDOWN }, -+ { 0x000000000100ffee, KEY_MUTE }, -+ /* iMON Knob values */ -+ { 0x000100ffffffffee, KEY_VOLUMEUP }, -+ { 0x010000ffffffffee, KEY_VOLUMEDOWN }, -+ { 0x000008ffffffffee, KEY_MUTE }, -+}; -+ -+/* to prevent races between open() and disconnect(), probing, etc */ -+static DEFINE_MUTEX(driver_lock); -+ -+/* Module bookkeeping bits */ -+MODULE_AUTHOR(MOD_AUTHOR); -+MODULE_DESCRIPTION(MOD_DESC); -+MODULE_VERSION(MOD_VERSION); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(usb, imon_usb_id_table); -+ -+static bool debug; -+module_param(debug, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)"); -+ -+/* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */ -+static int display_type; -+module_param(display_type, int, S_IRUGO); -+MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, " -+ "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); -+ -+/* IR protocol: native iMON, Windows MCE (RC-6), or iMON w/o PAD stabilize */ -+static int ir_protocol; -+module_param(ir_protocol, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(ir_protocol, "Which IR protocol to use. 0=native iMON, " -+ "1=Windows Media Center Ed. (RC-6), 2=iMON w/o PAD stabilize " -+ "(default: native iMON)"); -+ -+/* -+ * In certain use cases, mouse mode isn't really helpful, and could actually -+ * cause confusion, so allow disabling it when the IR device is open. -+ */ -+static bool nomouse; -+module_param(nomouse, bool, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is " -+ "open. 0=don't disable, 1=disable. (default: don't disable)"); -+ -+/* threshold at which a pad push registers as an arrow key in kbd mode */ -+static int pad_thresh; -+module_param(pad_thresh, int, S_IRUGO | S_IWUSR); -+MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an " -+ "arrow key in kbd mode (default: 28)"); -+ -+ -+static void free_imon_context(struct imon_context *ictx) -+{ -+ struct device *dev = ictx->dev; -+ -+ usb_free_urb(ictx->tx_urb); -+ usb_free_urb(ictx->rx_urb_intf0); -+ usb_free_urb(ictx->rx_urb_intf1); -+ kfree(ictx); -+ -+ dev_dbg(dev, "%s: iMON context freed\n", __func__); -+} -+ -+/** -+ * Called when the Display device (e.g. /dev/lcd0) -+ * is opened by the application. -+ */ -+static int display_open(struct inode *inode, struct file *file) -+{ -+ struct usb_interface *interface; -+ struct imon_context *ictx = NULL; -+ int subminor; -+ int retval = 0; -+ -+ /* prevent races with disconnect */ -+ mutex_lock(&driver_lock); -+ -+ subminor = iminor(inode); -+ interface = usb_find_interface(&imon_driver, subminor); -+ if (!interface) { -+ err("%s: could not find interface for minor %d", -+ __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ ictx = usb_get_intfdata(interface); -+ -+ if (!ictx) { -+ err("%s: no context found for minor %d", __func__, subminor); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (ictx->display_isopen) { -+ err("%s: display port is already open", __func__); -+ retval = -EBUSY; -+ } else { -+ ictx->display_isopen = 1; -+ file->private_data = ictx; -+ dev_dbg(ictx->dev, "display port opened\n"); -+ } -+ -+ mutex_unlock(&ictx->lock); -+ -+exit: -+ mutex_unlock(&driver_lock); -+ return retval; -+} -+ -+/** -+ * Called when the display device (e.g. /dev/lcd0) -+ * is closed by the application. -+ */ -+static int display_close(struct inode *inode, struct file *file) -+{ -+ struct imon_context *ictx = NULL; -+ int retval = 0; -+ -+ ictx = (struct imon_context *)file->private_data; -+ -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ err("%s: display not supported by device", __func__); -+ retval = -ENODEV; -+ } else if (!ictx->display_isopen) { -+ err("%s: display is not open", __func__); -+ retval = -EIO; -+ } else { -+ ictx->display_isopen = 0; -+ dev_dbg(ictx->dev, "display port closed\n"); -+ if (!ictx->dev_present_intf0) { -+ /* -+ * Device disconnected before close and IR port is not -+ * open. If IR port is open, context will be deleted by -+ * ir_close. -+ */ -+ mutex_unlock(&ictx->lock); -+ free_imon_context(ictx); -+ return retval; -+ } -+ } -+ -+ mutex_unlock(&ictx->lock); -+ return retval; -+} -+ -+/** -+ * Sends a packet to the device -- this function must be called -+ * with ictx->lock held. -+ */ -+static int send_packet(struct imon_context *ictx) -+{ -+ unsigned int pipe; -+ int interval = 0; -+ int retval = 0; -+ struct usb_ctrlrequest *control_req = NULL; -+ -+ /* Check if we need to use control or interrupt urb */ -+ if (!ictx->tx_control) { -+ pipe = usb_sndintpipe(ictx->usbdev_intf0, -+ ictx->tx_endpoint->bEndpointAddress); -+ interval = ictx->tx_endpoint->bInterval; -+ -+ usb_fill_int_urb(ictx->tx_urb, ictx->usbdev_intf0, pipe, -+ ictx->usb_tx_buf, -+ sizeof(ictx->usb_tx_buf), -+ usb_tx_callback, ictx, interval); -+ -+ ictx->tx_urb->actual_length = 0; -+ } else { -+ /* fill request into kmalloc'ed space: */ -+ control_req = kmalloc(sizeof(struct usb_ctrlrequest), -+ GFP_KERNEL); -+ if (control_req == NULL) -+ return -ENOMEM; -+ -+ /* setup packet is '21 09 0200 0001 0008' */ -+ control_req->bRequestType = 0x21; -+ control_req->bRequest = 0x09; -+ control_req->wValue = cpu_to_le16(0x0200); -+ control_req->wIndex = cpu_to_le16(0x0001); -+ control_req->wLength = cpu_to_le16(0x0008); -+ -+ /* control pipe is endpoint 0x00 */ -+ pipe = usb_sndctrlpipe(ictx->usbdev_intf0, 0); -+ -+ /* build the control urb */ -+ usb_fill_control_urb(ictx->tx_urb, ictx->usbdev_intf0, -+ pipe, (unsigned char *)control_req, -+ ictx->usb_tx_buf, -+ sizeof(ictx->usb_tx_buf), -+ usb_tx_callback, ictx); -+ ictx->tx_urb->actual_length = 0; -+ } -+ -+ init_completion(&ictx->tx.finished); -+ ictx->tx.busy = 1; -+ smp_rmb(); /* ensure later readers know we're busy */ -+ -+ retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL); -+ if (retval) { -+ ictx->tx.busy = 0; -+ smp_rmb(); /* ensure later readers know we're not busy */ -+ err("%s: error submitting urb(%d)", __func__, retval); -+ } else { -+ /* Wait for transmission to complete (or abort) */ -+ mutex_unlock(&ictx->lock); -+ retval = wait_for_completion_interruptible( -+ &ictx->tx.finished); -+ if (retval) -+ err("%s: task interrupted", __func__); -+ mutex_lock(&ictx->lock); -+ -+ retval = ictx->tx.status; -+ if (retval) -+ err("%s: packet tx failed (%d)", __func__, retval); -+ } -+ -+ kfree(control_req); -+ -+ return retval; -+} -+ -+/** -+ * Sends an associate packet to the iMON 2.4G. -+ * -+ * This might not be such a good idea, since it has an id collision with -+ * some versions of the "IR & VFD" combo. The only way to determine if it -+ * is an RF version is to look at the product description string. (Which -+ * we currently do not fetch). -+ */ -+static int send_associate_24g(struct imon_context *ictx) -+{ -+ int retval; -+ const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x20 }; -+ -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ if (!ictx->dev_present_intf0) { -+ err("%s: no iMON device present", __func__); -+ return -ENODEV; -+ } -+ -+ memcpy(ictx->usb_tx_buf, packet, sizeof(packet)); -+ retval = send_packet(ictx); -+ -+ return retval; -+} -+ -+/** -+ * Sends packets to setup and show clock on iMON display -+ * -+ * Arguments: year - last 2 digits of year, month - 1..12, -+ * day - 1..31, dow - day of the week (0-Sun...6-Sat), -+ * hour - 0..23, minute - 0..59, second - 0..59 -+ */ -+static int send_set_imon_clock(struct imon_context *ictx, -+ unsigned int year, unsigned int month, -+ unsigned int day, unsigned int dow, -+ unsigned int hour, unsigned int minute, -+ unsigned int second) -+{ -+ unsigned char clock_enable_pkt[IMON_CLOCK_ENABLE_PACKETS][8]; -+ int retval = 0; -+ int i; -+ -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ switch (ictx->display_type) { -+ case IMON_DISPLAY_TYPE_LCD: -+ clock_enable_pkt[0][0] = 0x80; -+ clock_enable_pkt[0][1] = year; -+ clock_enable_pkt[0][2] = month-1; -+ clock_enable_pkt[0][3] = day; -+ clock_enable_pkt[0][4] = hour; -+ clock_enable_pkt[0][5] = minute; -+ clock_enable_pkt[0][6] = second; -+ -+ clock_enable_pkt[1][0] = 0x80; -+ clock_enable_pkt[1][1] = 0; -+ clock_enable_pkt[1][2] = 0; -+ clock_enable_pkt[1][3] = 0; -+ clock_enable_pkt[1][4] = 0; -+ clock_enable_pkt[1][5] = 0; -+ clock_enable_pkt[1][6] = 0; -+ -+ if (ictx->product == 0xffdc) { -+ clock_enable_pkt[0][7] = 0x50; -+ clock_enable_pkt[1][7] = 0x51; -+ } else { -+ clock_enable_pkt[0][7] = 0x88; -+ clock_enable_pkt[1][7] = 0x8a; -+ } -+ -+ break; -+ -+ case IMON_DISPLAY_TYPE_VFD: -+ clock_enable_pkt[0][0] = year; -+ clock_enable_pkt[0][1] = month-1; -+ clock_enable_pkt[0][2] = day; -+ clock_enable_pkt[0][3] = dow; -+ clock_enable_pkt[0][4] = hour; -+ clock_enable_pkt[0][5] = minute; -+ clock_enable_pkt[0][6] = second; -+ clock_enable_pkt[0][7] = 0x40; -+ -+ clock_enable_pkt[1][0] = 0; -+ clock_enable_pkt[1][1] = 0; -+ clock_enable_pkt[1][2] = 1; -+ clock_enable_pkt[1][3] = 0; -+ clock_enable_pkt[1][4] = 0; -+ clock_enable_pkt[1][5] = 0; -+ clock_enable_pkt[1][6] = 0; -+ clock_enable_pkt[1][7] = 0x42; -+ -+ break; -+ -+ default: -+ return -ENODEV; -+ } -+ -+ for (i = 0; i < IMON_CLOCK_ENABLE_PACKETS; i++) { -+ memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8); -+ retval = send_packet(ictx); -+ if (retval) { -+ err("%s: send_packet failed for packet %d", -+ __func__, i); -+ break; -+ } -+ } -+ -+ return retval; -+} -+ -+/** -+ * These are the sysfs functions to handle the association on the iMON 2.4G LT. -+ */ -+static ssize_t show_associate_remote(struct device *d, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct imon_context *ictx = dev_get_drvdata(d); -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ if (ictx->ir_isassociating) -+ strcpy(buf, "associating\n"); -+ else -+ strcpy(buf, "closed\n"); -+ -+ dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for " -+ "instructions on how to associate your iMON 2.4G DT/LT " -+ "remote\n"); -+ mutex_unlock(&ictx->lock); -+ return strlen(buf); -+} -+ -+static ssize_t store_associate_remote(struct device *d, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct imon_context *ictx; -+ -+ ictx = dev_get_drvdata(d); -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ ictx->ir_isassociating = 1; -+ send_associate_24g(ictx); -+ mutex_unlock(&ictx->lock); -+ -+ return count; -+} -+ -+/** -+ * sysfs functions to control internal imon clock -+ */ -+static ssize_t show_imon_clock(struct device *d, -+ struct device_attribute *attr, char *buf) -+{ -+ struct imon_context *ictx = dev_get_drvdata(d); -+ size_t len; -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ len = snprintf(buf, PAGE_SIZE, "Not supported."); -+ } else { -+ len = snprintf(buf, PAGE_SIZE, -+ "To set the clock on your iMON display:\n" -+ "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n" -+ "%s", ictx->display_isopen ? -+ "\nNOTE: imon device must be closed\n" : ""); -+ } -+ -+ mutex_unlock(&ictx->lock); -+ -+ return len; -+} -+ -+static ssize_t store_imon_clock(struct device *d, -+ struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct imon_context *ictx = dev_get_drvdata(d); -+ ssize_t retval; -+ unsigned int year, month, day, dow, hour, minute, second; -+ -+ if (!ictx) -+ return -ENODEV; -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ retval = -ENODEV; -+ goto exit; -+ } else if (ictx->display_isopen) { -+ retval = -EBUSY; -+ goto exit; -+ } -+ -+ if (sscanf(buf, "%u %u %u %u %u %u %u", &year, &month, &day, &dow, -+ &hour, &minute, &second) != 7) { -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if ((month < 1 || month > 12) || -+ (day < 1 || day > 31) || (dow > 6) || -+ (hour > 23) || (minute > 59) || (second > 59)) { -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ retval = send_set_imon_clock(ictx, year, month, day, dow, -+ hour, minute, second); -+ if (retval) -+ goto exit; -+ -+ retval = count; -+exit: -+ mutex_unlock(&ictx->lock); -+ -+ return retval; -+} -+ -+ -+static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock, -+ store_imon_clock); -+ -+static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote, -+ store_associate_remote); -+ -+static struct attribute *imon_display_sysfs_entries[] = { -+ &dev_attr_imon_clock.attr, -+ NULL -+}; -+ -+static struct attribute_group imon_display_attribute_group = { -+ .attrs = imon_display_sysfs_entries -+}; -+ -+static struct attribute *imon_rf_sysfs_entries[] = { -+ &dev_attr_associate_remote.attr, -+ NULL -+}; -+ -+static struct attribute_group imon_rf_attribute_group = { -+ .attrs = imon_rf_sysfs_entries -+}; -+ -+/** -+ * Writes data to the VFD. The iMON VFD is 2x16 characters -+ * and requires data in 5 consecutive USB interrupt packets, -+ * each packet but the last carrying 7 bytes. -+ * -+ * I don't know if the VFD board supports features such as -+ * scrolling, clearing rows, blanking, etc. so at -+ * the caller must provide a full screen of data. If fewer -+ * than 32 bytes are provided spaces will be appended to -+ * generate a full screen. -+ */ -+static ssize_t vfd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int i; -+ int offset; -+ int seq; -+ int retval = 0; -+ struct imon_context *ictx; -+ const unsigned char vfd_packet6[] = { -+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; -+ -+ ictx = (struct imon_context *)file->private_data; -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->dev_present_intf0) { -+ err("%s: no iMON device present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes <= 0 || n_bytes > 32) { -+ err("%s: invalid payload size", __func__); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if (copy_from_user(ictx->tx.data_buf, buf, n_bytes)) { -+ retval = -EFAULT; -+ goto exit; -+ } -+ -+ /* Pad with spaces */ -+ for (i = n_bytes; i < 32; ++i) -+ ictx->tx.data_buf[i] = ' '; -+ -+ for (i = 32; i < 35; ++i) -+ ictx->tx.data_buf[i] = 0xFF; -+ -+ offset = 0; -+ seq = 0; -+ -+ do { -+ memcpy(ictx->usb_tx_buf, ictx->tx.data_buf + offset, 7); -+ ictx->usb_tx_buf[7] = (unsigned char) seq; -+ -+ retval = send_packet(ictx); -+ if (retval) { -+ err("%s: send packet failed for packet #%d", -+ __func__, seq/2); -+ goto exit; -+ } else { -+ seq += 2; -+ offset += 7; -+ } -+ -+ } while (offset < 35); -+ -+ /* Send packet #6 */ -+ memcpy(ictx->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6)); -+ ictx->usb_tx_buf[7] = (unsigned char) seq; -+ retval = send_packet(ictx); -+ if (retval) -+ err("%s: send packet failed for packet #%d", -+ __func__, seq / 2); -+ -+exit: -+ mutex_unlock(&ictx->lock); -+ -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Writes data to the LCD. The iMON OEM LCD screen expects 8-byte -+ * packets. We accept data as 16 hexadecimal digits, followed by a -+ * newline (to make it easy to drive the device from a command-line -+ * -- even though the actual binary data is a bit complicated). -+ * -+ * The device itself is not a "traditional" text-mode display. It's -+ * actually a 16x96 pixel bitmap display. That means if you want to -+ * display text, you've got to have your own "font" and translate the -+ * text into bitmaps for display. This is really flexible (you can -+ * display whatever diacritics you need, and so on), but it's also -+ * a lot more complicated than most LCDs... -+ */ -+static ssize_t lcd_write(struct file *file, const char *buf, -+ size_t n_bytes, loff_t *pos) -+{ -+ int retval = 0; -+ struct imon_context *ictx; -+ -+ ictx = (struct imon_context *)file->private_data; -+ if (!ictx) { -+ err("%s: no context for device", __func__); -+ return -ENODEV; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (!ictx->display_supported) { -+ err("%s: no iMON display present", __func__); -+ retval = -ENODEV; -+ goto exit; -+ } -+ -+ if (n_bytes != 8) { -+ err("%s: invalid payload size: %d (expecting 8)", -+ __func__, (int) n_bytes); -+ retval = -EINVAL; -+ goto exit; -+ } -+ -+ if (copy_from_user(ictx->usb_tx_buf, buf, 8)) { -+ retval = -EFAULT; -+ goto exit; -+ } -+ -+ retval = send_packet(ictx); -+ if (retval) { -+ err("%s: send packet failed!", __func__); -+ goto exit; -+ } else { -+ dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", -+ __func__, (int) n_bytes); -+ } -+exit: -+ mutex_unlock(&ictx->lock); -+ return (!retval) ? n_bytes : retval; -+} -+ -+/** -+ * Callback function for USB core API: transmit data -+ */ -+static void usb_tx_callback(struct urb *urb) -+{ -+ struct imon_context *ictx; -+ -+ if (!urb) -+ return; -+ ictx = (struct imon_context *)urb->context; -+ if (!ictx) -+ return; -+ -+ ictx->tx.status = urb->status; -+ -+ /* notify waiters that write has finished */ -+ ictx->tx.busy = 0; -+ smp_rmb(); /* ensure later readers know we're not busy */ -+ complete(&ictx->tx.finished); -+} -+ -+/** -+ * iMON IR receivers support two different signal sets -- those used by -+ * the iMON remotes, and those used by the Windows MCE remotes (which is -+ * really just RC-6), but only one or the other at a time, as the signals -+ * are decoded onboard the receiver. -+ */ -+static void imon_set_ir_protocol(struct imon_context *ictx) -+{ -+ int retval; -+ struct device *dev = ictx->dev; -+ unsigned char ir_proto_packet[] = { -+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; -+ -+ switch (ir_protocol) { -+ case IMON_IR_PROTOCOL_MCE: -+ dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); -+ ir_proto_packet[0] = 0x01; -+ ictx->ir_protocol = IMON_IR_PROTOCOL_MCE; -+ ictx->pad_mouse = 0; -+ break; -+ case IMON_IR_PROTOCOL_IMON: -+ dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); -+ /* ir_proto_packet[0] = 0x00; // already the default */ -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; -+ ictx->pad_mouse = 1; -+ break; -+ case IMON_IR_PROTOCOL_IMON_NOPAD: -+ dev_dbg(dev, "Configuring IR receiver for iMON protocol " -+ "without PAD stabilize function enabled\n"); -+ /* ir_proto_packet[0] = 0x00; // already the default */ -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON_NOPAD; -+ ictx->pad_mouse = 0; -+ break; -+ default: -+ dev_info(dev, "%s: unknown IR protocol specified, will " -+ "just default to iMON protocol\n", __func__); -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; -+ ictx->pad_mouse = 1; -+ break; -+ } -+ -+ memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); -+ -+ retval = send_packet(ictx); -+ if (retval) { -+ dev_info(dev, "%s: failed to set IR protocol, falling back " -+ "to standard iMON protocol mode\n", __func__); -+ ir_protocol = IMON_IR_PROTOCOL_IMON; -+ ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; -+ } -+} -+ -+static inline int tv2int(const struct timeval *a, const struct timeval *b) -+{ -+ int usecs = 0; -+ int sec = 0; -+ -+ if (b->tv_usec > a->tv_usec) { -+ usecs = 1000000; -+ sec--; -+ } -+ -+ usecs += a->tv_usec - b->tv_usec; -+ -+ sec += a->tv_sec - b->tv_sec; -+ sec *= 1000; -+ usecs /= 1000; -+ sec += usecs; -+ -+ if (sec < 0) -+ sec = 1000; -+ -+ return sec; -+} -+ -+/** -+ * The directional pad behaves a bit differently, depending on whether this is -+ * one of the older ffdc devices or a newer device. Newer devices appear to -+ * have a higher resolution matrix for more precise mouse movement, but it -+ * makes things overly sensitive in keyboard mode, so we do some interesting -+ * contortions to make it less touchy. Older devices run through the same -+ * routine with shorter timeout and a smaller threshold. -+ */ -+static int stabilize(int a, int b, u16 timeout, u16 threshold) -+{ -+ struct timeval ct; -+ static struct timeval prev_time = {0, 0}; -+ static struct timeval hit_time = {0, 0}; -+ static int x, y, prev_result, hits; -+ int result = 0; -+ int msec, msec_hit; -+ -+ do_gettimeofday(&ct); -+ msec = tv2int(&ct, &prev_time); -+ msec_hit = tv2int(&ct, &hit_time); -+ -+ if (msec > 100) { -+ x = 0; -+ y = 0; -+ hits = 0; -+ } -+ -+ x += a; -+ y += b; -+ -+ prev_time = ct; -+ -+ if (abs(x) > threshold || abs(y) > threshold) { -+ if (abs(y) > abs(x)) -+ result = (y > 0) ? 0x7F : 0x80; -+ else -+ result = (x > 0) ? 0x7F00 : 0x8000; -+ -+ x = 0; -+ y = 0; -+ -+ if (result == prev_result) { -+ hits++; -+ -+ if (hits > 3) { -+ switch (result) { -+ case 0x7F: -+ y = 17 * threshold / 30; -+ break; -+ case 0x80: -+ y -= 17 * threshold / 30; -+ break; -+ case 0x7F00: -+ x = 17 * threshold / 30; -+ break; -+ case 0x8000: -+ x -= 17 * threshold / 30; -+ break; -+ } -+ } -+ -+ if (hits == 2 && msec_hit < timeout) { -+ result = 0; -+ hits = 1; -+ } -+ } else { -+ prev_result = result; -+ hits = 1; -+ hit_time = ct; -+ } -+ } -+ -+ return result; -+} -+ -+static int imon_remote_key_lookup(u32 hw_code) -+{ -+ int i; -+ u32 code = be32_to_cpu(hw_code); -+ -+ /* Look for the initial press of a button */ -+ for (i = 0; i < ARRAY_SIZE(imon_remote_key_table); i++) -+ if (imon_remote_key_table[i].code == code) -+ return i; -+ -+ /* Look for the release of a button, return index + offset */ -+ for (i = 0; i < ARRAY_SIZE(imon_remote_key_table); i++) -+ if ((imon_remote_key_table[i].code | 0x4000) == code) -+ return i + IMON_KEY_RELEASE_OFFSET; -+ -+ return -1; -+} -+ -+static int imon_mce_key_lookup(u32 hw_code) -+{ -+ int i; -+ u32 code = be32_to_cpu(hw_code); -+ -+#define MCE_KEY_MASK 0x7000 -+#define MCE_TOGGLE_BIT 0x8000 -+ -+ /* -+ * On some receivers, mce keys decode to 0x8000f04xx and 0x8000f84xx -+ * (the toggle bit flipping between alternating key presses), while -+ * on other receivers, we see 0x8000f74xx and 0x8000ff4xx. To keep -+ * the table trim, we always or in the bits to look up 0x8000ff4xx, -+ * but we can't or them into all codes, as some keys are decoded in -+ * a different way w/o the same use of the toggle bit... -+ */ -+ if ((code >> 24) & 0x80) -+ code = code | MCE_KEY_MASK | MCE_TOGGLE_BIT; -+ -+ for (i = 0; i < ARRAY_SIZE(imon_mce_key_table); i++) -+ if (imon_mce_key_table[i].code == code) -+ return i; -+ -+ return -1; -+} -+ -+static int imon_panel_key_lookup(u64 hw_code) -+{ -+ int i; -+ u64 code = be64_to_cpu(hw_code); -+ -+ for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) -+ if (imon_panel_key_table[i].hw_code == (code | 0xffee)) -+ return i; -+ -+ return -1; -+} -+ -+static bool imon_mouse_event(struct imon_context *ictx, -+ unsigned char *buf, int len) -+{ -+ char rel_x = 0x00, rel_y = 0x00; -+ u8 right_shift = 1; -+ bool mouse_input = 1; -+ int dir = 0; -+ -+ /* newer iMON device PAD or mouse button */ -+ if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) { -+ rel_x = buf[2]; -+ rel_y = buf[3]; -+ right_shift = 1; -+ /* 0xffdc iMON PAD or mouse button input */ -+ } else if (ictx->product == 0xffdc && (buf[0] & 0x40) && -+ !((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01))) { -+ rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | -+ (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; -+ if (buf[0] & 0x02) -+ rel_x |= ~0x0f; -+ rel_x = rel_x + rel_x / 2; -+ rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | -+ (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; -+ if (buf[0] & 0x01) -+ rel_y |= ~0x0f; -+ rel_y = rel_y + rel_y / 2; -+ right_shift = 2; -+ /* some ffdc devices decode mouse buttons differently... */ -+ } else if (ictx->product == 0xffdc && (buf[0] == 0x68)) { -+ right_shift = 2; -+ /* ch+/- buttons, which we use for an emulated scroll wheel */ -+ } else if (ictx->kc == KEY_CHANNELUP && (buf[2] & 0x40) != 0x40) { -+ dir = 1; -+ } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) { -+ dir = -1; -+ } else -+ mouse_input = 0; -+ -+ if (mouse_input) { -+ dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); -+ -+ if (dir) { -+ input_report_rel(ictx->idev, REL_WHEEL, dir); -+ } else if (rel_x || rel_y) { -+ input_report_rel(ictx->idev, REL_X, rel_x); -+ input_report_rel(ictx->idev, REL_Y, rel_y); -+ } else { -+ input_report_key(ictx->idev, BTN_LEFT, buf[1] & 0x1); -+ input_report_key(ictx->idev, BTN_RIGHT, -+ buf[1] >> right_shift & 0x1); -+ } -+ input_sync(ictx->idev); -+ ictx->last_keycode = ictx->kc; -+ } -+ -+ return mouse_input; -+} -+ -+static void imon_touch_event(struct imon_context *ictx, unsigned char *buf) -+{ -+ mod_timer(&ictx->ttimer, jiffies + TOUCH_TIMEOUT); -+ ictx->touch_x = (buf[0] << 4) | (buf[1] >> 4); -+ ictx->touch_y = 0xfff - ((buf[2] << 4) | (buf[1] & 0xf)); -+ input_report_abs(ictx->touch, ABS_X, ictx->touch_x); -+ input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); -+ input_report_key(ictx->touch, BTN_TOUCH, 0x01); -+ input_sync(ictx->touch); -+} -+ -+static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) -+{ -+ int ki = 1; -+ int dir = 0; -+ int offset = IMON_KEY_RELEASE_OFFSET; -+ char rel_x = 0x00, rel_y = 0x00; -+ u16 timeout, threshold; -+ u64 temp_key; -+ u32 remote_key; -+ -+ /* -+ * The imon directional pad functions more like a touchpad. Bytes 3 & 4 -+ * contain a position coordinate (x,y), with each component ranging -+ * from -14 to 14. We want to down-sample this to only 4 discrete values -+ * for up/down/left/right arrow keys. Also, when you get too close to -+ * diagonals, it has a tendancy to jump back and forth, so lets try to -+ * ignore when they get too close. -+ */ -+ if (ictx->product != 0xffdc) { -+ /* first, pad to 8 bytes so it conforms with everything else */ -+ buf[5] = buf[6] = buf[7] = 0; -+ timeout = 500; /* in msecs */ -+ /* (2*threshold) x (2*threshold) square */ -+ threshold = pad_thresh ? pad_thresh : 28; -+ rel_x = buf[2]; -+ rel_y = buf[3]; -+ -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_IMON) { -+ if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { -+ dir = stabilize((int)rel_x, (int)rel_y, -+ timeout, threshold); -+ if (!dir) { -+ ictx->kc = KEY_UNKNOWN; -+ return; -+ } -+ buf[2] = dir & 0xFF; -+ buf[3] = (dir >> 8) & 0xFF; -+ memcpy(&temp_key, buf, sizeof(temp_key)); -+ remote_key = (u32) (le64_to_cpu(temp_key) -+ & 0xffffffff); -+ ki = imon_remote_key_lookup(remote_key); -+ ictx->kc = -+ imon_remote_key_table[ki % offset].keycode; -+ } -+ } else { -+ if (abs(rel_y) > abs(rel_x)) { -+ buf[2] = (rel_y > 0) ? 0x7F : 0x80; -+ buf[3] = 0; -+ ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP; -+ } else { -+ buf[2] = 0; -+ buf[3] = (rel_x > 0) ? 0x7F : 0x80; -+ ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT; -+ } -+ } -+ -+ /* -+ * Handle on-board decoded pad events for e.g. older VFD/iMON-Pad -+ * device (15c2:ffdc). The remote generates various codes from -+ * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates -+ * 0x688301b7 and the right one 0x688481b7. All other keys generate -+ * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with -+ * reversed endianess. Extract direction from buffer, rotate endianess, -+ * adjust sign and feed the values into stabilize(). The resulting codes -+ * will be 0x01008000, 0x01007F00, which match the newer devices. -+ */ -+ } else { -+ timeout = 10; /* in msecs */ -+ /* (2*threshold) x (2*threshold) square */ -+ threshold = pad_thresh ? pad_thresh : 15; -+ -+ /* buf[1] is x */ -+ rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | -+ (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6; -+ if (buf[0] & 0x02) -+ rel_x |= ~0x10+1; -+ /* buf[2] is y */ -+ rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | -+ (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6; -+ if (buf[0] & 0x01) -+ rel_y |= ~0x10+1; -+ -+ buf[0] = 0x01; -+ buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; -+ -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_IMON) { -+ dir = stabilize((int)rel_x, (int)rel_y, -+ timeout, threshold); -+ if (!dir) { -+ ictx->kc = KEY_UNKNOWN; -+ return; -+ } -+ buf[2] = dir & 0xFF; -+ buf[3] = (dir >> 8) & 0xFF; -+ memcpy(&temp_key, buf, sizeof(temp_key)); -+ remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff); -+ ki = imon_remote_key_lookup(remote_key); -+ ictx->kc = imon_remote_key_table[ki % offset].keycode; -+ } else { -+ if (abs(rel_y) > abs(rel_x)) { -+ buf[2] = (rel_y > 0) ? 0x7F : 0x80; -+ buf[3] = 0; -+ ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP; -+ } else { -+ buf[2] = 0; -+ buf[3] = (rel_x > 0) ? 0x7F : 0x80; -+ ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT; -+ } -+ } -+ } -+ -+ ictx->ki = ki; -+} -+ -+static int imon_parse_press_type(struct imon_context *ictx, -+ unsigned char *buf, u8 ksrc) -+{ -+ int press_type = 0; -+ -+ /* key release of 0x02XXXXXX key */ -+ if (ictx->ki == -1 && buf[0] == 0x02 && buf[3] == 0x00) -+ ictx->kc = ictx->last_keycode; -+ -+ /* mouse button release on (some) 0xffdc devices */ -+ else if (ictx->ki == -1 && buf[0] == 0x68 && buf[1] == 0x82 && -+ buf[2] == 0x81 && buf[3] == 0xb7) -+ ictx->kc = ictx->last_keycode; -+ -+ /* mouse button release on (some other) 0xffdc devices */ -+ else if (ictx->ki == -1 && buf[0] == 0x01 && buf[1] == 0x00 && -+ buf[2] == 0x81 && buf[3] == 0xb7) -+ ictx->kc = ictx->last_keycode; -+ -+ /* mce-specific button handling */ -+ else if (ksrc == IMON_BUTTON_MCE) { -+ /* initial press */ -+ if (ictx->kc != ictx->last_keycode -+ || buf[2] != ictx->mce_toggle_bit) { -+ ictx->last_keycode = ictx->kc; -+ ictx->mce_toggle_bit = buf[2]; -+ press_type = 1; -+ mod_timer(&ictx->itimer, -+ jiffies + msecs_to_jiffies(MCE_TIMEOUT_MS)); -+ /* repeat */ -+ } else { -+ press_type = 2; -+ mod_timer(&ictx->itimer, -+ jiffies + msecs_to_jiffies(MCE_TIMEOUT_MS)); -+ } -+ -+ /* incoherent or irrelevant data */ -+ } else if (ictx->ki == -1) -+ press_type = -EINVAL; -+ -+ /* key release of 0xXXXXXXb7 key */ -+ else if (ictx->ki >= IMON_KEY_RELEASE_OFFSET) -+ press_type = 0; -+ -+ /* this is a button press */ -+ else -+ press_type = 1; -+ -+ return press_type; -+} -+ -+/** -+ * Process the incoming packet -+ */ -+static void imon_incoming_packet(struct imon_context *ictx, -+ struct urb *urb, int intf) -+{ -+ int len = urb->actual_length; -+ unsigned char *buf = urb->transfer_buffer; -+ struct device *dev = ictx->dev; -+ u16 kc; -+ bool norelease = 0; -+ int i, ki; -+ int offset = IMON_KEY_RELEASE_OFFSET; -+ u64 temp_key; -+ u64 panel_key = 0; -+ u32 remote_key = 0; -+ struct input_dev *idev = NULL; -+ int press_type = 0; -+ int msec; -+ struct timeval t; -+ static struct timeval prev_time = { 0, 0 }; -+ u8 ksrc = IMON_BUTTON_IMON; -+ -+ idev = ictx->idev; -+ -+ /* filter out junk data on the older 0xffdc imon devices */ -+ if ((buf[0] == 0xff) && (buf[7] == 0xff)) -+ return; -+ -+ /* Figure out what key was pressed */ -+ memcpy(&temp_key, buf, sizeof(temp_key)); -+ if (len == 8 && buf[7] == 0xee) { -+ ksrc = IMON_BUTTON_PANEL; -+ panel_key = le64_to_cpu(temp_key); -+ ki = imon_panel_key_lookup(panel_key); -+ if (ki < 0) -+ kc = KEY_UNKNOWN; -+ else -+ kc = imon_panel_key_table[ki].keycode; -+ } else { -+ remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff); -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_MCE) { -+ if (buf[0] == 0x80) -+ ksrc = IMON_BUTTON_MCE; -+ ki = imon_mce_key_lookup(remote_key); -+ if (ki < 0) -+ kc = KEY_UNKNOWN; -+ else -+ kc = imon_mce_key_table[ki].keycode; -+ } else { -+ ki = imon_remote_key_lookup(remote_key); -+ if (ki < 0) -+ kc = KEY_UNKNOWN; -+ else -+ kc = imon_remote_key_table[ki % offset].keycode; -+ } -+ } -+ -+ /* keyboard/mouse mode toggle button */ -+ if (kc == KEY_KEYBOARD && ki < offset) { -+ ictx->last_keycode = kc; -+ if (!nomouse) { -+ ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1; -+ dev_dbg(dev, "toggling to %s mode\n", -+ ictx->pad_mouse ? "mouse" : "keyboard"); -+ return; -+ } else { -+ ictx->pad_mouse = 0; -+ dev_dbg(dev, "mouse mode disabled, passing key value\n"); -+ } -+ } -+ -+ ictx->ki = ki; -+ ictx->kc = kc; -+ -+ /* send touchscreen events through input subsystem if touchpad data */ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && -+ buf[7] == 0x86) { -+ imon_touch_event(ictx, buf); -+ -+ /* look for mouse events with pad in mouse mode */ -+ } else if (ictx->pad_mouse) { -+ if (imon_mouse_event(ictx, buf, len)) -+ return; -+ } -+ -+ /* Now for some special handling to convert pad input to arrow keys */ -+ if (((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) || -+ ((len == 8) && (buf[0] & 0x40) && -+ !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) { -+ len = 8; -+ imon_pad_to_keys(ictx, buf); -+ norelease = 1; -+ } -+ -+ if (debug) { -+ printk(KERN_INFO "intf%d decoded packet: ", intf); -+ for (i = 0; i < len; ++i) -+ printk("%02x ", buf[i]); -+ printk("\n"); -+ } -+ -+ press_type = imon_parse_press_type(ictx, buf, ksrc); -+ if (press_type < 0) -+ goto not_input_data; -+ -+ if (ictx->kc == KEY_UNKNOWN) -+ goto unknown_key; -+ -+ /* KEY_MUTE repeats from MCE and knob need to be suppressed */ -+ if ((ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) -+ && (buf[7] == 0xee || ksrc == IMON_BUTTON_MCE)) { -+ do_gettimeofday(&t); -+ msec = tv2int(&t, &prev_time); -+ prev_time = t; -+ if (msec < 200) -+ return; -+ } -+ -+ input_report_key(idev, ictx->kc, press_type); -+ input_sync(idev); -+ -+ /* panel keys and some remote keys don't generate a release */ -+ if (panel_key || norelease) { -+ input_report_key(idev, ictx->kc, 0); -+ input_sync(idev); -+ } -+ -+ ictx->last_keycode = ictx->kc; -+ -+ return; -+ -+unknown_key: -+ dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, -+ (panel_key ? be64_to_cpu(panel_key) : -+ be32_to_cpu(remote_key))); -+ return; -+ -+not_input_data: -+ if (len != 8) { -+ dev_warn(dev, "imon %s: invalid incoming packet " -+ "size (len = %d, intf%d)\n", __func__, len, intf); -+ return; -+ } -+ -+ /* iMON 2.4G associate frame */ -+ if (buf[0] == 0x00 && -+ buf[2] == 0xFF && /* REFID */ -+ buf[3] == 0xFF && -+ buf[4] == 0xFF && -+ buf[5] == 0xFF && /* iMON 2.4G */ -+ ((buf[6] == 0x4E && buf[7] == 0xDF) || /* LT */ -+ (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */ -+ dev_warn(dev, "%s: remote associated refid=%02X\n", -+ __func__, buf[1]); -+ ictx->ir_isassociating = 0; -+ } -+} -+ -+/** -+ * mce/rc6 keypresses have no distinct release code, use timer -+ */ -+static void imon_mce_timeout(unsigned long data) -+{ -+ struct imon_context *ictx = (struct imon_context *)data; -+ -+ input_report_key(ictx->idev, ictx->last_keycode, 0); -+ input_sync(ictx->idev); -+} -+ -+/** -+ * report touchscreen input -+ */ -+static void imon_touch_display_timeout(unsigned long data) -+{ -+ struct imon_context *ictx = (struct imon_context *)data; -+ -+ if (!ictx->display_type == IMON_DISPLAY_TYPE_VGA) -+ return; -+ -+ input_report_abs(ictx->touch, ABS_X, ictx->touch_x); -+ input_report_abs(ictx->touch, ABS_Y, ictx->touch_y); -+ input_report_key(ictx->touch, BTN_TOUCH, 0x00); -+ input_sync(ictx->touch); -+} -+ -+/** -+ * Callback function for USB core API: receive data -+ */ -+static void usb_rx_callback_intf0(struct urb *urb) -+{ -+ struct imon_context *ictx; -+ unsigned char *buf; -+ int len; -+ int intfnum = 0; -+ -+ if (!urb) -+ return; -+ -+ ictx = (struct imon_context *)urb->context; -+ if (!ictx) -+ return; -+ -+ buf = urb->transfer_buffer; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case -ESHUTDOWN: /* transport endpoint was shut down */ -+ break; -+ -+ case 0: -+ imon_incoming_packet(ictx, urb, intfnum); -+ break; -+ -+ default: -+ dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); -+} -+ -+static void usb_rx_callback_intf1(struct urb *urb) -+{ -+ struct imon_context *ictx; -+ unsigned char *buf; -+ int len; -+ int intfnum = 1; -+ -+ if (!urb) -+ return; -+ -+ ictx = (struct imon_context *)urb->context; -+ if (!ictx) -+ return; -+ -+ buf = urb->transfer_buffer; -+ len = urb->actual_length; -+ -+ switch (urb->status) { -+ case -ENOENT: /* usbcore unlink successful! */ -+ return; -+ -+ case -ESHUTDOWN: /* transport endpoint was shut down */ -+ break; -+ -+ case 0: -+ imon_incoming_packet(ictx, urb, intfnum); -+ break; -+ -+ default: -+ dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", -+ __func__, urb->status); -+ break; -+ } -+ -+ usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); -+} -+ -+static struct input_dev *imon_init_idev(struct imon_context *ictx) -+{ -+ struct input_dev *idev; -+ int ret, i; -+ -+ idev = input_allocate_device(); -+ if (!idev) { -+ dev_err(ictx->dev, "remote input dev allocation failed\n"); -+ goto idev_alloc_failed; -+ } -+ -+ snprintf(ictx->name_idev, sizeof(ictx->name_idev), -+ "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product); -+ idev->name = ictx->name_idev; -+ -+ usb_make_path(ictx->usbdev_intf0, ictx->phys_idev, -+ sizeof(ictx->phys_idev)); -+ strlcat(ictx->phys_idev, "/input0", sizeof(ictx->phys_idev)); -+ idev->phys = ictx->phys_idev; -+ -+ idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); -+ -+ idev->keybit[BIT_WORD(BTN_MOUSE)] = -+ BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); -+ idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | -+ BIT_MASK(REL_WHEEL); -+ -+ input_set_drvdata(idev, ictx); -+ -+ if (ir_protocol == IMON_IR_PROTOCOL_MCE) -+ ret = sparse_keymap_setup(idev, imon_mce_key_table, NULL); -+ else -+ ret = sparse_keymap_setup(idev, imon_remote_key_table, NULL); -+ if (ret) -+ goto keymap_failed; -+ -+ /* can't use sparse keymap atm, 64-bit keycodes */ -+ for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { -+ u16 kc = imon_panel_key_table[i].keycode; -+ __set_bit(kc, idev->keybit); -+ } -+ -+ usb_to_input_id(ictx->usbdev_intf0, &idev->id); -+ idev->dev.parent = ictx->dev; -+ ret = input_register_device(idev); -+ if (ret < 0) { -+ dev_err(ictx->dev, "remote input dev register failed\n"); -+ goto idev_register_failed; -+ } -+ -+ return idev; -+ -+idev_register_failed: -+ sparse_keymap_free(idev); -+keymap_failed: -+ input_free_device(idev); -+idev_alloc_failed: -+ -+ return NULL; -+} -+ -+static struct input_dev *imon_init_touch(struct imon_context *ictx) -+{ -+ struct input_dev *touch; -+ int ret; -+ -+ touch = input_allocate_device(); -+ if (!touch) { -+ dev_err(ictx->dev, "touchscreen input dev allocation failed\n"); -+ goto touch_alloc_failed; -+ } -+ -+ snprintf(ictx->name_touch, sizeof(ictx->name_touch), -+ "iMON USB Touchscreen (%04x:%04x)", -+ ictx->vendor, ictx->product); -+ touch->name = ictx->name_touch; -+ -+ usb_make_path(ictx->usbdev_intf1, ictx->phys_touch, -+ sizeof(ictx->phys_touch)); -+ strlcat(ictx->phys_touch, "/input1", sizeof(ictx->phys_touch)); -+ touch->phys = ictx->phys_touch; -+ -+ touch->evbit[0] = -+ BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); -+ touch->keybit[BIT_WORD(BTN_TOUCH)] = -+ BIT_MASK(BTN_TOUCH); -+ input_set_abs_params(touch, ABS_X, -+ 0x00, 0xfff, 0, 0); -+ input_set_abs_params(touch, ABS_Y, -+ 0x00, 0xfff, 0, 0); -+ -+ input_set_drvdata(touch, ictx); -+ -+ usb_to_input_id(ictx->usbdev_intf1, &touch->id); -+ touch->dev.parent = ictx->dev; -+ ret = input_register_device(touch); -+ if (ret < 0) { -+ dev_info(ictx->dev, "touchscreen input dev register failed\n"); -+ goto touch_register_failed; -+ } -+ -+ return touch; -+ -+touch_register_failed: -+ input_free_device(ictx->touch); -+ mutex_unlock(&ictx->lock); -+ -+touch_alloc_failed: -+ return NULL; -+} -+ -+static bool imon_find_endpoints(struct imon_context *ictx, -+ struct usb_host_interface *iface_desc) -+{ -+ struct usb_endpoint_descriptor *ep; -+ struct usb_endpoint_descriptor *rx_endpoint = NULL; -+ struct usb_endpoint_descriptor *tx_endpoint = NULL; -+ int ifnum = iface_desc->desc.bInterfaceNumber; -+ int num_endpts = iface_desc->desc.bNumEndpoints; -+ int i, ep_dir, ep_type; -+ bool ir_ep_found = 0; -+ bool display_ep_found = 0; -+ bool tx_control = 0; -+ -+ /* -+ * Scan the endpoint list and set: -+ * first input endpoint = IR endpoint -+ * first output endpoint = display endpoint -+ */ -+ for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) { -+ ep = &iface_desc->endpoint[i].desc; -+ ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK; -+ ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ -+ if (!ir_ep_found && ep_dir == USB_DIR_IN && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ -+ rx_endpoint = ep; -+ ir_ep_found = 1; -+ dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__); -+ -+ } else if (!display_ep_found && ep_dir == USB_DIR_OUT && -+ ep_type == USB_ENDPOINT_XFER_INT) { -+ tx_endpoint = ep; -+ display_ep_found = 1; -+ dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__); -+ } -+ } -+ -+ if (ifnum == 0) { -+ ictx->rx_endpoint_intf0 = rx_endpoint; -+ /* -+ * tx is used to send characters to lcd/vfd, associate RF -+ * remotes, set IR protocol, and maybe more... -+ */ -+ ictx->tx_endpoint = tx_endpoint; -+ } else { -+ ictx->rx_endpoint_intf1 = rx_endpoint; -+ } -+ -+ /* -+ * If we didn't find a display endpoint, this is probably one of the -+ * newer iMON devices that use control urb instead of interrupt -+ */ -+ if (!display_ep_found) { -+ tx_control = 1; -+ display_ep_found = 1; -+ dev_dbg(ictx->dev, "%s: device uses control endpoint, not " -+ "interface OUT endpoint\n", __func__); -+ } -+ -+ /* -+ * Some iMON receivers have no display. Unfortunately, it seems -+ * that SoundGraph recycles device IDs between devices both with -+ * and without... :\ -+ */ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) { -+ display_ep_found = 0; -+ dev_dbg(ictx->dev, "%s: device has no display\n", __func__); -+ } -+ -+ /* -+ * iMON Touch devices have a VGA touchscreen, but no "display", as -+ * that refers to e.g. /dev/lcd0 (a character device LCD or VFD). -+ */ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { -+ display_ep_found = 0; -+ dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__); -+ } -+ -+ /* Input endpoint is mandatory */ -+ if (!ir_ep_found) -+ err("%s: no valid input (IR) endpoint found.", __func__); -+ -+ ictx->tx_control = tx_control; -+ -+ if (display_ep_found) -+ ictx->display_supported = 1; -+ -+ return ir_ep_found; -+ -+} -+ -+static struct imon_context *imon_init_intf0(struct usb_interface *intf) -+{ -+ struct imon_context *ictx; -+ struct urb *rx_urb; -+ struct urb *tx_urb; -+ struct device *dev = &intf->dev; -+ struct usb_host_interface *iface_desc; -+ int ret; -+ -+ ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL); -+ if (!ictx) { -+ dev_err(dev, "%s: kzalloc failed for context", __func__); -+ goto exit; -+ } -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ dev_err(dev, "%s: usb_alloc_urb failed for IR urb", __func__); -+ goto rx_urb_alloc_failed; -+ } -+ tx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!tx_urb) { -+ dev_err(dev, "%s: usb_alloc_urb failed for display urb", -+ __func__); -+ goto tx_urb_alloc_failed; -+ } -+ -+ mutex_init(&ictx->lock); -+ -+ mutex_lock(&ictx->lock); -+ -+ if (ir_protocol == IMON_IR_PROTOCOL_MCE) { -+ init_timer(&ictx->itimer); -+ ictx->itimer.data = (unsigned long)ictx; -+ ictx->itimer.function = imon_mce_timeout; -+ } -+ -+ ictx->dev = dev; -+ ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf)); -+ ictx->dev_present_intf0 = 1; -+ ictx->rx_urb_intf0 = rx_urb; -+ ictx->tx_urb = tx_urb; -+ -+ ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); -+ ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); -+ -+ iface_desc = intf->cur_altsetting; -+ if (!imon_find_endpoints(ictx, iface_desc)) -+ goto find_endpoint_failed; -+ -+ ictx->idev = imon_init_idev(ictx); -+ if (!ictx->idev) { -+ dev_err(dev, "%s: input device setup failed\n", __func__); -+ goto idev_setup_failed; -+ } -+ -+ usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, -+ usb_rcvintpipe(ictx->usbdev_intf0, -+ ictx->rx_endpoint_intf0->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf0, ictx, -+ ictx->rx_endpoint_intf0->bInterval); -+ -+ ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL); -+ if (ret) { -+ err("%s: usb_submit_urb failed for intf0 (%d)", -+ __func__, ret); -+ goto urb_submit_failed; -+ } -+ -+ return ictx; -+ -+urb_submit_failed: -+ sparse_keymap_free(ictx->idev); -+ input_unregister_device(ictx->idev); -+ input_free_device(ictx->idev); -+idev_setup_failed: -+find_endpoint_failed: -+ mutex_unlock(&ictx->lock); -+ usb_free_urb(tx_urb); -+tx_urb_alloc_failed: -+ usb_free_urb(rx_urb); -+rx_urb_alloc_failed: -+ kfree(ictx); -+exit: -+ dev_err(dev, "unable to initialize intf0, err %d\n", ret); -+ -+ return NULL; -+} -+ -+static struct imon_context *imon_init_intf1(struct usb_interface *intf, -+ struct imon_context *ictx) -+{ -+ struct urb *rx_urb; -+ struct usb_host_interface *iface_desc; -+ int ret; -+ -+ rx_urb = usb_alloc_urb(0, GFP_KERNEL); -+ if (!rx_urb) { -+ err("%s: usb_alloc_urb failed for IR urb", __func__); -+ ret = -ENOMEM; -+ goto rx_urb_alloc_failed; -+ } -+ -+ mutex_lock(&ictx->lock); -+ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { -+ init_timer(&ictx->ttimer); -+ ictx->ttimer.data = (unsigned long)ictx; -+ ictx->ttimer.function = imon_touch_display_timeout; -+ } -+ -+ ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); -+ ictx->dev_present_intf1 = 1; -+ ictx->rx_urb_intf1 = rx_urb; -+ -+ iface_desc = intf->cur_altsetting; -+ if (!imon_find_endpoints(ictx, iface_desc)) -+ goto find_endpoint_failed; -+ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { -+ ictx->touch = imon_init_touch(ictx); -+ if (!ictx->touch) -+ goto touch_setup_failed; -+ } else -+ ictx->touch = NULL; -+ -+ usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, -+ usb_rcvintpipe(ictx->usbdev_intf1, -+ ictx->rx_endpoint_intf1->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf1, ictx, -+ ictx->rx_endpoint_intf1->bInterval); -+ -+ ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL); -+ -+ if (ret) { -+ err("%s: usb_submit_urb failed for intf1 (%d)", -+ __func__, ret); -+ goto urb_submit_failed; -+ } -+ -+ return ictx; -+ -+urb_submit_failed: -+ if (ictx->touch) { -+ input_unregister_device(ictx->touch); -+ input_free_device(ictx->touch); -+ } -+touch_setup_failed: -+find_endpoint_failed: -+ mutex_unlock(&ictx->lock); -+ usb_free_urb(rx_urb); -+rx_urb_alloc_failed: -+ dev_err(ictx->dev, "unable to initialize intf0, err %d\n", ret); -+ -+ return NULL; -+} -+ -+static void imon_set_display_type(struct imon_context *ictx, -+ struct usb_interface *intf) -+{ -+ int configured_display_type = IMON_DISPLAY_TYPE_VFD; -+ -+ /* -+ * Try to auto-detect the type of display if the user hasn't set -+ * it by hand via the display_type modparam. Default is VFD. -+ */ -+ if (display_type == IMON_DISPLAY_TYPE_AUTO) { -+ if (usb_match_id(intf, lcd_device_list)) -+ configured_display_type = IMON_DISPLAY_TYPE_LCD; -+ else if (usb_match_id(intf, imon_touchscreen_list)) -+ configured_display_type = IMON_DISPLAY_TYPE_VGA; -+ else if (usb_match_id(intf, ir_only_list)) -+ configured_display_type = IMON_DISPLAY_TYPE_NONE; -+ else -+ configured_display_type = IMON_DISPLAY_TYPE_VFD; -+ } else { -+ configured_display_type = display_type; -+ dev_dbg(ictx->dev, "%s: overriding display type to %d via " -+ "modparam\n", __func__, display_type); -+ } -+ -+ ictx->display_type = configured_display_type; -+} -+ -+static void imon_init_display(struct imon_context *ictx, -+ struct usb_interface *intf) -+{ -+ int ret; -+ const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, -+ 0x00, 0x00, 0x00, 0x88 }; -+ -+ dev_dbg(ictx->dev, "Registering iMON display with sysfs\n"); -+ -+ /* set up sysfs entry for built-in clock */ -+ ret = sysfs_create_group(&intf->dev.kobj, -+ &imon_display_attribute_group); -+ if (ret) -+ dev_err(ictx->dev, "Could not create display sysfs " -+ "entries(%d)", ret); -+ -+ if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) -+ ret = usb_register_dev(intf, &imon_lcd_class); -+ else -+ ret = usb_register_dev(intf, &imon_vfd_class); -+ if (ret) -+ /* Not a fatal error, so ignore */ -+ dev_info(ictx->dev, "could not get a minor number for " -+ "display\n"); -+ -+ /* Enable front-panel buttons and/or knobs */ -+ memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet)); -+ ret = send_packet(ictx); -+ /* Not fatal, but warn about it */ -+ if (ret) -+ dev_info(ictx->dev, "failed to enable front-panel " -+ "buttons and/or knobs\n"); -+} -+ -+/** -+ * Callback function for USB core API: Probe -+ */ -+static int __devinit imon_probe(struct usb_interface *interface, -+ const struct usb_device_id *id) -+{ -+ struct usb_device *usbdev = NULL; -+ struct usb_host_interface *iface_desc = NULL; -+ struct usb_interface *first_if; -+ struct device *dev = &interface->dev; -+ int ifnum, code_length, sysfs_err; -+ int ret = 0; -+ struct imon_context *ictx = NULL; -+ struct imon_context *first_if_ctx = NULL; -+ u16 vendor, product; -+ -+ code_length = BUF_CHUNK_SIZE * 8; -+ -+ usbdev = usb_get_dev(interface_to_usbdev(interface)); -+ iface_desc = interface->cur_altsetting; -+ ifnum = iface_desc->desc.bInterfaceNumber; -+ vendor = le16_to_cpu(usbdev->descriptor.idVendor); -+ product = le16_to_cpu(usbdev->descriptor.idProduct); -+ -+ dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", -+ __func__, vendor, product, ifnum); -+ -+ /* prevent races probing devices w/multiple interfaces */ -+ mutex_lock(&driver_lock); -+ -+ first_if = usb_ifnum_to_if(usbdev, 0); -+ first_if_ctx = (struct imon_context *)usb_get_intfdata(first_if); -+ -+ -+ if (ifnum == 0) { -+ ictx = imon_init_intf0(interface); -+ if (!ictx) { -+ err("%s: failed to initialize context!\n", __func__); -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ imon_set_display_type(ictx, interface); -+ -+ if (ictx->display_supported) -+ imon_init_display(ictx, interface); -+ -+ if (product == 0xffdc) { -+ /* RF products *also* use 0xffdc... sigh... */ -+ sysfs_err = sysfs_create_group(&interface->dev.kobj, -+ &imon_rf_attribute_group); -+ if (sysfs_err) -+ err("%s: Could not create RF sysfs entries(%d)", -+ __func__, sysfs_err); -+ } -+ -+ } else { -+ /* this is the secondary interface on the device */ -+ ictx = imon_init_intf1(interface, first_if_ctx); -+ if (!ictx) { -+ err("%s: failed to attach to context!\n", __func__); -+ ret = -ENODEV; -+ goto fail; -+ } -+ -+ } -+ -+ usb_set_intfdata(interface, ictx); -+ -+ /* set IR protocol/remote type */ -+ imon_set_ir_protocol(ictx); -+ -+ dev_info(dev, "iMON device (%04x:%04x, intf%d) on " -+ "usb<%d:%d> initialized\n", vendor, product, ifnum, -+ usbdev->bus->busnum, usbdev->devnum); -+ -+ mutex_unlock(&ictx->lock); -+ mutex_unlock(&driver_lock); -+ -+ return 0; -+ -+fail: -+ mutex_unlock(&driver_lock); -+ dev_err(dev, "unable to register, err %d\n", ret); -+ -+ return ret; -+} -+ -+/** -+ * Callback function for USB core API: disconnect -+ */ -+static void __devexit imon_disconnect(struct usb_interface *interface) -+{ -+ struct imon_context *ictx; -+ struct device *dev; -+ int ifnum; -+ -+ /* prevent races with multi-interface device probing and display_open */ -+ mutex_lock(&driver_lock); -+ -+ ictx = usb_get_intfdata(interface); -+ dev = ictx->dev; -+ ifnum = interface->cur_altsetting->desc.bInterfaceNumber; -+ -+ mutex_lock(&ictx->lock); -+ -+ /* -+ * sysfs_remove_group is safe to call even if sysfs_create_group -+ * hasn't been called -+ */ -+ sysfs_remove_group(&interface->dev.kobj, -+ &imon_display_attribute_group); -+ sysfs_remove_group(&interface->dev.kobj, -+ &imon_rf_attribute_group); -+ -+ usb_set_intfdata(interface, NULL); -+ -+ /* Abort ongoing write */ -+ if (ictx->tx.busy) { -+ usb_kill_urb(ictx->tx_urb); -+ complete_all(&ictx->tx.finished); -+ } -+ -+ if (ifnum == 0) { -+ ictx->dev_present_intf0 = 0; -+ usb_kill_urb(ictx->rx_urb_intf0); -+ sparse_keymap_free(ictx->idev); -+ input_unregister_device(ictx->idev); -+ if (ictx->display_supported) { -+ if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) -+ usb_deregister_dev(interface, &imon_lcd_class); -+ else -+ usb_deregister_dev(interface, &imon_vfd_class); -+ } -+ } else { -+ ictx->dev_present_intf1 = 0; -+ usb_kill_urb(ictx->rx_urb_intf1); -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) -+ input_unregister_device(ictx->touch); -+ } -+ -+ if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) { -+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) -+ del_timer_sync(&ictx->ttimer); -+ mutex_unlock(&ictx->lock); -+ if (!ictx->display_isopen) -+ free_imon_context(ictx); -+ } else { -+ if (ictx->ir_protocol == IMON_IR_PROTOCOL_MCE) -+ del_timer_sync(&ictx->itimer); -+ mutex_unlock(&ictx->lock); -+ } -+ -+ mutex_unlock(&driver_lock); -+ -+ dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n", -+ __func__, ifnum); -+} -+ -+static int imon_suspend(struct usb_interface *intf, pm_message_t message) -+{ -+ struct imon_context *ictx = usb_get_intfdata(intf); -+ int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; -+ -+ if (ifnum == 0) -+ usb_kill_urb(ictx->rx_urb_intf0); -+ else -+ usb_kill_urb(ictx->rx_urb_intf1); -+ -+ return 0; -+} -+ -+static int imon_resume(struct usb_interface *intf) -+{ -+ int rc = 0; -+ struct imon_context *ictx = usb_get_intfdata(intf); -+ int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; -+ -+ if (ifnum == 0) { -+ usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, -+ usb_rcvintpipe(ictx->usbdev_intf0, -+ ictx->rx_endpoint_intf0->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf0, ictx, -+ ictx->rx_endpoint_intf0->bInterval); -+ -+ rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); -+ -+ } else { -+ usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, -+ usb_rcvintpipe(ictx->usbdev_intf1, -+ ictx->rx_endpoint_intf1->bEndpointAddress), -+ ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf), -+ usb_rx_callback_intf1, ictx, -+ ictx->rx_endpoint_intf1->bInterval); -+ -+ rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); -+ } -+ -+ return rc; -+} -+ -+static int __init imon_init(void) -+{ -+ int rc; -+ -+ rc = usb_register(&imon_driver); -+ if (rc) { -+ err("%s: usb register failed(%d)", __func__, rc); -+ rc = -ENODEV; -+ } -+ -+ return rc; -+} -+ -+static void __exit imon_exit(void) -+{ -+ usb_deregister(&imon_driver); -+} -+ -+module_init(imon_init); -+module_exit(imon_exit); -diff -Naur linux-2.6.33.2/drivers/input/misc/Kconfig linux-2.6.33.2.patch/drivers/input/misc/Kconfig ---- linux-2.6.33.2/drivers/input/misc/Kconfig 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/misc/Kconfig 2010-04-07 22:05:13.635247879 +0200 -@@ -319,4 +319,16 @@ - To compile this driver as a module, choose M here: the - module will be called pcap_keys. - -+config INPUT_IMON -+ tristate "SoundGraph iMON Receiver and Display" -+ depends on USB_ARCH_HAS_HCD -+ select USB -+ select INPUT_SPARSEKMAP -+ help -+ Say Y here if you want to use a SoundGraph iMON (aka Antec Veris) -+ IR Receiver and/or LCD/VFD/VGA display. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called imon. -+ - endif -diff -Naur linux-2.6.33.2/drivers/input/misc/Makefile linux-2.6.33.2.patch/drivers/input/misc/Makefile ---- linux-2.6.33.2/drivers/input/misc/Makefile 2010-04-02 01:02:33.000000000 +0200 -+++ linux-2.6.33.2.patch/drivers/input/misc/Makefile 2010-04-07 22:05:13.635247879 +0200 -@@ -13,6 +13,7 @@ - obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o - obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o - obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o -+obj-$(CONFIG_INPUT_IMON) += imon.o - obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o - obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o - obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o -diff -Naur linux-2.6.33.2/include/linux/lirc.h linux-2.6.33.2.patch/include/linux/lirc.h ---- linux-2.6.33.2/include/linux/lirc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33.2.patch/include/linux/lirc.h 2010-04-07 21:56:14.000000000 +0200 -@@ -0,0 +1,159 @@ -+/* -+ * lirc.h - linux infrared remote control header file -+ * last modified 2007/09/27 -+ */ -+ -+#ifndef _LINUX_LIRC_H -+#define _LINUX_LIRC_H -+ -+#include -+#include -+ -+/* */ -+#define PULSE_BIT 0x01000000 -+#define PULSE_MASK 0x00FFFFFF -+/* */ -+ -+#define LIRC_MODE2_SPACE 0x00000000 -+#define LIRC_MODE2_PULSE 0x01000000 -+#define LIRC_MODE2_FREQUENCY 0x02000000 -+#define LIRC_MODE2_TIMEOUT 0x03000000 -+ -+#define LIRC_VALUE_MASK 0x00FFFFFF -+#define LIRC_MODE2_MASK 0xFF000000 -+ -+#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE) -+#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE) -+#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY) -+#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT) -+ -+#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK) -+#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK) -+ -+#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE) -+#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE) -+#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY) -+#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT) -+ -+/*** lirc compatible hardware features ***/ -+ -+#define LIRC_MODE2SEND(x) (x) -+#define LIRC_SEND2MODE(x) (x) -+#define LIRC_MODE2REC(x) ((x) << 16) -+#define LIRC_REC2MODE(x) ((x) >> 16) -+ -+#define LIRC_MODE_RAW 0x00000001 -+#define LIRC_MODE_PULSE 0x00000002 -+#define LIRC_MODE_MODE2 0x00000004 -+#define LIRC_MODE_LIRCCODE 0x00000010 -+ -+ -+#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW) -+#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE) -+#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2) -+#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE) -+ -+#define LIRC_CAN_SEND_MASK 0x0000003f -+ -+#define LIRC_CAN_SET_SEND_CARRIER 0x00000100 -+#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200 -+#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400 -+ -+#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW) -+#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE) -+#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2) -+#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE) -+ -+#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK) -+ -+#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16) -+#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16) -+ -+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000 -+#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000 -+#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000 -+#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000 -+#define LIRC_CAN_SET_REC_FILTER 0x08000000 -+ -+#define LIRC_CAN_MEASURE_CARRIER 0x02000000 -+ -+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK) -+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK) -+ -+#define LIRC_CAN_NOTIFY_DECODE 0x01000000 -+ -+/*** IOCTL commands for lirc driver ***/ -+ -+#define LIRC_GET_FEATURES _IOR('i', 0x00000000, unsigned long) -+ -+#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, unsigned long) -+#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, unsigned long) -+#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, unsigned int) -+#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, unsigned int) -+#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, unsigned int) -+#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, unsigned int) -+#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, unsigned int) -+ -+#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, uint32_t) -+#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, uint32_t) -+ -+#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, uint32_t) -+#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, uint32_t) -+#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, uint32_t) -+#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, uint32_t) -+ -+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */ -+#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, unsigned long) -+ -+#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, unsigned long) -+#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, unsigned long) -+/* Note: these can reset the according pulse_width */ -+#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, unsigned int) -+#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, unsigned int) -+#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, unsigned int) -+#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, unsigned int) -+#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, unsigned int) -+ -+/* -+ * when a timeout != 0 is set the driver will send a -+ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is -+ * never sent, timeout is disabled by default -+ */ -+#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, uint32_t) -+ -+/* -+ * pulses shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x00000019, uint32_t) -+/* -+ * spaces shorter than this are filtered out by hardware (software -+ * emulation in lirc_dev?) -+ */ -+#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001a, uint32_t) -+/* -+ * if filter cannot be set independantly for pulse/space, this should -+ * be used -+ */ -+#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001b, uint32_t) -+ -+/* -+ * to set a range use -+ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the -+ * lower bound first and later -+ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound -+ */ -+ -+#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, unsigned int) -+#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, unsigned int) -+ -+#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020) -+ -+/* -+ * from the next key press on the driver will send -+ * LIRC_MODE2_FREQUENCY packets -+ */ -+#define LIRC_MEASURE_CARRIER_ENABLE _IO('i', 0x00000021) -+#define LIRC_MEASURE_CARRIER_DISABLE _IO('i', 0x00000022) -+ -+#endif diff --git a/packages/linux/url b/packages/linux/url deleted file mode 100644 index 5703069b93..0000000000 --- a/packages/linux/url +++ /dev/null @@ -1 +0,0 @@ -http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.34.1.tar.bz2