Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2d86100 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Staging: pcc-acpi: update to latest version



Import the changes from the upstream driver into this version to keep
things up to date.

Cc: Yokota Hiroshi <yokota@netlab.cs.tsukuba.ac.jp>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent bc36e655
Loading
Loading
Loading
Loading
+309 −231
Original line number Diff line number Diff line
@@ -94,20 +94,21 @@
 *
 */

#define ACPI_PCC_VERSION	"0.9"
#define ACPI_PCC_VERSION	"0.9+hy"

#include <linux/version.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <asm/uaccess.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/input.h>
#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>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/version.h>


/*************************************************************************
@@ -152,10 +153,10 @@ static int _open_func_name_(struct inode *inode, struct file *file) \
#endif

#define _COMPONENT		ACPI_HOTKEY_COMPONENT
ACPI_MODULE_NAME("pcc_acpi")
ACPI_MODULE_NAME("pcc_acpi");

MODULE_AUTHOR("Hiroshi Miura");
MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Lets Note laptops");
MODULE_AUTHOR("Hiroshi Miura, Hiroshi Yokota");
MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops");
MODULE_LICENSE("GPL");

#define LOGPREFIX "pcc_acpi: "
@@ -182,7 +183,7 @@ MODULE_LICENSE("GPL");
 * definitions for /proc/ interface
 *
 *******************************************************************/
#define ACPI_PCC_DRIVER_NAME	"PCC Extra Driver"
#define ACPI_PCC_DRIVER_NAME	"pcc_acpi"
#define ACPI_PCC_DEVICE_NAME	"PCCExtra"
#define ACPI_PCC_CLASS		"pcc"
#define PROC_PCC		ACPI_PCC_CLASS
@@ -196,6 +197,12 @@ MODULE_LICENSE("GPL");

#define PROC_STR_MAX_LEN  8

#define BUS_PCC_HOTKEY BUS_I8042 /*0x1a*/ /* FIXME: BUS_I8042? */

/* Fn+F4/F5 confricts with Shift+F1/F2  */
/* This hack avoids key number confrict */
#define PCC_KEYINPUT_MODE (0)

/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
   ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00
*/
@@ -209,11 +216,7 @@ enum SINF_BITS { SINF_NUM_BATTERIES = 0,
		 SINF_STICKY_KEY = 0x80,
};

static int acpi_pcc_hotkey_add(struct acpi_device *device);
static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type);
static int acpi_pcc_hotkey_resume(struct acpi_device *device);

static const struct acpi_device_id pcc_device_ids[] = {
static struct acpi_device_id pcc_device_ids[] = {
	{"MAT0012", 0},
	{"MAT0013", 0},
	{"MAT0018", 0},
@@ -222,14 +225,23 @@ static const struct acpi_device_id pcc_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, pcc_device_ids);


static int __devinit acpi_pcc_hotkey_add(struct acpi_device *device);
static int __devexit acpi_pcc_hotkey_remove(struct acpi_device *device, int type);
static int acpi_pcc_hotkey_resume(struct acpi_device *device);


static struct acpi_driver acpi_pcc_driver = {
	.name =		ACPI_PCC_DRIVER_NAME,
	.class =	ACPI_PCC_CLASS,
	.ids =		pcc_device_ids,
	.ops =		{
				.add =		acpi_pcc_hotkey_add,
				.remove =	acpi_pcc_hotkey_remove,
				.remove =	__devexit_p(acpi_pcc_hotkey_remove),
#ifdef CONFIG_PM
				/*.suspend =      acpi_pcc_hotkey_suspend,*/
				.resume =       acpi_pcc_hotkey_resume,
#endif
			},
};

@@ -248,9 +260,12 @@ struct pcc_keyinput {
	int key_mode;
};

/* --------------------------------------------------------------------------
/* *************************************************************************
   Hotkey driver core
   ************************************************************************* */
/* -------------------------------------------------------------------------
                           method access functions
   -------------------------------------------------------------------------- */
   ------------------------------------------------------------------------- */
static int acpi_pcc_write_sset(struct acpi_hotkey *hotkey, int func, int val)
{
	union acpi_object in_objs[] = {
@@ -263,13 +278,13 @@ static int acpi_pcc_write_sset(struct acpi_hotkey *hotkey, int func, int val)
		.count   = ARRAY_SIZE(in_objs),
		.pointer = in_objs,
	};
	acpi_status status = AE_OK;
	acpi_status status;

	ACPI_FUNCTION_TRACE("acpi_pcc_write_sset");

	status = acpi_evaluate_object(hotkey->handle, METHOD_HKEY_SSET, &params, NULL);

	return_VALUE(status == AE_OK);
	return_VALUE(status == AE_OK ? AE_OK : AE_ERROR);
}

static inline int acpi_pcc_get_sqty(struct acpi_device *device)
@@ -301,19 +316,20 @@ static int acpi_pcc_retrieve_biosdata(struct acpi_hotkey *hotkey, u32* sinf)
	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);
		status = AE_ERROR;
		return_VALUE(status);
	}

	hkey = buffer.pointer;
	if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
		goto end;
		goto free_buffer;
	}

	if (hotkey->num_sifr < hkey->package.count) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "SQTY reports bad SINF length\n"));
		status = AE_ERROR;
		goto end;
		goto free_buffer;
	}

	for (i = 0; i < hkey->package.count; i++) {
@@ -322,47 +338,42 @@ static int acpi_pcc_retrieve_biosdata(struct acpi_hotkey *hotkey, u32* sinf)
			sinf[i] = element->integer.value;
		} else {
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF data\n"));
			status = AE_ERROR;
			break;
		}
	}
	sinf[hkey->package.count] = -1;

end:
 free_buffer:
	kfree(buffer.pointer);
	return_VALUE(status == AE_OK);
	return_VALUE(status == AE_OK ? AE_OK : AE_ERROR);
}

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);
	u32 sinf[hotkey->num_sifr + 1];

	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(hotkey, sinf)) {
	if (ACPI_SUCCESS(acpi_pcc_retrieve_biosdata(hotkey, sinf))) {
		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);
	return_VALUE(AE_OK);
}

/* --------------------------------------------------------------------------
/* -------------------------------------------------------------------------
                       user interface functions
   -------------------------------------------------------------------------- */
   ------------------------------------------------------------------------- */
/* read methods */
/* Sinf read methods */
#define PCC_SINF_READ_F(_name_, FUNC) \
static int _name_  (struct seq_file *seq, void *offset) \
{ \
	return acpi_pcc_read_sinf_field(seq, (FUNC)); \
	return_VALUE(ACPI_SUCCESS(acpi_pcc_read_sinf_field(seq, (FUNC)))  ? 0 : -EINVAL); \
}

PCC_SINF_READ_F(acpi_pcc_numbatteries_show,	 SINF_NUM_BATTERIES);
@@ -383,7 +394,7 @@ static int acpi_pcc_sticky_key_show(struct seq_file *seq, void *offset)
	ACPI_FUNCTION_TRACE("acpi_pcc_sticky_key_show");

	if (!hotkey || !hotkey->device) {
		return_VALUE(0);
		return_VALUE(-EINVAL);
	}

	seq_printf(seq, "%d\n", hotkey->sticky_mode);
@@ -410,8 +421,9 @@ static int acpi_pcc_version_show(struct seq_file *seq, void *offset)

	ACPI_FUNCTION_TRACE("acpi_pcc_version_show");

	if (!hotkey || !hotkey->device)
		return 0;
	if (!hotkey || !hotkey->device) {
		return_VALUE(-EINVAL);
	}

	seq_printf(seq, "%s version %s\n", ACPI_PCC_DRIVER_NAME, ACPI_PCC_VERSION);
	seq_printf(seq, "%li functions\n", hotkey->num_sifr);
@@ -441,7 +453,8 @@ static ssize_t acpi_pcc_write_single_flag (struct file *file,
	}
	write_string[count] = '\0';

	if (sscanf(write_string, "%i", &val) == 1 && (val == 0 || val == 1)) {
	if ((sscanf(write_string, "%3i", &val) == 1) &&
	    (val == 0 || val == 1)) {
		acpi_pcc_write_sset(hotkey, sinf_func, val);
	}

@@ -457,53 +470,51 @@ static unsigned long acpi_pcc_write_brightness(struct file *file, const char __u
	struct acpi_hotkey	*hotkey = (struct acpi_hotkey *)seq->private;
	char			write_string[PROC_STR_MAX_LEN];
	u32 bright;
	u32* sinf = kmalloc(sizeof(u32) * (hotkey->num_sifr + 1), GFP_KERNEL);
	u32 sinf[hotkey->num_sifr + 1];

	ACPI_FUNCTION_TRACE("acpi_pcc_write_brightness");

	if (!hotkey || (count > sizeof(write_string) - 1))
	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))
	if (copy_from_user(write_string, buffer, count)) {
		return_VALUE(-EFAULT);
	}

	write_string[count] = '\0';

	if (!acpi_pcc_retrieve_biosdata(hotkey, sinf)) {
	if (ACPI_FAILURE(acpi_pcc_retrieve_biosdata(hotkey, sinf))) {
		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]) {
	if ((sscanf(write_string, "%4i", &bright) == 1) &&
	    (bright >= sinf[min_index]                ) &&
	    (bright <= sinf[max_index]                )) {
		acpi_pcc_write_sset(hotkey, cur_index, bright);
	}

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,
	return_VALUE(acpi_pcc_write_brightness(file, buffer, count,
					       SINF_AC_MIN_BRIGHT,
					       SINF_AC_MAX_BRIGHT,
					 SINF_AC_CUR_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,
	return_VALUE(acpi_pcc_write_brightness(file, buffer, count,
					       SINF_DC_MIN_BRIGHT,
					       SINF_DC_MAX_BRIGHT,
					 SINF_DC_CUR_BRIGHT);
					       SINF_DC_CUR_BRIGHT));
}

static ssize_t acpi_pcc_write_no_brightness(struct file *file, const char __user *buffer,
@@ -518,14 +529,36 @@ static ssize_t acpi_pcc_write_mute (struct file *file,
				    const char __user *buffer,
				    size_t count, loff_t *ppos)
{
	return acpi_pcc_write_single_flag(file, buffer, count, SINF_MUTE);
	return_VALUE(acpi_pcc_write_single_flag(file, buffer, count, SINF_MUTE));
}

static ssize_t acpi_pcc_write_sticky_key (struct file *file,
					  const char __user *buffer,
					  size_t count, loff_t *ppos)
{
	return acpi_pcc_write_single_flag(file, buffer, count, SINF_STICKY_KEY);
	struct seq_file     *seq = (struct seq_file *)file->private_data;
	struct acpi_hotkey  *hotkey = (struct acpi_hotkey *)seq->private;
	char                 write_string[PROC_STR_MAX_LEN];
	int                  mode;

	ACPI_FUNCTION_TRACE("acpi_pcc_write_sticky_key");

	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, "%3i", &mode) == 1) &&
	    (mode == 0 || mode == 1)) {
		acpi_pcc_write_sset(hotkey, SINF_STICKY_KEY, mode);
		hotkey->sticky_mode = mode;
	}

	return_VALUE(count);
}

static ssize_t acpi_pcc_write_keyinput(struct file *file, const char __user *buffer,
@@ -539,25 +572,28 @@ static ssize_t acpi_pcc_write_keyinput(struct file *file, const char __user *buf

	ACPI_FUNCTION_TRACE("acpi_pcc_write_keyinput");

	if (!hotkey || (count > sizeof(write_string) - 1))
	if (!hotkey || (count > (sizeof(write_string) - 1))) {
		return_VALUE(-EINVAL);
	}

	if (copy_from_user(write_string, buffer, count))
	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 *)input_get_drvdata(hotkey->input_dev);
	if ((sscanf(write_string, "%4i", &key_mode) == 1) &&
	    (key_mode == 0 || key_mode == 1)) {
		keyinput = input_get_drvdata(hotkey->input_dev);
		keyinput->key_mode = key_mode;
	}

	return_VALUE(count);
}

/* --------------------------------------------------------------------------
/* -------------------------------------------------------------------------
                            hotkey driver
   -------------------------------------------------------------------------- */
   ------------------------------------------------------------------------- */
static void acpi_pcc_generete_keyinput(struct acpi_hotkey *hotkey)
{
	struct input_dev    *hotk_input_dev = hotkey->input_dev;
@@ -640,9 +676,9 @@ void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data)
	return_VOID;
}

/* --------------------------------------------------------------------------
/* *************************************************************************
   FS Interface (/proc)
   -------------------------------------------------------------------------- */
   ************************************************************************* */
/* oepn proc file fs*/
SEQ_OPEN_FS(acpi_pcc_dc_brightness_open_fs,	acpi_pcc_dc_brightness_show);
SEQ_OPEN_FS(acpi_pcc_numbatteries_open_fs,	acpi_pcc_numbatteries_show);
@@ -681,8 +717,7 @@ typedef struct _ProcItem
} ProcItem;

/* Note: These functions map *exactly* to the SINF/SSET functions */
ProcItem pcc_proc_items_sifr[] =
{
ProcItem acpi_pcc_proc_items_sifr[] = {
	{ "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 },
@@ -696,22 +731,21 @@ ProcItem pcc_proc_items_sifr[] =
	{ NULL, NULL, 0 },
};

ProcItem pcc_proc_items[] =
{
ProcItem acpi_pcc_proc_items[] = {
	{ "sticky_key",		&acpi_pcc_sticky_key_fops,	 S_IFREG | S_IRUGO | S_IWUSR },
	{ "keyinput",		&acpi_pcc_keyinput_fops,	 S_IFREG | S_IRUGO | S_IWUSR },
	{ "version",		&acpi_pcc_version_fops,		 S_IRUGO },
	{ NULL, NULL, 0 },
};

static int acpi_pcc_add_device(struct acpi_device *device,
static int __devinit acpi_pcc_add_device(struct acpi_device *device,
					 ProcItem *proc_items,
					 int num)
{
	struct acpi_hotkey *hotkey = (struct acpi_hotkey*)acpi_driver_data(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 < num; ++item, ++i) {
		proc = create_proc_entry(item->name, item->flag, hotkey->proc_dir_entry);
@@ -724,13 +758,13 @@ static int acpi_pcc_add_device(struct acpi_device *device,
				item--;
				remove_proc_entry(item->name, hotkey->proc_dir_entry);
			}
			return -ENODEV;
			return_VALUE(-ENODEV);
		}
	}
	return 0;
	return_VALUE(0);
}

static int acpi_pcc_proc_init(struct acpi_device *device)
static int __devinit 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);
@@ -748,8 +782,8 @@ static int acpi_pcc_proc_init(struct acpi_device *device)
	acpi_pcc_dir->owner = THIS_MODULE;
	hotkey->proc_dir_entry = acpi_pcc_dir;

	status =  acpi_pcc_add_device(device, pcc_proc_items_sifr, hotkey->num_sifr);
	status |= acpi_pcc_add_device(device, pcc_proc_items, sizeof(pcc_proc_items)/sizeof(ProcItem));
	status =  acpi_pcc_add_device(device, acpi_pcc_proc_items_sifr, hotkey->num_sifr);
	status |= acpi_pcc_add_device(device, acpi_pcc_proc_items,      ARRAY_SIZE(acpi_pcc_proc_items));
	if (unlikely(status)) {
		remove_proc_entry(PROC_PCC, acpi_root_dir);
		hotkey->proc_dir_entry = NULL;
@@ -759,7 +793,7 @@ static int acpi_pcc_proc_init(struct acpi_device *device)
	return_VALUE(status);
}

static void acpi_pcc_remove_device(struct acpi_device *device,
static void __devexit acpi_pcc_remove_device(struct acpi_device *device,
					     ProcItem *proc_items,
					     int num)
{
@@ -771,39 +805,58 @@ static void acpi_pcc_remove_device(struct acpi_device *device,
		remove_proc_entry(item->name, hotkey->proc_dir_entry);
	}

	return;
	return_VOID;
}

/* *************************************************************************
   Power Management
   ************************************************************************* */
#ifdef CONFIG_PM
static int acpi_pcc_hotkey_resume(struct acpi_device *device)
{
	struct acpi_hotkey *hotkey = acpi_driver_data(device);
	acpi_status	    status = AE_OK;

	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume");

	if (device == NULL || hotkey == NULL) { return_VALUE(-EINVAL); }

	if (hotkey->num_sifr != 0) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Sticky mode restore: %d\n", hotkey->sticky_mode));

		status = acpi_pcc_write_sset(hotkey, SINF_STICKY_KEY, hotkey->sticky_mode);
	}
	if (status != AE_OK) { return_VALUE(-EINVAL); }

	return_VALUE(0);
}
#endif

/* --------------------------------------------------------------------------
                             input init
   -------------------------------------------------------------------------- */
static int acpi_pcc_init_input(struct acpi_hotkey *hotkey)
/* *************************************************************************
   Module init/remove
   ************************************************************************* */
/* -------------------------------------------------------------------------
   input
   ------------------------------------------------------------------------- */
static int __devinit acpi_pcc_init_input(struct acpi_hotkey *hotkey)
{
	struct input_dev    *hotk_input_dev;
	struct pcc_keyinput *pcc_keyinput;
	int error;

	ACPI_FUNCTION_TRACE("acpi_pcc_init_input");

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
	hotk_input_dev = input_allocate_device();
	if (!hotk_input_dev) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate input device for hotkey"));
		return_VALUE(-ENOMEM);
	}
#else
	hotk_input_dev = kcalloc(1, sizeof(struct input_dev),GFP_KERNEL);
	if (hotk_input_dev == NULL) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate mem for hotkey"));
		return_VALUE(-ENOMEM);
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate input device for hotkey"));
		goto err_input;
	}
#endif

	pcc_keyinput = kcalloc(1, sizeof(struct pcc_keyinput), GFP_KERNEL);

	if (pcc_keyinput == NULL) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate mem for hotkey"));
		input_unregister_device(hotk_input_dev);
		return_VALUE(-ENOMEM);
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate mem for private data"));
		goto err_pcc;
	}

	hotk_input_dev->evbit[0] = BIT(EV_KEY);
@@ -819,71 +872,87 @@ static int acpi_pcc_init_input(struct acpi_hotkey *hotkey)

	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.bustype = BUS_PCC_HOTKEY;
	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->key_mode = PCC_KEYINPUT_MODE;
	pcc_keyinput->hotkey   = hotkey;

	input_set_drvdata(hotk_input_dev, pcc_keyinput);

	hotkey->input_dev = hotk_input_dev;

	error = input_register_device(hotk_input_dev);

	input_register_device(hotk_input_dev);
	if (error) {
		goto err_pcc;
	}

	return_VALUE(0);
}

/* --------------------------------------------------------------------------
                         module init
   -------------------------------------------------------------------------- */
 err_pcc:
	input_unregister_device(hotk_input_dev);
 err_input:
	return_VALUE(-ENOMEM);
}

static int acpi_pcc_hotkey_resume(struct acpi_device *device)
static void __devexit acpi_pcc_remove_input(struct acpi_hotkey *hotkey)
{
	struct acpi_hotkey *hotkey = acpi_driver_data(device);
	acpi_status	    status = AE_OK;
	struct input_dev    *hotk_input_dev;
	struct pcc_keyinput *pcc_keyinput;

	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume");
	ACPI_FUNCTION_TRACE("acpi_pcc_remove_input");

	if (device == NULL || hotkey == NULL) { return_VALUE(-EINVAL); }
	if (hotkey == NULL) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Can't free memory"));
		return_VOID;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n", hotkey->sticky_mode));
	hotk_input_dev = hotkey->input_dev;
	pcc_keyinput   = input_get_drvdata(hotk_input_dev);

	status = acpi_pcc_write_sset(hotkey, SINF_STICKY_KEY, hotkey->sticky_mode);
	input_unregister_device(hotk_input_dev);

	return_VALUE(status == AE_OK ? 0 : -EINVAL);
	kfree(pcc_keyinput);
}

static int acpi_pcc_hotkey_add (struct acpi_device *device)
/* -------------------------------------------------------------------------
   ACPI
   ------------------------------------------------------------------------- */
static int __devinit acpi_pcc_hotkey_add (struct acpi_device *device)
{
	acpi_status		status = AE_OK;
	struct acpi_hotkey	*hotkey = NULL;
	int num_sifr, result;
	int sifr_status, num_sifr, result;

	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add");

	if (!device) {
	if (device == NULL) {
		return_VALUE(-EINVAL);
	}

	num_sifr = acpi_pcc_get_sqty(device);
	sifr_status = acpi_pcc_get_sqty(device);

	if (num_sifr > 255) {
	if (sifr_status > 255) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large"));
		return_VALUE(-ENODEV);
	}

	hotkey = kmalloc(sizeof(struct acpi_hotkey), GFP_KERNEL);
	if (!hotkey) {
	if (sifr_status < 0) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "not support SQTY"));
		num_sifr = 0;
	} else {
		num_sifr = sifr_status;
	}

	hotkey = kcalloc(1, sizeof(struct acpi_hotkey), GFP_KERNEL);
	if (hotkey == NULL) {
		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;
@@ -891,8 +960,7 @@ static int acpi_pcc_hotkey_add (struct acpi_device *device)
	strcpy(acpi_device_name(device),  ACPI_PCC_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_PCC_CLASS);

	status = acpi_install_notify_handler (
			hotkey->handle,
	status = acpi_install_notify_handler(hotkey->handle,
					     ACPI_DEVICE_NOTIFY,
					     acpi_pcc_hotkey_notify,
					     hotkey);
@@ -904,7 +972,7 @@ static int acpi_pcc_hotkey_add (struct acpi_device *device)
	}

	result = acpi_pcc_init_input(hotkey);
	if (result) {
	if (result != 0) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error installing keyinput handler\n"));
		kfree(hotkey);
		return_VALUE(result);
@@ -913,62 +981,72 @@ static int acpi_pcc_hotkey_add (struct acpi_device *device)
	return_VALUE(acpi_pcc_proc_init(device));
}

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);
}

module_init(acpi_pcc_init);

static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
static int __devexit 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)
	if (!device || !hotkey) {
		return_VALUE(-EINVAL);
	}

	if (hotkey->proc_dir_entry) {
		acpi_pcc_remove_device(device, pcc_proc_items_sifr, hotkey->num_sifr);
		acpi_pcc_remove_device(device, pcc_proc_items, sizeof(pcc_proc_items)/sizeof(ProcItem));
		acpi_pcc_remove_device(device, acpi_pcc_proc_items_sifr, hotkey->num_sifr);
		acpi_pcc_remove_device(device, acpi_pcc_proc_items,      ARRAY_SIZE(acpi_pcc_proc_items));
		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))
	if (ACPI_FAILURE(status)) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error removing notify handler\n"));
	}

	input_unregister_device(hotkey->input_dev);

	acpi_pcc_remove_input(hotkey);
	if (hotkey != NULL) {
		kfree(hotkey);
	}
	return_VALUE(status == AE_OK);
}

/* *********************************************************************
   Module entry point
   ********************************************************************* */
static int __init acpi_pcc_init(void)
{
	int result;

	ACPI_FUNCTION_TRACE("acpi_pcc_init");

	printk(KERN_INFO LOGPREFIX "loading...\n");

	if (acpi_disabled) {
		printk(KERN_INFO LOGPREFIX "ACPI disabled.\n");
		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(result);
}

static void __exit acpi_pcc_exit(void)
{
	ACPI_FUNCTION_TRACE("acpi_pcc_exit");

	printk(KERN_INFO LOGPREFIX "unloading...\n");

	acpi_bus_unregister_driver(&acpi_pcc_driver);

	return_VOID;
}

module_init(acpi_pcc_init);
module_exit(acpi_pcc_exit);