mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Len Brown <lenb@kernel.org>
To: linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Harald Welte <laforge@gnumonks.org>, Len Brown <len.brown@intel.com>
Subject: [PATCH 41/85] panasonic-laptop: add Panasonic Let's Note laptop extras driver v0.94
Date: Sat, 11 Oct 2008 02:36:01 -0400	[thread overview]
Message-ID: <709ee531c153038d81b30649b9eeed3c44a4d5cc.1223706853.git.len.brown@intel.com> (raw)
In-Reply-To: <1223707005-26864-1-git-send-email-lenb@kernel.org>
In-Reply-To: <1d80ebdb81444701024ad9b9f026516561496a43.1223706853.git.len.brown@intel.com>

From: Harald Welte <laforge@gnumonks.org>

This is a driver for ACPI extras such as hotkeys and backlight
brightness control on various Panasonic "Let's Note" series laptop
computers.

It exports the backlight via the backlight class device API,
and the hotkeys as input event device.  Some more esoteric
items like number of installed batteries are exported via sysfs
device attributes.

Hotkey events also generate old-style ACPI enents through
/proc/acpi/event to interoperate with current versions of acpid.

Signed-off-by: Harald Welte <laforge@gnumonks.org>
Acked-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Acked-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
 MAINTAINERS                     |    5 +
 drivers/misc/Kconfig            |   11 +
 drivers/misc/Makefile           |    1 +
 drivers/misc/panasonic-laptop.c |  767 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 784 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/panasonic-laptop.c

diff --git a/MAINTAINERS b/MAINTAINERS
index cad81a2..fa35793 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3148,6 +3148,11 @@ M:	olof@lixom.net
 L:	i2c@lm-sensors.org
 S:	Maintained
 
+PANASONIC LAPTOP ACPI EXTRAS DRIVER
+P:	Harald Welte
+M:	laforge@gnumonks.org
+S:	Maintained
+
 PARALLEL PORT SUPPORT
 L:	linux-parport@lists.infradead.org (subscribers-only)
 S:	Orphan
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a726f3b..4ed8357 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -245,6 +245,17 @@ config MSI_LAPTOP
 
 	  If you have an MSI S270 laptop, say Y or M here.
 
+config PANASONIC_LAPTOP
+	tristate "Panasonic Laptop Extras"
+	depends on X86 && INPUT
+        depends on BACKLIGHT_CLASS_DEVICE
+	---help---
+	  This driver adds support for access to backlight control and hotkeys
+	  on Panasonic Let's Note laptops.
+
+	  If you have a Panasonic Let's note laptop (such as the R1(N variant),
+	  R2, R3, R5, T2, W2 and Y2 series), say Y.
+
 config COMPAL_LAPTOP
 	tristate "Compal Laptop Extras"
 	depends on X86
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c6c13f6..909e246 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_SGI_IOC4)		+= ioc4.o
 obj-$(CONFIG_SONY_LAPTOP)	+= sony-laptop.o
 obj-$(CONFIG_THINKPAD_ACPI)	+= thinkpad_acpi.o
 obj-$(CONFIG_FUJITSU_LAPTOP)	+= fujitsu-laptop.o
+obj-$(CONFIG_PANASONIC_LAPTOP)	+= panasonic-laptop.o
 obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
 obj-$(CONFIG_INTEL_MENLOW)	+= intel_menlow.o
 obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
diff --git a/drivers/misc/panasonic-laptop.c b/drivers/misc/panasonic-laptop.c
new file mode 100644
index 0000000..9aecda5
--- /dev/null
+++ b/drivers/misc/panasonic-laptop.c
@@ -0,0 +1,767 @@
+/*
+ *  Panasonic HotKey and LCD brightness control driver
+ *  (C) 2004 Hiroshi Miura <miura@da-cha.org>
+ *  (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
+ *  (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp>
+ *  (C) 2004 David Bronaugh <dbronaugh>
+ *  (C) 2006-2008 Harald Welte <laforge@gnumonks.org>
+ *
+ *  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.23, 2008	Harald Welte <laforge@gnumonks.org>
+ *		-v0.95	rename driver from drivers/acpi/pcc_acpi.c to
+ *			drivers/misc/panasonic-laptop.c
+ *
+ * 	Jul.04, 2008	Harald Welte <laforge@gnumonks.org>
+ * 		-v0.94	replace /proc interface with device attributes
+ * 			support {set,get}keycode on th input device
+ *
+ *      Jun.27, 2008	Harald Welte <laforge@gnumonks.org>
+ *      	-v0.92	merge with 2.6.26-rc6 input API changes
+ *      		remove broken <= 2.6.15 kernel support
+ *      		resolve all compiler warnings
+ *      		various coding style fixes (checkpatch.pl)
+ *      		add support for backlight api
+ *      		major code restructuring
+ *
+ * 	Dac.28, 2007	Harald Welte <laforge@gnumonks.org>
+ * 		-v0.91	merge with 2.6.24-rc6 ACPI changes
+ *
+ * 	Nov.04, 2006	Hiroshi Miura <miura@da-cha.org>
+ * 		-v0.9	remove warning about section reference.
+ * 			remove acpi_os_free
+ * 			add /proc/acpi/pcc/brightness interface for HAL access
+ * 			merge dbronaugh's enhancement
+ * 			Aug.17, 2004 David Bronaugh (dbronaugh)
+ *  				- Added screen brightness setting interface
+ *				  Thanks to FreeBSD crew (acpi_panasonic.c)
+ * 				  for the ideas I needed to accomplish it
+ *
+ *	May.29, 2006	Hiroshi Miura <miura@da-cha.org>
+ *		-v0.8.4 follow to change keyinput structure
+ *			thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>,
+ *			Jacob Bower <jacob.bower@ic.ac.uk> and
+ *			Hiroshi Yokota for providing solutions.
+ *
+ *	Oct.02, 2004	Hiroshi Miura <miura@da-cha.org>
+ *		-v0.8.2	merge code of YOKOTA Hiroshi
+ *					<yokota@netlab.is.tsukuba.ac.jp>.
+ *			Add sticky key mode interface.
+ *			Refactoring acpi_pcc_generate_keyinput().
+ *
+ *	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
+ *			facility 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
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/backlight.h>
+#include <linux/ctype.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/input.h>
+
+
+#ifndef ACPI_HOTKEY_COMPONENT
+#define ACPI_HOTKEY_COMPONENT	0x10000000
+#endif
+
+#define _COMPONENT		ACPI_HOTKEY_COMPONENT
+
+MODULE_AUTHOR("Hiroshi Miura, David Bronaugh and Harald Welte");
+MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops");
+MODULE_LICENSE("GPL");
+
+#define LOGPREFIX "pcc_acpi: "
+
+/* Define ACPI PATHs */
+/* Lets note hotkeys */
+#define METHOD_HKEY_QUERY	"HINF"
+#define METHOD_HKEY_SQTY	"SQTY"
+#define METHOD_HKEY_SINF	"SINF"
+#define METHOD_HKEY_SSET	"SSET"
+#define HKEY_NOTIFY		 0x80
+
+#define ACPI_PCC_DRIVER_NAME	"Panasonic Laptop Support"
+#define ACPI_PCC_DEVICE_NAME	"Hotkey"
+#define ACPI_PCC_CLASS		"pcc"
+
+#define ACPI_PCC_INPUT_PHYS	"panasonic/hkey0"
+
+/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
+   ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00
+*/
+enum SINF_BITS { SINF_NUM_BATTERIES = 0,
+		 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,
+		 SINF_STICKY_KEY = 0x80,
+	};
+/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
+
+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[] = {
+	{ "MAT0012", 0},
+	{ "MAT0013", 0},
+	{ "MAT0018", 0},
+	{ "MAT0019", 0},
+	{ "", 0},
+};
+
+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,
+				.resume =       acpi_pcc_hotkey_resume,
+			},
+};
+
+#define KEYMAP_SIZE		11
+static const int initial_keymap[KEYMAP_SIZE] = {
+	/*  0 */ KEY_RESERVED,
+	/*  1 */ KEY_BRIGHTNESSDOWN,
+	/*  2 */ KEY_BRIGHTNESSUP,
+	/*  3 */ KEY_DISPLAYTOGGLE,
+	/*  4 */ KEY_MUTE,
+	/*  5 */ KEY_VOLUMEDOWN,
+	/*  6 */ KEY_VOLUMEUP,
+	/*  7 */ KEY_SLEEP,
+	/*  8 */ KEY_PROG1, /* Change CPU boost */
+	/*  9 */ KEY_BATTERY,
+	/* 10 */ KEY_SUSPEND,
+};
+
+struct pcc_acpi {
+	acpi_handle		handle;
+	unsigned long		num_sifr;
+	int			sticky_mode;
+	u32 			*sinf;
+	struct acpi_device	*device;
+	struct input_dev	*input_dev;
+	struct backlight_device	*backlight;
+	int			keymap[KEYMAP_SIZE];
+};
+
+struct pcc_keyinput {
+	struct acpi_hotkey      *hotkey;
+};
+
+/* method access functions */
+static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
+{
+	union acpi_object in_objs[] = {
+		{ .integer.type  = ACPI_TYPE_INTEGER,
+		  .integer.value = func, },
+		{ .integer.type  = ACPI_TYPE_INTEGER,
+		  .integer.value = val, },
+	};
+	struct acpi_object_list params = {
+		.count   = ARRAY_SIZE(in_objs),
+		.pointer = in_objs,
+	};
+	acpi_status status = AE_OK;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_write_sset");
+
+	status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
+				      &params, NULL);
+
+	return 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 s;
+	else {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "evaluation error HKEY.SQTY\n"));
+		return -EINVAL;
+	}
+}
+
+static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
+{
+	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(pcc->handle, METHOD_HKEY_SINF, 0,
+				      &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "evaluation error HKEY.SINF\n"));
+		return 0;
+	}
+
+	hkey = buffer.pointer;
+	if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
+		goto end;
+	}
+
+	if (pcc->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:
+	kfree(buffer.pointer);
+	return status == AE_OK;
+}
+
+/* backlight API interface functions */
+
+/* This driver currently treats AC and DC brightness identical,
+ * since we don't need to invent an interface to the core ACPI
+ * logic to receive events in case a power supply is plugged in
+ * or removed */
+
+static int bl_get(struct backlight_device *bd)
+{
+	struct pcc_acpi *pcc = bl_get_data(bd);
+
+	if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+		return -EIO;
+
+	return pcc->sinf[SINF_AC_CUR_BRIGHT];
+}
+
+static int bl_set_status(struct backlight_device *bd)
+{
+	struct pcc_acpi *pcc = bl_get_data(bd);
+	int bright = bd->props.brightness;
+	int rc;
+
+	if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+		return -EIO;
+
+	if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
+		bright = pcc->sinf[SINF_AC_MIN_BRIGHT];
+
+	if (bright < pcc->sinf[SINF_DC_MIN_BRIGHT])
+		bright = pcc->sinf[SINF_DC_MIN_BRIGHT];
+
+	if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT] ||
+	    bright > pcc->sinf[SINF_AC_MAX_BRIGHT])
+		return -EINVAL;
+
+	rc = acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, bright);
+	if (rc < 0)
+		return rc;
+
+	return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright);
+}
+
+static struct backlight_ops pcc_backlight_ops = {
+	.get_brightness	= bl_get,
+	.update_status	= bl_set_status,
+};
+
+
+/* sysfs user interface functions */
+
+static ssize_t show_numbatt(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct acpi_device *acpi = to_acpi_device(dev);
+	struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+	if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+		return -EIO;
+
+	return sprintf(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
+}
+
+static ssize_t show_lcdtype(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct acpi_device *acpi = to_acpi_device(dev);
+	struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+	if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+		return -EIO;
+
+	return sprintf(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
+}
+
+static ssize_t show_mute(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct acpi_device *acpi = to_acpi_device(dev);
+	struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+	if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+		return -EIO;
+
+	return sprintf(buf, "%u\n", pcc->sinf[SINF_MUTE]);
+}
+
+static ssize_t show_sticky(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct acpi_device *acpi = to_acpi_device(dev);
+	struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+	if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+		return -EIO;
+
+	return sprintf(buf, "%u\n", pcc->sinf[SINF_STICKY_KEY]);
+}
+
+static ssize_t set_sticky(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct acpi_device *acpi = to_acpi_device(dev);
+	struct pcc_acpi *pcc = acpi_driver_data(acpi);
+	int val;
+
+	if (count && sscanf(buf, "%i", &val) == 1 &&
+	    (val == 0 || val == 1)) {
+		acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, val);
+		pcc->sticky_mode = val;
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(numbatt, S_IRUGO, show_numbatt, NULL);
+static DEVICE_ATTR(lcdtype, S_IRUGO, show_lcdtype, NULL);
+static DEVICE_ATTR(mute, S_IRUGO, show_mute, NULL);
+static DEVICE_ATTR(sticky_key, S_IRUGO | S_IWUSR, show_sticky, set_sticky);
+
+static struct attribute *pcc_sysfs_entries[] = {
+	&dev_attr_numbatt.attr,
+	&dev_attr_lcdtype.attr,
+	&dev_attr_mute.attr,
+	&dev_attr_sticky_key.attr,
+	NULL,
+};
+
+static struct attribute_group pcc_attr_group = {
+	.name	= NULL,		/* put in device directory */
+	.attrs	= pcc_sysfs_entries,
+};
+
+
+/* hotkey input device driver */
+
+static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+{
+	struct pcc_acpi *pcc = input_get_drvdata(dev);
+
+	if (scancode >= ARRAY_SIZE(pcc->keymap))
+		return -EINVAL;
+
+	*keycode = pcc->keymap[scancode];
+
+	return 0;
+}
+
+static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) {
+		if (pcc->keymap[i] == keycode)
+			return i+1;
+	}
+
+	return 0;
+}
+
+static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
+{
+	struct pcc_acpi *pcc = input_get_drvdata(dev);
+	int oldkeycode;
+
+	if (scancode >= ARRAY_SIZE(pcc->keymap))
+		return -EINVAL;
+
+	if (keycode < 0 || keycode > KEY_MAX)
+		return -EINVAL;
+
+	oldkeycode = pcc->keymap[scancode];
+	pcc->keymap[scancode] = keycode;
+
+	set_bit(keycode, dev->keybit);
+
+	if (!keymap_get_by_keycode(pcc, oldkeycode))
+		clear_bit(oldkeycode, dev->keybit);
+
+	return 0;
+}
+
+static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
+{
+	struct input_dev *hotk_input_dev = pcc->input_dev;
+	int rc;
+	int key_code, hkey_num;
+	unsigned long result;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_generate_keyinput");
+
+	rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
+				   NULL, &result);
+	if (!ACPI_SUCCESS(rc)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				 "error getting hotkey status\n"));
+		return;
+	}
+
+	acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
+
+	hkey_num = result & 0xf;
+
+	if (hkey_num < 0 || hkey_num > ARRAY_SIZE(pcc->keymap)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "hotkey number out of range: %d\n",
+				  hkey_num));
+		return;
+	}
+
+	key_code = pcc->keymap[hkey_num];
+
+	if (key_code != KEY_RESERVED) {
+		int pushed = (result & 0x80) ? TRUE : FALSE;
+
+		input_report_key(hotk_input_dev, key_code, pushed);
+		input_sync(hotk_input_dev);
+	}
+
+	return;
+}
+
+static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data)
+{
+	struct pcc_acpi *pcc = (struct pcc_acpi *) data;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify");
+
+	switch (event) {
+	case HKEY_NOTIFY:
+		acpi_pcc_generate_keyinput(pcc);
+		break;
+	default:
+		/* nothing to do */
+		break;
+	}
+}
+
+static int acpi_pcc_init_input(struct pcc_acpi *pcc)
+{
+	int i, rc;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_init_input");
+
+	pcc->input_dev = input_allocate_device();
+	if (!pcc->input_dev) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "Couldn't allocate input device for hotkey"));
+		return -ENOMEM;
+	}
+
+	pcc->input_dev->evbit[0] = BIT(EV_KEY);
+
+	pcc->input_dev->name = ACPI_PCC_DRIVER_NAME;
+	pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS;
+	pcc->input_dev->id.bustype = BUS_HOST;
+	pcc->input_dev->id.vendor = 0x0001;
+	pcc->input_dev->id.product = 0x0001;
+	pcc->input_dev->id.version = 0x0100;
+	pcc->input_dev->getkeycode = pcc_getkeycode;
+	pcc->input_dev->setkeycode = pcc_setkeycode;
+
+	/* load initial keymap */
+	memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap));
+
+	for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++)
+		__set_bit(pcc->keymap[i], pcc->input_dev->keybit);
+	__clear_bit(KEY_RESERVED, pcc->input_dev->keybit);
+
+	input_set_drvdata(pcc->input_dev, pcc);
+
+	rc = input_register_device(pcc->input_dev);
+	if (rc < 0)
+		input_free_device(pcc->input_dev);
+
+	return rc;
+}
+
+/* kernel module interface */
+
+static int acpi_pcc_hotkey_resume(struct acpi_device *device)
+{
+	struct pcc_acpi *pcc = acpi_driver_data(device);
+	acpi_status status = AE_OK;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume");
+
+	if (device == NULL || pcc == NULL)
+		return -EINVAL;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n",
+			  pcc->sticky_mode));
+
+	status = acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
+
+	return status == AE_OK ? 0 : -EINVAL;
+}
+
+static int acpi_pcc_hotkey_add(struct acpi_device *device)
+{
+	acpi_status status;
+	struct pcc_acpi *pcc;
+	int num_sifr, result;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add");
+
+	if (!device)
+		return -EINVAL;
+
+	num_sifr = acpi_pcc_get_sqty(device);
+
+	if (num_sifr > 255) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large"));
+		return -ENODEV;
+	}
+
+	pcc = kzalloc(sizeof(struct pcc_acpi), GFP_KERNEL);
+	if (!pcc) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "Couldn't allocate mem for pcc"));
+		return -ENOMEM;
+	}
+
+	pcc->sinf = kzalloc(sizeof(u32) * (num_sifr + 1), GFP_KERNEL);
+	if (!pcc->sinf) {
+		result = -ENOMEM;
+		goto out_hotkey;
+	}
+
+	pcc->device = device;
+	pcc->handle = device->handle;
+	pcc->num_sifr = num_sifr;
+	acpi_driver_data(device) = pcc;
+	strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
+	strcpy(acpi_device_class(device), ACPI_PCC_CLASS);
+
+	result = acpi_pcc_init_input(pcc);
+	if (result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "Error installing keyinput handler\n"));
+		goto out_sinf;
+	}
+
+	/* initialize hotkey input device */
+	status = acpi_install_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
+					     acpi_pcc_hotkey_notify, pcc);
+
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "Error installing notify handler\n"));
+		result = -ENODEV;
+		goto out_input;
+	}
+
+	/* initialize backlight */
+	pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
+						   &pcc_backlight_ops);
+	if (IS_ERR(pcc->backlight))
+		goto out_notify;
+
+	if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				 "Couldn't retrieve BIOS data\n"));
+		goto out_backlight;
+	}
+
+	/* read the initial brightness setting from the hardware */
+	pcc->backlight->props.max_brightness =
+					pcc->sinf[SINF_AC_MAX_BRIGHT];
+	pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
+
+	/* read the initial sticky key mode from the hardware */
+	pcc->sticky_mode = pcc->sinf[SINF_STICKY_KEY];
+
+	/* add sysfs attributes */
+	result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group);
+	if (result)
+		goto out_backlight;
+
+	return 0;
+
+out_backlight:
+	backlight_device_unregister(pcc->backlight);
+out_notify:
+	acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
+				   acpi_pcc_hotkey_notify);
+out_input:
+	input_unregister_device(pcc->input_dev);
+	/* no need to input_free_device() since core input API refcount and
+	 * free()s the device */
+out_sinf:
+	kfree(pcc->sinf);
+out_hotkey:
+	kfree(pcc);
+
+	return result;
+}
+
+static int __init acpi_pcc_init(void)
+{
+	int result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_init");
+
+	if (acpi_disabled)
+		return -ENODEV;
+
+	result = acpi_bus_register_driver(&acpi_pcc_driver);
+	if (result < 0) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "Error registering hotkey driver\n"));
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
+{
+	struct pcc_acpi *pcc = acpi_driver_data(device);
+
+	ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove");
+
+	if (!device || !pcc)
+		return -EINVAL;
+
+	sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
+
+	backlight_device_unregister(pcc->backlight);
+
+	acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
+				   acpi_pcc_hotkey_notify);
+
+	input_unregister_device(pcc->input_dev);
+	/* no need to input_free_device() since core input API refcount and
+	 * free()s the device */
+
+	kfree(pcc->sinf);
+	kfree(pcc);
+
+	return 0;
+}
+
+static void __exit acpi_pcc_exit(void)
+{
+	ACPI_FUNCTION_TRACE("acpi_pcc_exit");
+
+	acpi_bus_unregister_driver(&acpi_pcc_driver);
+}
+
+module_init(acpi_pcc_init);
+module_exit(acpi_pcc_exit);
-- 
1.5.5.1


  parent reply	other threads:[~2008-10-11  6:46 UTC|newest]

Thread overview: 111+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-10-11  6:35 ACPI patch queue for 2.6.28 Len Brown
2008-10-11  6:35 ` [PATCH 01/85] ACPI: Add missing acpi.debug_layer Documentation hunk from Thomas Renninger Len Brown
2008-10-11  6:35   ` [PATCH 02/85] acpi: replace AE_BAD_ADDRESS exception code with AE_ERROR Len Brown
2008-10-11  6:35   ` [PATCH 03/85] ACPI: Get the device power state in the course of scanning device Len Brown
2008-10-11  6:35   ` [PATCH 04/85] ACPI: Attach the ACPI device to the ACPI handle as early as possible Len Brown
2008-10-11  6:35   ` [PATCH 05/85] ACPI: Add "acpi.power_nocheck=1" to disable power state check in power transition Len Brown
2008-10-11  6:35   ` [PATCH 06/85] ACPI: Add DMI check " Len Brown
2008-10-11  6:35   ` [PATCH 07/85] ACPI : Load device driver according to the status of acpi device Len Brown
2008-10-11  6:35   ` [PATCH 08/85] ACPICA: Copy dynamically loaded tables to local buffer Len Brown
2008-10-11  6:35   ` [PATCH 09/85] ACPICA: Add check for invalid handle in acpi_get_object_info Len Brown
2008-10-11  6:35   ` [PATCH 10/85] ACPICA: Allow same ACPI table to be loaded/unloaded more than once Len Brown
2008-10-11  6:35   ` [PATCH 11/85] ACPICA: Fix wrong resource descriptor length for 64-bit build Len Brown
2008-10-11  6:35   ` [PATCH 12/85] ACPICA: Fix table compare code, length then data Len Brown
2008-10-11  6:35   ` [PATCH 13/85] ACPICA: Return status from global init function Len Brown
2008-10-11  6:35   ` [PATCH 14/85] ACPICA: Add function to dereference returned reference objects Len Brown
2008-10-11  6:35   ` [PATCH 15/85] ACPICA: Fix warning for 64-bit build Len Brown
2008-10-11  6:35   ` [PATCH 16/85] ACPICA: Cleanup macro definition file Len Brown
2008-10-11  6:35   ` [PATCH 17/85] ACPICA: Return method arg count from acpi_get_object_info Len Brown
2008-10-11  6:35   ` [PATCH 18/85] ACPICA: Update version to 20080701 Len Brown
2008-10-11  6:35   ` [PATCH 19/85] ACPICA: Add function to decode reference obj types to strings Len Brown
2008-10-11  6:35   ` [PATCH 20/85] ACPICA: Improve object conversion error messages Len Brown
2008-10-11  6:35   ` [PATCH 21/85] ACPICA: x2APIC support: changes for MADT and SRAT ACPI tables Len Brown
2008-10-11  6:35   ` [PATCH 22/85] ACPICA: Update version to 20080729 Len Brown
2008-10-11  6:35   ` [PATCH 23/85] ACPI: Clear WAK_STS on resume Len Brown
2008-10-13  9:01     ` Christian Borntraeger
2008-10-11  6:35   ` [PATCH 24/85] ACPI : Add the support for _TTS object Len Brown
2008-10-11  6:35   ` [PATCH 25/85] Introduce FW_BUG, FW_WARN and FW_INFO to consistenly tell users about BIOS bugs Len Brown
2008-10-11  6:35   ` [PATCH 26/85] ACPI: cpufreq, processor: Detect old BIOS, not supporting CPU freq on a recent CPU Len Brown
2008-10-11  6:35   ` [PATCH 27/85] CPUFREQ: powernow-k8: Try to detect old BIOS, not supporting CPU freq on a recent AMD CPUs Len Brown
2008-10-11  6:35   ` [PATCH 28/85] ACPI: dock: avoid check _STA method Len Brown
2008-10-11  6:35   ` [PATCH 29/85] dock: fix eject request process (2.6.27-rc1 regression) Len Brown
2008-10-11  6:35   ` [PATCH 30/85] dock: add _LCK support Len Brown
2008-10-11  6:35   ` [PATCH 31/85] dock: add bay and battery hotplug support Len Brown
2008-10-11  6:35   ` [PATCH 32/85] ACPI: introduce notifier change to avoid duplicates Len Brown
2008-10-11  6:35   ` [PATCH 33/85] ACPI: fix hotplug race Len Brown
2008-10-11  6:35   ` [PATCH 34/85] libata: remove functions now handed by ACPI dock driver Len Brown
2008-10-11  6:35   ` [PATCH 35/85] dock: introduce .uevent for devices in dock, eg libata Len Brown
2008-10-11  6:35   ` [PATCH 36/85] bay: remove driver, all functions now handled by dock driver Len Brown
2008-10-11  6:35   ` [PATCH 37/85] dock: fix for ATA bay in a dock station Len Brown
2008-10-11  6:35   ` [PATCH 38/85] dock: add 'type' sysfs file Len Brown
2008-10-11  6:35   ` [PATCH 39/85] dock: Shaohua Li is new maintainer Len Brown
2008-10-11  6:36   ` [PATCH 40/85] ACPI suspend: Always use the 32-bit waking vector Len Brown
2008-10-11  6:36   ` Len Brown [this message]
2008-10-11  6:36   ` [PATCH 42/85] ACPI: EC: do transaction from interrupt context Len Brown
2008-10-11  6:36   ` [PATCH 43/85] ACPI: EC: Rename some variables Len Brown
2008-10-11  6:36   ` [PATCH 44/85] ACPICA: add preemption point after each opcode parse Len Brown
2008-10-11  6:36   ` [PATCH 45/85] ACPI Suspend: Enable ACPI during resume if SCI_EN is not set Len Brown
2008-10-11  6:36   ` [PATCH 46/85] ACPI: don't enable control method power button as wakeup device when Fixed Power button is used Len Brown
2008-10-11  6:36   ` [PATCH 47/85] acer-wmi: Add rfkill support for wireless and bluetooth Len Brown
2008-10-11  6:36   ` [PATCH 48/85] acer-wmi: Remove wireless and bluetooth sysfs entries Len Brown
2008-10-11  6:36   ` [PATCH 49/85] ACPI: WMI: Enable event methods when registering notifiers Len Brown
2008-10-11  6:36   ` [PATCH 50/85] ACPI: Change acpi_evaluate_integer to support 64-bit on 32-bit kernels Len Brown
2008-10-11  6:36   ` [PATCH 51/85] ACPI: fix FADT parsing Len Brown
2008-10-11  6:36   ` [PATCH 52/85] fujitsu-laptop: better handling of P8010 hotkey Len Brown
2008-10-11  6:36   ` [PATCH 53/85] i7300_idle driver v1.55 Len Brown
2008-10-11  8:33     ` Ingo Molnar
2008-10-15 22:32       ` Len Brown
2008-10-16 22:05       ` [PATCH 1/2] x86: allow module driver to register idle notifier Len Brown
2008-10-21  1:57         ` Len Brown
2008-10-21 11:49           ` Ingo Molnar
2008-10-16 22:08       ` [PATCH 2/2] i7300_idle driver v1.55 Len Brown
2008-10-20 17:32         ` Randy Dunlap
2008-10-21 22:09           ` Pallipadi, Venkatesh
2008-10-21 22:15             ` Randy Dunlap
2008-10-21 23:02               ` Pallipadi, Venkatesh
2008-10-21 16:47         ` Andi Kleen
2008-10-21 22:34           ` Pallipadi, Venkatesh
2008-10-22  7:19             ` Andi Kleen
2008-10-22 23:34               ` [PATCH] Disable ioat channel only on platforms where ile driver can load Venki Pallipadi
2008-10-22 23:51                 ` [PATCH] Cleanup of i7300_idle based on review comments Venki Pallipadi
2008-10-24 17:03                   ` Len Brown
2008-10-24 17:02                 ` [PATCH] Disable ioat channel only on platforms where ile driver can load Len Brown
     [not found]                 ` <f12847240810270941v68a1cf7aqfa7db14fceb61fe5@mail.gmail.com>
2008-10-28 16:30                   ` Sosnowski, Maciej
2008-10-22 23:40               ` [PATCH 2/2] i7300_idle driver v1.55 Venki Pallipadi
2008-10-23  1:11                 ` Andi Kleen
2008-10-23  4:59                   ` Pallipadi, Venkatesh
2008-10-23 12:26                     ` Andi Kleen
2008-10-23 15:00                     ` Paul E. McKenney
2008-10-23 16:26                       ` Andi Kleen
2008-10-11  6:36   ` [PATCH 54/85] eeepc-laptop: Use standard interfaces Len Brown
2008-10-11  6:36   ` [PATCH 55/85] x86: remove magic number from ACPI sleep stack buffer Len Brown
2008-10-11  6:36   ` [PATCH 56/85] x86: trim " Len Brown
2008-10-11  6:36   ` [PATCH 57/85] ACPI: acpi_driver_data could only be applied to acpi_device Len Brown
2008-10-11  6:36   ` [PATCH 58/85] ACPI: toshiba_acpi.c fix sparse signedness mismatch warnings Len Brown
2008-10-11  6:36   ` [PATCH 59/85] ACPI: catch calls of acpi_driver_data on pointer of wrong type Len Brown
2008-10-11  6:36   ` [PATCH 60/85] toshiba_acpi: depends on INPUT Len Brown
2008-10-11  6:36   ` [PATCH 61/85] PNP: fix debug formatting (cosmetic) Len Brown
2008-10-11  6:36   ` [PATCH 62/85] PNPACPI: use dev_printk when possible Len Brown
2008-10-11  6:36   ` [PATCH 63/85] PNP: convert the last few pnp_info() uses to printk() Len Brown
2008-10-11  6:36   ` [PATCH 64/85] PNP: use new vsprintf symbolic function pointer format Len Brown
2008-10-11  6:36   ` [PATCH 65/85] PNP: remove some uses of DEBUG ifdef Len Brown
2008-10-11  6:36   ` [PATCH 66/85] PNP: add CONFIG_PNP_DEBUG_MESSAGES and pnp_dbg() Len Brown
2008-10-11  6:36   ` [PATCH 67/85] PNP: convert to using pnp_dbg() Len Brown
2008-10-11  6:36   ` [PATCH 68/85] PNP: remove old CONFIG_PNP_DEBUG option Len Brown
2008-10-11  6:36   ` [PATCH 69/85] ACPI: don't load acpi_cpufreq if acpi=off Len Brown
2008-10-11  6:36   ` [PATCH 70/85] ACPI: remove unused have_arch_parse_srat Len Brown
2008-10-11  6:36   ` [PATCH 71/85] acer-wmi: Remove private workqueue Len Brown
2008-10-11  6:36   ` [PATCH 72/85] Subject: ACPI dock: Use ACPI_EXCEPTION instead of printk(KERN_ERR Len Brown
2008-10-11  6:36   ` [PATCH 73/85] ACPI cm_sbs: Debug interface used for error message cleanup Len Brown
2008-10-11  6:36   ` [PATCH 74/85] ACPI memhotplug: " Len Brown
2008-10-11  6:36   ` [PATCH 75/85] ACPI processor: " Len Brown
2008-10-11  6:36   ` [PATCH 76/85] ACPI video: " Len Brown
2008-10-11  6:36   ` [PATCH 77/85] ACPI scan: " Len Brown
2008-10-11  6:36   ` [PATCH 78/85] ACPI fan: " Len Brown
2008-10-11  6:36   ` [PATCH 79/85] ACPI osl: " Len Brown
2008-10-11  6:36   ` [PATCH 80/85] ACPI thermal: " Len Brown
2008-10-11  6:36   ` [PATCH 81/85] ACPI system: " Len Brown
2008-10-11  6:36   ` [PATCH 82/85] ACPI: remove unused acpi_is_child_device() Len Brown
2008-10-11  6:36   ` [PATCH 83/85] ACPI: Enable EC device immediately after ACPI full initialization Len Brown
2008-10-11  6:36   ` [PATCH 84/85] delete drivers/acpi/bay.c Len Brown
2008-10-11  6:36   ` [PATCH 85/85] panasonic-laptop: fix build Len Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=709ee531c153038d81b30649b9eeed3c44a4d5cc.1223706853.git.len.brown@intel.com \
    --to=lenb@kernel.org \
    --cc=laforge@gnumonks.org \
    --cc=len.brown@intel.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®