diff -urN -X dontdiff 2.6.8.1-orig/drivers/acpi/Kconfig linux-pcc-acpi-0.8.1/drivers/acpi/Kconfig
--- 2.6.8.1-orig/drivers/acpi/Kconfig	2004-10-11 23:18:04.000000000 +0900
+++ linux-pcc-acpi-0.8.1/drivers/acpi/Kconfig	2004-10-11 23:31:43.000000000 +0900
@@ -204,6 +204,27 @@
 	  If you have a legacy free Toshiba laptop (such as the Libretto L1
 	  series), say Y.
 
+config ACPI_PCC
+	tristate "Panasonic Laptop Extras"
+	depends on X86
+	depends on ACPI_INTERPRETER
+	default m
+	---help---
+	  This driver adds support for access to certain system settings
+	  on Panasonic Let's Note laptops.
+
+	  On these machines, all hotkeys are handled through the ACPI.
+	  This driver is required for access to controls not covered
+	  by the general ACPI drivers, such as LCD brightness, video output,
+	  etc.
+
+	  In order to use this driver, you must configure acpid to handle 
+	  hotkey events; scripts to handle these events and information about 
+	  this driver will be available at <http://www.da-cha.org/letsnote/>
+
+	  If you have a Panasonic Let's Note laptop (such as the CF-T2, Y2,
+	  R1N, R2, W2, R3), say Y.
+
 config ACPI_DEBUG
 	bool "Debug Statements"
 	depends on ACPI_INTERPRETER
diff -urN -X dontdiff 2.6.8.1-orig/drivers/acpi/Makefile linux-pcc-acpi-0.8.1/drivers/acpi/Makefile
--- 2.6.8.1-orig/drivers/acpi/Makefile	2004-10-11 23:17:41.000000000 +0900
+++ linux-pcc-acpi-0.8.1/drivers/acpi/Makefile	2004-10-11 23:31:43.000000000 +0900
@@ -47,4 +47,5 @@
 obj-$(CONFIG_ACPI_NUMA)		+= numa.o
 obj-$(CONFIG_ACPI_ASUS)		+= asus_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
+obj-$(CONFIG_ACPI_PCC)		+= pcc_acpi.o
 obj-$(CONFIG_ACPI_BUS)		+= scan.o 
diff -urN -X dontdiff 2.6.8.1-orig/drivers/acpi/pcc_acpi.c linux-pcc-acpi-0.8.1/drivers/acpi/pcc_acpi.c
--- 2.6.8.1-orig/drivers/acpi/pcc_acpi.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-pcc-acpi-0.8.1/drivers/acpi/pcc_acpi.c	2004-10-12 00:08:18.000000000 +0900
@@ -0,0 +1,966 @@
+/*
+ *  Panasonic HotKey and lcd brightness control Extra driver
+ *  (C) 2004 Hiroshi Miura <miura@da-cha.org>
+ *  (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
+ *
+ *  derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as 
+ *  publicshed by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *---------------------------------------------------------------------------
+ *
+ * ChangeLog:
+ *	Sep.15, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		-v0.8	Generate key input event on input subsystem.
+ *			This is based on yet another driver written by Ryuta Nakanishi.
+ *
+ *	Sep.10, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		-v0.7	Change proc interface functions using seq_file
+ *			fasility as same as other ACPI drivers.
+ *
+ *	Aug.28, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		-v0.6.4 Fix a silly error with status checking
+ *
+ *	Aug.25, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		-v0.6.3 replace read_acpi_int by standard function acpi_evaluate_integer
+ *			some clean up and make smart copyright notice.
+ *			fix return value of pcc_acpi_get_key()
+ *			fix checking return value of acpi_bus_register_driver() 
+ *
+ *      Aug.22, 2004    David Bronaugh <dbronaugh@linuxboxen.org>
+ *              -v0.6.2 Add check on ACPI data (num_sifr)
+ *                      Coding style cleanups, better error messages/handling
+ *			Fixed an off-by-one error in memory allocation
+ *
+ *      Aug.21, 2004    David Bronaugh <dbronaugh@linuxboxen.org>
+ *              -v0.6.1 Fix a silly error with status checking
+ *
+ *      Aug.20, 2004    David Bronaugh <dbronaugh@linuxboxen.org>
+ *              - v0.6  Correct brightness controls to reflect reality
+ *                      based on information gleaned by Hiroshi Miura
+ *                      and discussions with Hiroshi Miura
+ *
+ *	Aug.10, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		- v0.5  support LCD brightness control
+ *			based on the disclosed information by MEI.
+ *
+ *	Jul.25, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		- v0.4  first post version
+ *		        add function to retrive SIFR
+ *
+ *	Jul.24, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		- v0.3  get proper status of hotkey
+ *
+ *      Jul.22, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		- v0.2  add HotKey handler
+ *
+ *      Jul.17, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		- v0.1  start from toshiba_acpi driver written by John Belmonte
+ *
+ */
+
+#define ACPI_PCC_VERSION	"0.8.1"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/input.h>
+
+#define ACPI_HOTKEY_COMPONENT		0x10000000
+#define _COMPONENT		ACPI_HOTKEY_COMPONENT
+ACPI_MODULE_NAME		("pcc_acpi")
+
+MODULE_AUTHOR("Hiroshi Miura");
+MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Lets Note laptops");
+MODULE_LICENSE("GPL");
+
+#define LOGPREFIX "pcc_acpi: "
+
+/****************************************************
+ * Define ACPI PATHs 
+ ****************************************************/
+/* Lets note hotkeys */
+#define DEVICE_NAME_HKEY 	"\\_SB_.HKEY"
+#define METHOD_HKEY_QUERY	"HINF"
+#define METHOD_HKEY_SQTY	"SQTY"
+#define METHOD_HKEY_SINF	"SINF"
+#define METHOD_HKEY_SSET	"SSET"
+#define HKEY_HID		"MAT0012,MAT0013,MAT0018,MAT0019"
+#define HKEY_NOTIFY		 0x80
+
+/*******************************************************************
+ *
+ * definitions for /proc/ interface
+ *
+ *******************************************************************/
+#define PROC_PCC		"pcc"
+
+#define ACPI_PCC_DRIVER_NAME "PCC Extra Driver"
+#define ACPI_PCC_DEVICE_NAME "PCCExtra"
+#define ACPI_PCC_CLASS "pcc"
+
+#define ACPI_PCC_INPUT_PHYS   "panasonic/hkey0"
+
+/* This is transitional definition */
+#ifndef KEY_BATT
+#define KEY_BATT  227
+#endif
+
+/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
+   ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00 
+*/
+enum SINF_BITS { SINF_NUM_BATTERIES, SINF_LCD_TYPE, SINF_AC_MAX_BRIGHT, 
+		 SINF_AC_MIN_BRIGHT, SINF_AC_CUR_BRIGHT, SINF_DC_MAX_BRIGHT,
+		 SINF_DC_MIN_BRIGHT, SINF_DC_CUR_BRIGHT, SINF_MUTE,
+		 SINF_RESERVED,      SINF_ENV_STATE,
+};
+
+static int acpi_pcc_hotkey_add (struct acpi_device *device);
+static int acpi_pcc_hotkey_remove (struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_pcc_driver = {
+	.name =		ACPI_PCC_DRIVER_NAME,
+	.class =	ACPI_PCC_CLASS,
+	.ids =		HKEY_HID,
+	.ops =		{
+				.add =		acpi_pcc_hotkey_add,
+				.remove =	acpi_pcc_hotkey_remove,
+			},
+};
+
+struct acpi_hotkey {
+	acpi_handle		handle;
+	struct acpi_device	*device;
+	struct proc_dir_entry   *proc_dir_entry;
+	unsigned long		num_sifr;
+	unsigned long		status;
+	struct input_dev 	*input_dev;
+};
+
+struct pcc_keyinput {
+	struct acpi_hotkey      *hotkey;
+	int key_mode;
+};
+
+/* --------------------------------------------------------------------------
+                              FS Interface (/proc)
+   -------------------------------------------------------------------------- */
+static int acpi_pcc_version_open_fs(struct inode*,struct file*);
+static int acpi_pcc_numbatteries_open_fs(struct inode*,struct file*);
+static int acpi_pcc_lcdtype_open_fs(struct inode*,struct file*);
+static int acpi_pcc_mute_open_fs(struct inode*,struct file*);
+static int acpi_pcc_ac_brightness_max_open_fs(struct inode*,struct file*);
+static int acpi_pcc_ac_brightness_min_open_fs(struct inode*,struct file*);
+static int acpi_pcc_dc_brightness_max_open_fs(struct inode*,struct file*);
+static int acpi_pcc_dc_brightness_min_open_fs(struct inode*,struct file*);
+static int acpi_pcc_ac_brightness_open_fs(struct inode*,struct file*);
+static int acpi_pcc_dc_brightness_open_fs(struct inode*,struct file*);
+static int acpi_pcc_keyinput_open_fs(struct inode*,struct file*);
+static ssize_t acpi_pcc_write_mute (struct file*,const char __user *,size_t,loff_t *);
+static ssize_t acpi_pcc_write_ac_brightness (struct file*,const char __user *,size_t,loff_t *);
+static ssize_t acpi_pcc_write_dc_brightness (struct file*,const char __user *,size_t,loff_t *);
+static ssize_t acpi_pcc_write_keyinput (struct file*,const char __user *,size_t,loff_t *);
+
+static struct file_operations acpi_pcc_version_fops = {
+	.open		= acpi_pcc_version_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_numbatteries_fops = {
+	.open		= acpi_pcc_numbatteries_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_lcdtype_fops = {
+	.open		= acpi_pcc_lcdtype_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_mute_fops = {
+	.open		= acpi_pcc_mute_open_fs,
+	.read		= seq_read,
+	.write		= acpi_pcc_write_mute,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_ac_brightness_fops = {
+	.open		= acpi_pcc_ac_brightness_open_fs,
+	.read		= seq_read,
+	.write		= acpi_pcc_write_ac_brightness,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_ac_brightness_max_fops = {
+	.open		= acpi_pcc_ac_brightness_max_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_ac_brightness_min_fops = {
+	.open		= acpi_pcc_ac_brightness_min_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_dc_brightness_fops = {
+	.open		= acpi_pcc_dc_brightness_open_fs,
+	.read		= seq_read,
+	.write		= acpi_pcc_write_dc_brightness,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_dc_brightness_max_fops = {
+	.open		= acpi_pcc_dc_brightness_max_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_dc_brightness_min_fops = {
+	.open		= acpi_pcc_dc_brightness_min_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+static struct file_operations acpi_pcc_keyinput_fops = {
+	.open		= acpi_pcc_keyinput_open_fs,
+	.read		= seq_read,
+	.write		= acpi_pcc_write_keyinput,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+/* --------------------------------------------------------------------------
+                           method access functions
+   -------------------------------------------------------------------------- */
+static int acpi_pcc_write_sset(int func, int val, struct acpi_hotkey *hotkey)
+{
+	struct acpi_object_list params;
+	union acpi_object in_objs[2];
+	acpi_status status = AE_OK;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_write_sset");
+
+	params.count = sizeof(in_objs)/sizeof(in_objs[0]);
+	params.pointer = in_objs;
+	in_objs[0].type = ACPI_TYPE_INTEGER;
+	in_objs[0].integer.value = func;
+	in_objs[1].type = ACPI_TYPE_INTEGER;
+	in_objs[1].integer.value = val;
+
+	status = acpi_evaluate_object(hotkey->handle, METHOD_HKEY_SSET, &params, 0);
+
+	return_VALUE(status == AE_OK);
+}
+
+static inline int acpi_pcc_get_sqty(struct acpi_device *device) 
+{
+	unsigned long s;
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_get_sqty");
+
+	status = acpi_evaluate_integer(device->handle,METHOD_HKEY_SQTY,NULL,&s);
+	if (ACPI_SUCCESS(status)) {
+		return_VALUE(s);
+	} else {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+				  "evaluation error HKEY.SQTY\n"));
+		return_VALUE(-EINVAL);
+	}
+}
+
+static int acpi_pcc_retrieve_biosdata(u32* sinf, struct acpi_hotkey *hotkey) 
+{
+	acpi_status status;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	union acpi_object *hkey = NULL;
+	int i;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata");
+
+	status = acpi_evaluate_object(hotkey->handle, METHOD_HKEY_SINF, 0 , &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "evaluation error HKEY.SINF\n"));
+		return_VALUE(0);
+	}
+
+	hkey = (union acpi_object *) buffer.pointer;
+	if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
+		goto end;
+	}
+	
+	if (hotkey->num_sifr < hkey->package.count) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "SQTY reports bad SINF length\n"));
+		status = AE_ERROR;
+		goto end;
+	}
+
+	for (i = 0; i < hkey->package.count; i++) {
+		union acpi_object *element = &(hkey->package.elements[i]);
+		if (likely(element->type == ACPI_TYPE_INTEGER)) {
+			sinf[i] = element->integer.value;
+		} else {
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF data\n"));
+		}
+	}
+	sinf[hkey->package.count] = -1; 
+
+end:
+	acpi_os_free(buffer.pointer);
+	return_VALUE(status == AE_OK);
+}
+
+static int acpi_pcc_read_sinf_field(struct seq_file *seq, int field)
+{
+	struct acpi_hotkey *hotkey = (struct acpi_hotkey *) seq->private;
+	u32* sinf = kmalloc(sizeof(u32) * (hotkey->num_sifr + 1), GFP_KERNEL);
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_read_sinf_field");
+
+	if (!sinf) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate %li bytes\n", 
+		       sizeof(u32) * hotkey->num_sifr));
+		return_VALUE(0);
+	}
+
+	if (acpi_pcc_retrieve_biosdata(sinf, hotkey)) {
+		seq_printf(seq, "%u\n",	sinf[field]);
+	} else {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't retrieve BIOS data\n"));
+	}
+
+	kfree(sinf);
+	return_VALUE(0);
+}
+
+
+/* --------------------------------------------------------------------------
+                       user interface functions
+   -------------------------------------------------------------------------- */
+
+/* Sinf read methods */
+static int acpi_pcc_numbatteries_show(struct seq_file *seq, void *offset)
+{
+	return acpi_pcc_read_sinf_field(seq, SINF_NUM_BATTERIES);
+}
+
+static int acpi_pcc_lcdtype_show(struct seq_file *seq, void *offset)
+{
+	return acpi_pcc_read_sinf_field(seq, SINF_LCD_TYPE);
+}
+
+static int acpi_pcc_ac_max_brightness_show(struct seq_file *seq, void *offset)
+{
+	return acpi_pcc_read_sinf_field(seq, SINF_AC_MAX_BRIGHT);
+}
+
+static int acpi_pcc_ac_min_brightness_show(struct seq_file *seq, void *offset)
+{
+	return acpi_pcc_read_sinf_field(seq, SINF_AC_MIN_BRIGHT);
+}
+
+static int acpi_pcc_ac_brightness_show(struct seq_file *seq, void *offset)
+{
+	return acpi_pcc_read_sinf_field(seq, SINF_AC_CUR_BRIGHT);
+}
+
+static int acpi_pcc_dc_max_brightness_show(struct seq_file *seq, void *offset)
+{
+	return acpi_pcc_read_sinf_field(seq, SINF_DC_MAX_BRIGHT);
+}
+
+static int acpi_pcc_dc_min_brightness_show(struct seq_file *seq, void *offset)
+{
+	return acpi_pcc_read_sinf_field(seq, SINF_DC_MIN_BRIGHT);
+}
+
+static int acpi_pcc_dc_brightness_show(struct seq_file *seq, void *offset)
+{
+	return acpi_pcc_read_sinf_field(seq, SINF_DC_CUR_BRIGHT);
+}
+
+static int acpi_pcc_mute_show(struct seq_file *seq, void *offset)
+{
+	return acpi_pcc_read_sinf_field(seq, SINF_MUTE);
+}
+
+/* write methods */
+static ssize_t acpi_pcc_write_mute (struct file *file,	const char __user *buffer,
+		     size_t count, loff_t *ppos)
+{
+	struct seq_file		*seq = (struct seq_file *)file->private_data;
+	struct acpi_hotkey	*hotkey = (struct acpi_hotkey *)seq->private;
+	char			write_string[4]= {'\0'};
+	u32 mute;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_write_mute");
+
+	if (!hotkey || (count > sizeof(write_string) - 1))
+		return_VALUE(-EINVAL);
+
+	if (copy_from_user(write_string, buffer, count))
+		return_VALUE(-EFAULT);
+	write_string[count] = '\0';
+
+	if (sscanf(write_string, "%i", &mute) == 1 && (mute == 0 || mute == 1)) {
+		acpi_pcc_write_sset(SINF_MUTE, mute, hotkey);
+	}
+
+	return_VALUE(count);
+}
+
+static unsigned long acpi_pcc_write_brightness(struct file *file, const char __user *buffer,
+					       size_t count,
+					       int min_index, int max_index,
+					       int cur_index)
+{
+	struct seq_file		*seq = (struct seq_file *)file->private_data;
+	struct acpi_hotkey	*hotkey = (struct acpi_hotkey *)seq->private;
+	char			write_string[8] = {'\0'};
+	u32 bright;
+	u32* sinf = kmalloc(sizeof(u32) * (hotkey->num_sifr + 1), GFP_KERNEL);
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_write_brightness");
+
+	if (!hotkey || (count > sizeof(write_string) - 1))
+		return_VALUE(-EINVAL);
+
+	if (!sinf) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate %li bytes\n", 
+		       sizeof(u32) * hotkey->num_sifr));
+		return_VALUE(-EFAULT);
+	}
+
+	if (copy_from_user(write_string, buffer, count))
+		return_VALUE(-EFAULT);
+	
+	write_string[count] = '\0';
+
+	if (!acpi_pcc_retrieve_biosdata(sinf, hotkey)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't retrieve BIOS data\n"));
+		goto end;
+	}
+
+	if (sscanf(write_string, "%i", &bright) == 1 && 
+		bright >= sinf[min_index] && bright <= sinf[max_index]) {
+			acpi_pcc_write_sset(cur_index, bright, hotkey);
+	}
+
+end: 
+	kfree(sinf);
+	return_VALUE(count);
+}
+
+static ssize_t acpi_pcc_write_ac_brightness(struct file *file, const char __user *buffer,
+					 size_t count, loff_t *ppos)
+{
+	return acpi_pcc_write_brightness(file, buffer, count, SINF_AC_MIN_BRIGHT, 
+					 SINF_AC_MAX_BRIGHT, 
+					 SINF_AC_CUR_BRIGHT);
+}
+
+static ssize_t acpi_pcc_write_dc_brightness(struct file *file, const char __user *buffer,
+					 size_t count, loff_t *ppos)
+{
+	return acpi_pcc_write_brightness(file, buffer, count, SINF_DC_MIN_BRIGHT, 
+					 SINF_DC_MAX_BRIGHT, 
+					 SINF_DC_CUR_BRIGHT);
+}
+
+static int acpi_pcc_keyinput_show(struct seq_file *seq, void *offset)
+{
+	struct acpi_hotkey 	*hotkey = (struct acpi_hotkey *) seq->private;
+	struct input_dev 	*hotk_input_dev = hotkey->input_dev;
+	struct pcc_keyinput 	*keyinput = hotk_input_dev->private;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_keyinput_show");
+
+	seq_printf(seq, "%d\n", keyinput->key_mode);
+
+	return_VALUE(0);
+}
+
+static ssize_t acpi_pcc_write_keyinput(struct file *file, const char __user *buffer,
+					 size_t count, loff_t *ppos)
+{
+	struct seq_file		*seq = (struct seq_file *)file->private_data;
+	struct acpi_hotkey	*hotkey = (struct acpi_hotkey *)seq->private;
+	struct pcc_keyinput 	*keyinput;
+	char			write_string[8] = {'\0'};
+	int			key_mode;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_write_keyinput");
+
+	if (!hotkey || (count > sizeof(write_string) - 1))
+		return_VALUE(-EINVAL);
+
+	if (copy_from_user(write_string, buffer, count))
+		return_VALUE(-EFAULT);
+	
+	write_string[count] = '\0';
+
+	if (sscanf(write_string, "%i", &key_mode) == 1 && (key_mode == 0 || key_mode == 1)) {
+		keyinput = (struct pcc_keyinput *) hotkey->input_dev->private;
+		keyinput->key_mode = key_mode;
+	}
+
+	return_VALUE(count);
+}
+
+static int acpi_pcc_version_show(struct seq_file *seq, void *offset)
+{
+	struct acpi_hotkey *hotkey = (struct acpi_hotkey *) seq->private;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_version_show");
+
+	if (!hotkey || !hotkey->device)
+		return 0;
+
+	seq_printf(seq, "%s version %s\n", ACPI_PCC_DRIVER_NAME, ACPI_PCC_VERSION);
+	seq_printf(seq, "%li functions\n", hotkey->num_sifr);
+
+	return_VALUE(0);
+}
+
+/* oepn proc file fs*/
+static int acpi_pcc_dc_brightness_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_dc_brightness_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_numbatteries_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_numbatteries_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_lcdtype_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_lcdtype_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_ac_brightness_max_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_ac_max_brightness_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_ac_brightness_min_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_ac_min_brightness_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_ac_brightness_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_ac_brightness_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_dc_brightness_max_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_dc_max_brightness_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_dc_brightness_min_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_dc_min_brightness_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_mute_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_mute_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_version_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_version_show, PDE(inode)->data);
+}
+
+static int acpi_pcc_keyinput_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_pcc_keyinput_show, PDE(inode)->data);
+}
+
+/* --------------------------------------------------------------------------
+                            hotkey driver 
+   -------------------------------------------------------------------------- */
+
+static void pcc_acpi_generete_keyinput(struct acpi_hotkey *hotkey)
+{
+	struct input_dev *hotk_input_dev = hotkey->input_dev;
+	struct pcc_keyinput *keyinput = hotk_input_dev->private;
+	int hinf = hotkey->status;
+
+	if (keyinput->key_mode) {
+		switch (hinf & 0xf){
+		case 0x01:
+			input_report_key(hotk_input_dev, KEY_BRIGHTNESSDOWN,  hinf & 0x80);
+			break;
+		case 0x02:
+			input_report_key(hotk_input_dev, KEY_BRIGHTNESSUP,  hinf & 0x80);
+			break;
+		case 0x03:
+			/* vga/lcd switch event is not occur on hotkey driver. */
+			break;
+		case 0x04:
+			input_report_key(hotk_input_dev, KEY_MUTE,  hinf & 0x80);
+			break;
+		case 0x05:
+			input_report_key(hotk_input_dev, KEY_VOLUMEDOWN,  hinf & 0x80);
+			break;
+		case 0x06:
+			input_report_key(hotk_input_dev, KEY_VOLUMEUP,  hinf & 0x80);
+			break;
+		case 0x07:
+			input_report_key(hotk_input_dev, KEY_SLEEP,  hinf & 0x80);
+			break;
+		case 0x08:
+			/* do nothing */
+			break;
+		case 0x09:
+			input_report_key(hotk_input_dev, KEY_BATT,  hinf & 0x80);
+			break;
+		case 0x0a:
+			input_report_key(hotk_input_dev, KEY_SUSPEND,  hinf & 0x80);
+			break;
+		}
+		input_sync(hotk_input_dev);
+	}
+}
+
+static int acpi_pcc_hotkey_get_key(struct acpi_hotkey *hotkey)
+{
+	unsigned long result;
+	acpi_status status = AE_OK;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_get_key");
+
+	status = acpi_evaluate_integer(hotkey->handle,METHOD_HKEY_QUERY,NULL,&result);
+	if (likely(ACPI_SUCCESS(status))) {
+		hotkey->status = result;
+	} else {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "error getting hotkey status\n"));
+	}
+
+	return_VALUE(status == AE_OK);
+}
+
+void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data)
+{
+	struct acpi_hotkey *hotkey = (struct acpi_hotkey *) data;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify");
+
+	switch(event) {
+	case HKEY_NOTIFY:
+		if (acpi_pcc_hotkey_get_key(hotkey)) {
+			/* generate event like '"pcc HKEY 00000080 00000084"' when Fn+F4 pressed */
+			acpi_bus_generate_event(hotkey->device, event, hotkey->status);
+		}
+		pcc_acpi_generete_keyinput(hotkey);
+		break;
+	default:
+		/* nothing to do */
+		break;
+	}
+	return_VOID;
+}
+
+/* --------------------------------------------------------------------------
+                         proc init
+   -------------------------------------------------------------------------- */
+
+typedef struct _ProcItem
+{
+	const char* name;
+	struct file_operations *fops;
+	mode_t flag;
+} ProcItem;
+
+/* Note: These functions map *exactly* to the SINF/SSET functions */
+ProcItem pcc_proc_items[] =
+{
+	{ "keyinput",           &acpi_pcc_keyinput_fops,         S_IFREG | S_IRUGO | S_IWUSR },
+	{ "version",            &acpi_pcc_version_fops,          S_IRUGO },
+	{ "num_batteries",      &acpi_pcc_numbatteries_fops,     S_IRUGO },
+	{ "lcd_type",           &acpi_pcc_lcdtype_fops,          S_IRUGO },
+	{ "ac_brightness_max" , &acpi_pcc_ac_brightness_max_fops,S_IRUGO },
+	{ "ac_brightness_min" , &acpi_pcc_ac_brightness_min_fops,S_IRUGO },
+	{ "ac_brightness" ,     &acpi_pcc_ac_brightness_fops,    S_IFREG | S_IRUGO | S_IWUSR },
+	{ "dc_brightness_max" , &acpi_pcc_dc_brightness_max_fops,S_IRUGO },
+	{ "dc_brightness_min" , &acpi_pcc_dc_brightness_min_fops,S_IRUGO },
+	{ "dc_brightness" ,     &acpi_pcc_dc_brightness_fops,    S_IFREG | S_IRUGO | S_IWUSR }, 
+	{ "mute",               &acpi_pcc_mute_fops,             S_IFREG | S_IRUGO | S_IWUSR },
+	{ NULL, NULL, 0 },
+};
+
+static int __init add_device(ProcItem *proc_items, 
+			     struct acpi_device *device)
+{
+	struct proc_dir_entry* proc;
+	ProcItem* item;
+	int i;
+	struct acpi_hotkey *hotkey = (struct acpi_hotkey*)acpi_driver_data(device);
+
+	for (item = proc_items, i = 0; item->name && i < hotkey->num_sifr + 2; 
+	     ++item, ++i) {
+		proc = create_proc_entry(item->name, item->flag, hotkey->proc_dir_entry); 
+		if (likely(proc)) {
+			proc->proc_fops = item->fops;
+			proc->data = hotkey;
+			proc->owner = THIS_MODULE;
+		} else {
+			while (i-- > 0) {
+				item--;
+				remove_proc_entry(item->name, hotkey->proc_dir_entry);
+			}
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+static int __init acpi_pcc_proc_init(struct acpi_device *device)
+{
+	struct proc_dir_entry* acpi_pcc_dir;
+	struct acpi_hotkey *hotkey = (struct acpi_hotkey*)acpi_driver_data(device);
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_proc_init");
+
+	acpi_pcc_dir = proc_mkdir(PROC_PCC, acpi_root_dir);
+
+	if (unlikely(!acpi_pcc_dir)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't create dir in /proc\n"));
+		return_VALUE(-ENODEV);
+	}
+
+	acpi_pcc_dir->owner = THIS_MODULE;
+	hotkey->proc_dir_entry = acpi_pcc_dir;
+
+	status = add_device(pcc_proc_items, device);
+	if (unlikely(status)) {
+		remove_proc_entry(PROC_PCC, acpi_root_dir);
+		hotkey->proc_dir_entry = NULL;
+		return_VALUE(-ENODEV);
+	}
+
+	return_VALUE(status);
+}
+
+static void __exit remove_device(ProcItem *proc_items, 
+					struct acpi_device *device)
+{
+	struct acpi_hotkey *hotkey = (struct acpi_hotkey*)acpi_driver_data(device);
+	ProcItem* item;
+	int i;
+
+	for (item = proc_items, i = 0; item->name && i <= hotkey->num_sifr; ++item, ++i) {
+		remove_proc_entry(item->name, hotkey->proc_dir_entry);
+	}
+
+	return;
+}
+
+/* --------------------------------------------------------------------------
+                             input init
+   -------------------------------------------------------------------------- */
+static int hotk_input_open(struct input_dev *dev)
+{
+	return 0;
+}
+
+static void hotk_input_close(struct input_dev *dev)
+{
+}
+
+static int acpi_pcc_init_input(struct acpi_hotkey *hotkey)
+{
+	struct input_dev *hotk_input_dev;
+	struct pcc_keyinput *pcc_keyinput;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_init_input");
+
+	hotk_input_dev = kmalloc(sizeof(struct input_dev),GFP_KERNEL);
+
+	if (!hotk_input_dev) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate mem for hotkey"));
+		return_VALUE(-ENOMEM);
+	}
+
+	pcc_keyinput = kmalloc(sizeof(struct pcc_keyinput),GFP_KERNEL);
+
+	if (!pcc_keyinput) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate mem for hotkey"));
+		return_VALUE(-ENOMEM);
+	}
+
+	memset(hotk_input_dev, 0, sizeof(struct input_dev));
+	hotk_input_dev->open = hotk_input_open;
+	hotk_input_dev->close = hotk_input_close;
+  
+	hotk_input_dev->evbit[0] = BIT(EV_KEY);
+  
+	set_bit(KEY_BRIGHTNESSDOWN, hotk_input_dev->keybit);
+	set_bit(KEY_BRIGHTNESSUP, hotk_input_dev->keybit);
+	set_bit(KEY_MUTE, hotk_input_dev->keybit);
+	set_bit(KEY_VOLUMEDOWN, hotk_input_dev->keybit);
+	set_bit(KEY_VOLUMEUP, hotk_input_dev->keybit);
+	set_bit(KEY_SLEEP, hotk_input_dev->keybit);
+	set_bit(KEY_BATT, hotk_input_dev->keybit);
+	set_bit(KEY_SUSPEND, hotk_input_dev->keybit);
+ 
+	hotk_input_dev->name = ACPI_PCC_DRIVER_NAME;
+	hotk_input_dev->phys = ACPI_PCC_INPUT_PHYS;
+	hotk_input_dev->id.bustype = 0x1a; /* XXX FIXME: BUS_I8042? */
+	hotk_input_dev->id.vendor = 0x0001; 
+	hotk_input_dev->id.product = 0x0001;
+	hotk_input_dev->id.version = 0x0100;
+
+	pcc_keyinput->key_mode = 1; /* default on */
+	pcc_keyinput->hotkey = hotkey; 
+  
+	hotk_input_dev->private = pcc_keyinput;
+
+	hotkey->input_dev = hotk_input_dev;
+
+  
+	input_register_device(hotk_input_dev);
+
+	return_VALUE(0);
+}
+
+/* --------------------------------------------------------------------------
+                         module init
+   -------------------------------------------------------------------------- */
+
+static int acpi_pcc_hotkey_add (struct acpi_device *device)
+{
+	acpi_status		status = AE_OK;
+	struct acpi_hotkey	*hotkey = NULL;
+	int num_sifr, result;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add");
+
+	if (!device) {
+		return_VALUE(-EINVAL);
+	}
+
+	num_sifr = acpi_pcc_get_sqty(device);
+	
+	if (num_sifr > 255) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large"));
+		return_VALUE(-ENODEV);
+	}
+
+	hotkey = kmalloc(sizeof(struct acpi_hotkey), GFP_KERNEL);
+	if (!hotkey) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate mem for hotkey"));
+		return_VALUE(-ENOMEM);
+	}
+
+	memset(hotkey, 0, sizeof(struct acpi_hotkey));
+
+	hotkey->device = device;
+	hotkey->handle = device->handle;
+	hotkey->num_sifr = num_sifr;
+	acpi_driver_data(device) = hotkey;
+	strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
+	strcpy(acpi_device_class(device), ACPI_PCC_CLASS);
+
+	status = acpi_install_notify_handler (
+			hotkey->handle,
+			ACPI_DEVICE_NOTIFY,
+			acpi_pcc_hotkey_notify,
+			hotkey);
+
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error installing notify handler\n"));		
+		kfree(hotkey); 
+		return_VALUE(-ENODEV);
+	}
+
+	result = acpi_pcc_init_input(hotkey);
+	if (result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error installing keyinput handler\n"));		
+		kfree(hotkey); 
+		return_VALUE(result);
+	}
+
+	return_VALUE(acpi_pcc_proc_init(device));
+}
+
+static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
+{
+	acpi_status		status = AE_OK;
+	struct acpi_hotkey	*hotkey = acpi_driver_data(device);
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove");
+
+	if (!device || !hotkey)
+		return_VALUE(-EINVAL);
+
+	if (hotkey->proc_dir_entry) {
+		remove_device(pcc_proc_items, device);
+		remove_proc_entry(PROC_PCC, acpi_root_dir);
+	}
+
+	status = acpi_remove_notify_handler(hotkey->handle,
+		    ACPI_DEVICE_NOTIFY, acpi_pcc_hotkey_notify);
+
+	if (ACPI_FAILURE(status))
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error removing notify handler\n"));
+
+	kfree(hotkey);
+	return_VALUE(status == AE_OK);
+}
+
+static int __init acpi_pcc_init(void)
+{
+	int result = 0;
+ 
+	ACPI_FUNCTION_TRACE("acpi_pcc_init");
+
+	if (acpi_disabled) {
+		return_VALUE(-ENODEV);
+	}
+
+	result = acpi_bus_register_driver(&acpi_pcc_driver);
+	if (result < 0) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error registering hotkey driver\n"));
+		return_VALUE(-ENODEV);
+	}
+
+	return_VALUE(0);
+}
+
+static void __exit acpi_pcc_exit(void)
+{
+	ACPI_FUNCTION_TRACE("acpi_pcc_exit");
+
+	acpi_bus_unregister_driver(&acpi_pcc_driver); 
+
+	return_VOID;
+}
+
+module_init(acpi_pcc_init);
+module_exit(acpi_pcc_exit);

