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 <linux/semaphore.h>
+
+#include <linux/lirc.h>
+#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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/pnp.h>
+
+/*//#include <asm/semaphore.h>*/
+#include <linux/semaphore.h>
+
+#include <linux/device.h>
+#include <asm-generic/ioctl.h>
+
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+
+
+#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 <linux/sched.h>
+#include <linux/module.h>
+
+#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 <linux/input.h>
+#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<<i;
+			if ((buf & ir->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)
+
