* [PATCH][ACPI] Panasonic Hotkey Driver
@ 2004-07-31 14:17 Hiroshi Miura
2004-08-18 5:04 ` Len Brown
0 siblings, 1 reply; 6+ messages in thread
From: Hiroshi Miura @ 2004-07-31 14:17 UTC (permalink / raw)
To: Len Brown; +Cc: linux-kernel, acpi-devel, letsnote-tech
Hi,
This is a hotkey driver for Panasonic Lets note series.
I tested this driver on 2.6.7 kernel and Panasonic CF-R3 laptop.
Using this driver, users can handle Fn+Fx key (except for Fn+F3) with acpid.
The event is for example 'HKEY HKEY 00000080 0000001' for Fn+F1.
sample scripts as follows
# /etc/acpi/events/hotkey
event=HKEY.*
action=/etc/acpi/hotkey.sh "%e"
hotkey.sh is
#!/bin/sh
set $*
# Take care about the way events are reported
key="$4";
case "$key" in
0000000a)
logger "acpid: received a suspend request"
echo 1 > /proc/swsusp/activate
hwclock --hctosys
break
;;
*)
logger "acpid: action $key is not defined"
;;
esac
patch is follows
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
# 2004/07/26 11:50:39+09:00 miura@da-cha.org
# Panasonic Laptop Extra driver.
# This adds support of hotkey (Fn+Fx) on Panasonic Lets note Laptop series.
# Loding this driver, user can get event through acpid like "HKEY HKEY 0000080 000001"
#
# Signed-off-by: Hiroshi Miura <miura@da-cha.org>
#
# drivers/acpi/pcc_acpi.c
# 2004/07/26 11:50:23+09:00 miura@da-cha.org +518 -0
#
# drivers/acpi/pcc_acpi.c
# 2004/07/26 11:50:23+09:00 miura@da-cha.org +0 -0
# BitKeeper file /home/miura/kernel/linux-2.6.7-hm/drivers/acpi/pcc_acpi.c
#
# drivers/acpi/Makefile
# 2004/07/26 11:50:23+09:00 miura@da-cha.org +1 -0
# add Panasonic Laptop Extra driver entry
#
# drivers/acpi/Kconfig
# 2004/07/26 11:50:23+09:00 miura@da-cha.org +20 -0
# add Panasonic Laptop Extra driver entry
#
diff -Nru a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
--- a/drivers/acpi/Kconfig 2004-07-27 12:44:53 +09:00
+++ b/drivers/acpi/Kconfig 2004-07-27 12:44:53 +09:00
@@ -204,6 +204,26 @@
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 hotkey is 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.
+
+ More information about this driver will be available at
+ <http://www.da-cha.org/letsnote/>
+
+ If you have a panasonic lets note laptop (such as the CF-T2, Y2,
+ R2, W2, R3), say Y.
+
config ACPI_DEBUG
bool "Debug Statements"
depends on ACPI_INTERPRETER
diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile
--- a/drivers/acpi/Makefile 2004-07-27 12:44:53 +09:00
+++ b/drivers/acpi/Makefile 2004-07-27 12:44:53 +09:00
@@ -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 -Nru a/drivers/acpi/pcc_acpi.c b/drivers/acpi/pcc_acpi.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/drivers/acpi/pcc_acpi.c 2004-07-27 12:44:53 +09:00
@@ -0,0 +1,518 @@
+/*
+ * Panasonic HotKey control Extra driver
+ * (C) 2004 Hiroshi Miura <miura@da-cha.org>
+ * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
+ * All Rights Reserved
+ *
+ * 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
+ *
+ * The devolpment page for this driver will be located at
+ * http://www.da-cha.org/
+ *
+ *---------------------------------------------------------------------------
+ *
+ * ChangeLog:
+ * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.4 first post version
+ * - add debug 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 based on acpi video driver
+ *
+ * TODO
+ * everything all
+ *
+ */
+
+#define ACPI_PCC_VERSION "0.4"
+#define PROC_INTERFACE_VERSION 2
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Hiroshi Miura");
+MODULE_DESCRIPTION("ACPI HotKey driver for lets note");
+MODULE_LICENSE("GPL");
+
+#define LOGPREFIX "acpi_pcc: "
+
+/****************************************************
+ * Define ACPI PATHs
+ ****************************************************/
+/* crt/lcd hot key definitions */
+#define DEVICE_NAME_VGA "\\_SB_.PCI0.GRFX"
+#define DEVICE_NAME_CRT "CRT1"
+#define DEVICE_NAME_LCD "LCD1"
+#define METHOD_CHGD "\\_SB_.CHGD"
+
+/* Lets note hotkeys definitions */
+#define DEVICE_NAME_HKEY "\\_SB_.HKEY"
+#define METHOD_HKEY_QUERY "HINF"
+
+/* ACPI BIOS inside use only? */
+#define METHOD_HKEY_RESET "HRES"
+#define METHOD_HKEY_SAVE "HSAV"
+#define METHOD_HKEY_HIND "HIND"
+
+/* event read/write functions */
+#define METHOD_HKEY_SQTY "SQTY"
+#define METHOD_HKEY_SINF "SINF"
+#define METHOD_HKEY_SSET "SSET"
+
+
+/* device(HKEY) definitions */
+#define HKEY_HID "MAT0019"
+#define HKEY_NOTIFY 0x80
+
+/*******************************************************************
+ *
+ * definitions for /proc/ interface
+ *
+ *******************************************************************/
+#define PROC_PCC "pcc"
+
+#define ACPI_HOTKEY_DRIVER_NAME "PCC HotKey Driver"
+#define ACPI_HOTKEY_DEVICE_NAME "HotKey"
+#define ACPI_HOTKEY_CLASS "HKEY"
+
+static int acpi_hotkey_add (struct acpi_device *device);
+static int acpi_hotkey_remove (struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_hotkey_driver = {
+ .name = ACPI_HOTKEY_DRIVER_NAME,
+ .class = ACPI_HOTKEY_CLASS,
+ .ids = HKEY_HID,
+ .ops = {
+ .add = acpi_hotkey_add,
+ .remove = acpi_hotkey_remove,
+ },
+};
+
+struct acpi_hotkey {
+ acpi_handle handle;
+ struct acpi_device *device;
+ unsigned long status;
+};
+
+
+/*
+ * utility functions
+ */
+static __inline__ void
+_set_bit(u32* word, u32 mask, int value)
+{
+ *word = (*word & ~mask) | (mask * value);
+}
+
+/* acpi interface wrappers
+ */
+static int
+is_valid_acpi_path(const char* methodName)
+{
+ acpi_handle handle;
+ acpi_status status;
+
+ status = acpi_get_handle(0, (char*)methodName, &handle);
+ return !ACPI_FAILURE(status);
+}
+
+#if 0
+static int
+write_acpi_int(const char* methodName, int val)
+{
+ struct acpi_object_list params;
+ union acpi_object in_objs[1];
+ acpi_status status;
+
+ 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 = val;
+
+ status = acpi_evaluate_object(0, (char*)methodName, ¶ms, 0);
+ return (status == AE_OK);
+}
+#endif
+
+static int
+read_acpi_int(acpi_handle handle, const char* methodName, int* pVal)
+{
+ struct acpi_buffer results;
+ union acpi_object out_objs[1];
+ acpi_status status;
+
+ results.length = sizeof(out_objs);
+ results.pointer = out_objs;
+
+ status = acpi_evaluate_object(handle, (char*)methodName, 0, &results);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO "acpi evaluate error on %s\n", methodName);
+ return (-EFAULT);
+ }
+
+ if (out_objs[0].type == ACPI_TYPE_INTEGER) {
+ *pVal = out_objs[0].integer.value;
+ } else {
+ printk(KERN_INFO "return value is not int\n");
+ status = AE_ERROR;
+ }
+
+ return (status == AE_OK);
+}
+
+static struct proc_dir_entry* acpi_pcc_dir;
+
+typedef struct _ProcItem
+{
+ const char* name;
+ char* (*read_func)(char*);
+ unsigned long (*write_func)(const char*, unsigned long);
+} ProcItem;
+
+
+/* register utils for proc handler */
+static int
+dispatch_read(char* page, char** start, off_t off, int count, int* eof,
+ ProcItem* item)
+{
+ char* p = page;
+ int len;
+
+ if (off == 0)
+ p = item->read_func(p);
+
+ /* ISSUE: I don't understand this code */
+ len = (p - page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int
+dispatch_write(struct file* file, __user const char* buffer,
+ unsigned long count, ProcItem* item)
+{
+ int result;
+ char* tmp_buffer;
+
+ /* Arg buffer points to userspace memory, which can't be accessed
+ * directly. Since we're making a copy, zero-terminate the
+ * destination so that sscanf can be used on it safely.
+ */
+ tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
+ if (copy_from_user(tmp_buffer, buffer, count)) {
+ result = -EFAULT;
+ }
+ else {
+ tmp_buffer[count] = 0;
+ result = item->write_func(tmp_buffer, count);
+ }
+ kfree(tmp_buffer);
+ return result;
+}
+
+/*
+ * proc file handlers
+ */
+#ifdef DEBUG_PCC_VGA
+static unsigned long
+write_chgd(const char* buffer, unsigned long count)
+{
+ int value;
+ acpi_status status;
+
+ if (sscanf(buffer, "%i", &value) == 1 && value >= 0 && value < 2) {
+ if (value == 0)
+ /* do nothing */
+ status = AE_OK;
+ else {
+ status = acpi_evaluate_object(0, METHOD_CHGD, 0 , 0);
+ }
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO LOGPREFIX "fail evaluate CHGD()\n");
+ return -EFAULT;
+ }
+ }
+ return count;
+
+}
+
+static char*
+read_nothing(char* p)
+{
+ /* nothing to do*/
+ return p;
+}
+#endif
+
+static char*
+read_hkey_status(char* p)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *hkey = NULL;
+ int i, num_sifr;
+
+ if (!read_acpi_int(NULL, DEVICE_NAME_HKEY "." METHOD_HKEY_SQTY, &num_sifr)){
+ printk(KERN_INFO LOGPREFIX "evaluation error HKEY.SQTY\n");
+ return p;
+ }
+
+ status = acpi_evaluate_object(NULL, DEVICE_NAME_HKEY "." METHOD_HKEY_SINF, 0 , &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO LOGPREFIX "evaluation error HEKY.SINF\n");
+ return p;
+ }
+ hkey = (union acpi_object *) buffer.pointer;
+ if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
+ printk(KERN_INFO LOGPREFIX "Invalid HKEY.SINF\n");
+ goto end;
+ }
+
+ if (num_sifr != hkey->package.count) {
+ printk(KERN_INFO LOGPREFIX "SQTY is not equal to SINF length?\n");
+ 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)) {
+ p += sprintf(p, "0x%02x,\n", (unsigned int)element->integer.value);
+ } else
+ printk(KERN_INFO LOGPREFIX "Invalid HKEY.SINF value\n");
+ }
+end:
+ acpi_os_free(buffer.pointer);
+ return p;
+}
+
+
+static char*
+read_version(char* p)
+{
+ p += sprintf(p, "%s version %s\n", ACPI_HOTKEY_DRIVER_NAME, ACPI_PCC_VERSION);
+ p += sprintf(p, "proc_interface version %d\n", PROC_INTERFACE_VERSION);
+ return p;
+}
+
+
+/* hotkey driver */
+static int
+acpi_hotkey_get_key(struct acpi_hotkey *hotkey)
+{
+ int result;
+ int status;
+
+ status = read_acpi_int(hotkey->handle, METHOD_HKEY_QUERY, &result);
+ if (!status) {
+ printk(KERN_INFO LOGPREFIX "error getting hotkey status\n");
+ } else
+ hotkey->status = result;
+
+ return (status);
+}
+
+void
+acpi_hotkey_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct acpi_hotkey *hotkey = (struct acpi_hotkey *) data;
+
+ if (!hotkey || !hotkey->device)
+ return;
+
+ switch(event) {
+ case HKEY_NOTIFY:
+ if (acpi_hotkey_get_key(hotkey))
+ acpi_bus_generate_event(hotkey->device, event, hotkey->status);
+ break;
+ default:
+ /* nothing to do */
+ break;
+ }
+
+ return;
+}
+
+static int
+acpi_hotkey_add (struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_hotkey *hotkey = NULL;
+
+ if (!device)
+ return (-EINVAL);
+
+ hotkey = kmalloc(sizeof(struct acpi_hotkey), GFP_KERNEL);
+ if (!hotkey)
+ return (-ENOMEM);
+
+ memset(hotkey, 0, sizeof(struct acpi_hotkey));
+
+ hotkey->device = device;
+ hotkey->handle = device->handle;
+ acpi_driver_data(device) = hotkey;
+ strcpy(acpi_device_name(device), ACPI_HOTKEY_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_HOTKEY_CLASS);
+
+ status = acpi_install_notify_handler (
+ hotkey->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_hotkey_notify,
+ hotkey);
+ if (ACPI_FAILURE(status))
+ result = -ENODEV;
+
+ if (result)
+ kfree(hotkey);
+
+ return (result);
+}
+
+static int
+acpi_hotkey_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+ struct acpi_hotkey *hotkey = NULL;
+
+ if (!device || !acpi_driver_data(device))
+ return(-EINVAL);
+
+ hotkey = acpi_driver_data(device);
+ status = acpi_remove_notify_handler(hotkey->handle,
+ ACPI_DEVICE_NOTIFY, acpi_hotkey_notify);
+ if (ACPI_FAILURE(status))
+ printk(KERN_INFO LOGPREFIX "Error removing notify handler\n");
+
+ kfree(hotkey);
+
+ return(0);
+}
+
+/*
+ * proc and module init
+*/
+
+ProcItem pcc_proc_items[] =
+{
+#ifdef DEBUG_PCC_VGA
+ { "chgd" , read_nothing , write_chgd},
+#endif
+ { "hkey_status", read_hkey_status, NULL},
+ { "version", read_version , NULL},
+ { NULL , NULL , NULL},
+};
+
+static acpi_status __init
+add_device(ProcItem *proc_items, struct proc_dir_entry* proc_entry)
+{
+ struct proc_dir_entry* proc;
+ ProcItem* item;
+
+ for (item = proc_items; item->name; ++item)
+ {
+ proc = create_proc_read_entry(item->name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ proc_entry, (read_proc_t*)dispatch_read, item);
+ if (proc)
+ proc->owner = THIS_MODULE;
+ if (proc && item->write_func)
+ proc->write_proc = (write_proc_t*)dispatch_write;
+ }
+
+ return(AE_OK);
+}
+
+
+static int __init
+pcc_proc_init(void)
+{
+ acpi_status status = AE_OK;
+
+ if (unlikely(!(acpi_pcc_dir = proc_mkdir(PROC_PCC, acpi_root_dir))))
+ return -ENODEV;
+
+ acpi_pcc_dir->owner = THIS_MODULE;
+ status = add_device(pcc_proc_items, acpi_pcc_dir);
+ if (ACPI_FAILURE(status)){
+ remove_proc_entry(PROC_PCC, acpi_root_dir);
+ return -ENODEV;
+ }
+
+ return (status == AE_OK);
+}
+
+static acpi_status __exit
+remove_device(ProcItem *proc_items, struct proc_dir_entry* proc_entry)
+{
+ ProcItem* item;
+
+ for (item = proc_items; item->name; ++item)
+ remove_proc_entry(item->name, proc_entry);
+ return(AE_OK);
+}
+
+
+
+/* init funcs. */
+static int __init
+acpi_pcc_init(void)
+{
+ acpi_status result = AE_OK;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ /* simple device detection: look forI method */
+ if (!(is_valid_acpi_path(METHOD_CHGD)))
+ return -ENODEV;
+
+ result = acpi_bus_register_driver(&acpi_hotkey_driver);
+ if (ACPI_FAILURE(result))
+ printk(KERN_INFO LOGPREFIX "Error registering hotkey driver\n");
+
+ printk(KERN_INFO LOGPREFIX "ACPI PCC HotKey driver version %s\n", ACPI_PCC_VERSION);
+
+ return (pcc_proc_init());
+
+}
+
+static void __exit
+acpi_pcc_exit(void)
+{
+ if (acpi_pcc_dir) {
+ remove_device(pcc_proc_items, acpi_pcc_dir);
+ remove_proc_entry(PROC_PCC, acpi_root_dir);
+ }
+ acpi_bus_unregister_driver(&acpi_hotkey_driver);
+ return;
+}
+
+module_init(acpi_pcc_init);
+module_exit(acpi_pcc_exit);
--
Hiroshi Miura --- http://www.da-cha.org/ --- miura@da-cha.org
NTTDATA Corp. OpenSource Software Center. --- miurahr@nttdata.co.jp
NTTDATA Intellilink Corp. OpenSource Engineering Dev. -- miurahr@intellilink.co.jp
Key fingerprint = 9117 9407 5684 FBF1 4063 15B4 401D D077 04AB 8617
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH][ACPI] Panasonic Hotkey Driver
2004-07-31 14:17 [PATCH][ACPI] Panasonic Hotkey Driver Hiroshi Miura
@ 2004-08-18 5:04 ` Len Brown
2004-08-18 14:52 ` John Belmonte
2004-08-19 3:50 ` Hiroshi Miura
0 siblings, 2 replies; 6+ messages in thread
From: Len Brown @ 2004-08-18 5:04 UTC (permalink / raw)
To: Hiroshi Miura; +Cc: linux-kernel, ACPI Developers, letsnote-tech
[-- Attachment #1: Type: text/plain, Size: 20892 bytes --]
Ah yes, another battle in the war on hot-keys;-)
On Sat, 2004-07-31 at 10:17, Hiroshi Miura wrote:
> Hi,
>
> This is a hotkey driver for Panasonic Lets note series.
> I tested this driver on 2.6.7 kernel and Panasonic CF-R3 laptop.
> Using this driver, users can handle Fn+Fx key (except for Fn+F3) with
> acpid.
>
> The event is for example 'HKEY HKEY 00000080 0000001' for Fn+F1.
Would be good if you had a comment that listed what hot keys are
available etc.
>
> sample scripts as follows
>
> # /etc/acpi/events/hotkey
> event=HKEY.*
> action=/etc/acpi/hotkey.sh "%e"
>
> hotkey.sh is
>
> #!/bin/sh
> set $*
> # Take care about the way events are reported
> key="$4";
>
> case "$key" in
> 0000000a)
> logger "acpid: received a suspend request"
> echo 1 > /proc/swsusp/activate
> hwclock --hctosys
> break
> ;;
> *)
> logger "acpid: action $key is not defined"
> ;;
> esac
>
>
>
>
> patch is follows
>
> # This is a BitKeeper generated diff -Nru style patch.
Since you're using bitkeeper, one option is to preserve your check-in
comments by sending me the patch via bjorn's bkexport script (attached).
Though I reserve the right to edit all comments;-)
> # ChangeSet
> # 2004/07/26 11:50:39+09:00 miura@da-cha.org
> # Panasonic Laptop Extra driver.
> # This adds support of hotkey (Fn+Fx) on Panasonic Lets note Laptop
> series.
> # Loding this driver, user can get event through acpid like "HKEY
> HKEY 0000080 000001"
> #
> # Signed-off-by: Hiroshi Miura <miura@da-cha.org>
> #
> # drivers/acpi/pcc_acpi.c
> # 2004/07/26 11:50:23+09:00 miura@da-cha.org +518 -0
> #
> # drivers/acpi/pcc_acpi.c
> # 2004/07/26 11:50:23+09:00 miura@da-cha.org +0 -0
> # BitKeeper file
> /home/miura/kernel/linux-2.6.7-hm/drivers/acpi/pcc_acpi.c
> #
> # drivers/acpi/Makefile
> # 2004/07/26 11:50:23+09:00 miura@da-cha.org +1 -0
> # add Panasonic Laptop Extra driver entry
> #
> # drivers/acpi/Kconfig
> # 2004/07/26 11:50:23+09:00 miura@da-cha.org +20 -0
> # add Panasonic Laptop Extra driver entry
> #
> diff -Nru a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> --- a/drivers/acpi/Kconfig 2004-07-27 12:44:53 +09:00
> +++ b/drivers/acpi/Kconfig 2004-07-27 12:44:53 +09:00
> @@ -204,6 +204,26 @@
> If you have a legacy free Toshiba laptop (such as the
> Libretto L1
> series), say Y.
>
> +config ACPI_PCC
> + tristate "Panasonic Laptop Extras"
how about calling it a hot key driver instead of an "extras driver",
unless there is something other than hot keys coming.
> + depends on X86
> + depends on ACPI_INTERPRETER
CONFIG_ACPI_INTERPRETER options is going away, okay to leave it out.
> + default m
> + ---help---
> + This driver adds support for access to certain system
> settings
> + on panasonic Let's Note laptops.
> +
> + On these machines, all hotkey is 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.
> +
> + More information about this driver will be available at
> + <http://www.da-cha.org/letsnote/>
> +
> + If you have a panasonic lets note laptop (such as the CF-T2,
> Y2,
> + R2, W2, R3), say Y.
> +
> config ACPI_DEBUG
> bool "Debug Statements"
> depends on ACPI_INTERPRETER
> diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> --- a/drivers/acpi/Makefile 2004-07-27 12:44:53 +09:00
> +++ b/drivers/acpi/Makefile 2004-07-27 12:44:53 +09:00
> @@ -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 -Nru a/drivers/acpi/pcc_acpi.c b/drivers/acpi/pcc_acpi.c
> --- /dev/null Wed Dec 31 16:00:00 196900
> +++ b/drivers/acpi/pcc_acpi.c 2004-07-27 12:44:53 +09:00
> @@ -0,0 +1,518 @@
> +/*
> + * Panasonic HotKey control Extra driver
> + * (C) 2004 Hiroshi Miura <miura@da-cha.org>
> + * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
> + * All Rights Reserved
> + *
> + * 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
> + *
> + * The devolpment page for this driver will be located at
> + * http://www.da-cha.org/
> + *
> +
> *---------------------------------------------------------------------------
> + *
> + * ChangeLog:
> + * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org>
> + * - v0.4 first post version
> + * - add debug 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 based on acpi video driver
> + *
would be polite to credit the exact files that you leveraged.
> + * TODO
> + * everything all
> + *
> + */
> +
> +#define ACPI_PCC_VERSION "0.4"
> +#define PROC_INTERFACE_VERSION 2
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/proc_fs.h>
> +#include <asm/uaccess.h>
> +
> +#include <acpi/acpi_bus.h>
> +#include <acpi/acpi_drivers.h>
> +
> +MODULE_AUTHOR("Hiroshi Miura");
> +MODULE_DESCRIPTION("ACPI HotKey driver for lets note");
> +MODULE_LICENSE("GPL");
> +
> +#define LOGPREFIX "acpi_pcc: "
> +
> +/****************************************************
> + * Define ACPI PATHs
> + ****************************************************/
> +/* crt/lcd hot key definitions */
> +#define DEVICE_NAME_VGA "\\_SB_.PCI0.GRFX"
> +#define DEVICE_NAME_CRT "CRT1"
> +#define DEVICE_NAME_LCD "LCD1"
These three are unused and should be deleted.
(they should be part of the video driver)
> +#define METHOD_CHGD "\\_SB_.CHGD"
> +
> +/* Lets note hotkeys definitions */
> +#define DEVICE_NAME_HKEY "\\_SB_.HKEY"
> +#define METHOD_HKEY_QUERY "HINF"
> +
> +/* ACPI BIOS inside use only? */
> +#define METHOD_HKEY_RESET "HRES"
> +#define METHOD_HKEY_SAVE "HSAV"
> +#define METHOD_HKEY_HIND "HIND"
> +
> +/* event read/write functions */
> +#define METHOD_HKEY_SQTY "SQTY"
> +#define METHOD_HKEY_SINF "SINF"
> +#define METHOD_HKEY_SSET "SSET"
> +
> +
> +/* device(HKEY) definitions */
> +#define HKEY_HID "MAT0019"
I'm extremely pleased to see this keys off a HID.
> +#define HKEY_NOTIFY 0x80
> +
> +/*******************************************************************
> + *
> + * definitions for /proc/ interface
> + *
> + *******************************************************************/
> +#define PROC_PCC "pcc"
> +
> +#define ACPI_HOTKEY_DRIVER_NAME "PCC HotKey Driver"
> +#define ACPI_HOTKEY_DEVICE_NAME "HotKey"
> +#define ACPI_HOTKEY_CLASS "HKEY"
> +
> +static int acpi_hotkey_add (struct acpi_device *device);
> +static int acpi_hotkey_remove (struct acpi_device *device, int type);
> +
> +static struct acpi_driver acpi_hotkey_driver = {
> + .name = ACPI_HOTKEY_DRIVER_NAME,
> + .class = ACPI_HOTKEY_CLASS,
> + .ids = HKEY_HID,
> + .ops = {
> + .add = acpi_hotkey_add,
> + .remove = acpi_hotkey_remove,
> + },
> +};
> +
> +struct acpi_hotkey {
> + acpi_handle handle;
> + struct acpi_device *device;
> + unsigned long status;
> +};
> +
> +
> +/*
> + * utility functions
> + */
> +static __inline__ void
> +_set_bit(u32* word, u32 mask, int value)
> +{
> + *word = (*word & ~mask) | (mask * value);
> +}
> +
> +/* acpi interface wrappers
> + */
> +static int
> +is_valid_acpi_path(const char* methodName)
> +{
> + acpi_handle handle;
> + acpi_status status;
> +
> + status = acpi_get_handle(0, (char*)methodName, &handle);
> + return !ACPI_FAILURE(status);
> +}
> +
> +#if 0
> +static int
> +write_acpi_int(const char* methodName, int val)
> +{
> + struct acpi_object_list params;
> + union acpi_object in_objs[1];
> + acpi_status status;
> +
> + 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 = val;
> +
> + status = acpi_evaluate_object(0, (char*)methodName, ¶ms,
> 0);
> + return (status == AE_OK);
> +}
> +#endif
hmm, this dead code above looks familiar:-)
we'll want to clean out the #if 0's, or at least
put them under a descriptive #ifdef, yes?
> +
> +static int
> +read_acpi_int(acpi_handle handle, const char* methodName, int* pVal)
> +{
> + struct acpi_buffer results;
> + union acpi_object out_objs[1];
> + acpi_status status;
> +
> + results.length = sizeof(out_objs);
> + results.pointer = out_objs;
> +
> + status = acpi_evaluate_object(handle, (char*)methodName, 0,
> &results);
> + if (ACPI_FAILURE(status)) {
> + printk(KERN_INFO "acpi evaluate error on %s\n",
> methodName);
> + return (-EFAULT);
> + }
> +
> + if (out_objs[0].type == ACPI_TYPE_INTEGER) {
> + *pVal = out_objs[0].integer.value;
> + } else {
> + printk(KERN_INFO "return value is not int\n");
> + status = AE_ERROR;
> + }
> +
> + return (status == AE_OK);
> +}
> +
> +static struct proc_dir_entry* acpi_pcc_dir;
> +
> +typedef struct _ProcItem
> +{
> + const char* name;
> + char* (*read_func)(char*);
> + unsigned long (*write_func)(const char*, unsigned long);
> +} ProcItem;
> +
> +
> +/* register utils for proc handler */
> +static int
> +dispatch_read(char* page, char** start, off_t off, int count, int*
> eof,
> + ProcItem* item)
> +{
> + char* p = page;
> + int len;
> +
> + if (off == 0)
> + p = item->read_func(p);
> +
> + /* ISSUE: I don't understand this code */
> + len = (p - page);
> + if (len <= off+count) *eof = 1;
> + *start = page + off;
> + len -= off;
> + if (len>count) len = count;
> + if (len<0) len = 0;
> + return len;
> +}
> +
> +static int
> +dispatch_write(struct file* file, __user const char* buffer,
> + unsigned long count, ProcItem* item)
> +{
> + int result;
> + char* tmp_buffer;
> +
> + /* Arg buffer points to userspace memory, which can't be
> accessed
> + * directly. Since we're making a copy, zero-terminate the
> + * destination so that sscanf can be used on it safely.
> + */
> + tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
> + if (copy_from_user(tmp_buffer, buffer, count)) {
> + result = -EFAULT;
> + }
> + else {
> + tmp_buffer[count] = 0;
> + result = item->write_func(tmp_buffer, count);
> + }
> + kfree(tmp_buffer);
> + return result;
> +}
> +
> +/*
> + * proc file handlers
> + */
Of course we're trying to get away from /proc at this point and head for
sysfs...
> +#ifdef DEBUG_PCC_VGA
> +static unsigned long
> +write_chgd(const char* buffer, unsigned long count)
> +{
> + int value;
> + acpi_status status;
> +
> + if (sscanf(buffer, "%i", &value) == 1 && value >= 0 && value <
> 2) {
> + if (value == 0)
> + /* do nothing */
> + status = AE_OK;
> + else {
> + status = acpi_evaluate_object(0, METHOD_CHGD,
> 0 , 0);
> + }
> + if (ACPI_FAILURE(status)) {
> + printk(KERN_INFO LOGPREFIX "fail evaluate
> CHGD()\n");
> + return -EFAULT;
> + }
> + }
> + return count;
> +
> +}
> +
> +static char*
> +read_nothing(char* p)
> +{
> + /* nothing to do*/
> + return p;
> +}
> +#endif
> +
> +static char*
> +read_hkey_status(char* p)
> +{
> + acpi_status status;
> + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
> + union acpi_object *hkey = NULL;
> + int i, num_sifr;
> +
> + if (!read_acpi_int(NULL, DEVICE_NAME_HKEY "."
> METHOD_HKEY_SQTY, &num_sifr)){
> + printk(KERN_INFO LOGPREFIX "evaluation error
> HKEY.SQTY\n");
> + return p;
> + }
> +
> + status = acpi_evaluate_object(NULL, DEVICE_NAME_HKEY "."
> METHOD_HKEY_SINF, 0 , &buffer);
> + if (ACPI_FAILURE(status)) {
> + printk(KERN_INFO LOGPREFIX "evaluation error
> HEKY.SINF\n");
> + return p;
> + }
> + hkey = (union acpi_object *) buffer.pointer;
> + if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
> + printk(KERN_INFO LOGPREFIX "Invalid HKEY.SINF\n");
> + goto end;
> + }
> +
> + if (num_sifr != hkey->package.count) {
> + printk(KERN_INFO LOGPREFIX "SQTY is not equal to SINF
> length?\n");
> + 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)) {
> + p += sprintf(p, "0x%02x,\n", (unsigned
> int)element->integer.value);
> + } else
> + printk(KERN_INFO LOGPREFIX "Invalid HKEY.SINF
> value\n");
> + }
> +end:
> + acpi_os_free(buffer.pointer);
> + return p;
> +}
> +
> +
> +static char*
> +read_version(char* p)
> +{
> + p += sprintf(p, "%s version %s\n", ACPI_HOTKEY_DRIVER_NAME,
> ACPI_PCC_VERSION);
> + p += sprintf(p, "proc_interface version %d\n",
> PROC_INTERFACE_VERSION);
> + return p;
> +}
> +
> +
> +/* hotkey driver */
> +static int
> +acpi_hotkey_get_key(struct acpi_hotkey *hotkey)
> +{
> + int result;
> + int status;
> +
> + status = read_acpi_int(hotkey->handle, METHOD_HKEY_QUERY,
> &result);
> + if (!status) {
> + printk(KERN_INFO LOGPREFIX "error getting hotkey
> status\n");
> + } else
> + hotkey->status = result;
> +
> + return (status);
> +}
> +
> +void
> +acpi_hotkey_notify(acpi_handle handle, u32 event, void *data)
> +{
> + struct acpi_hotkey *hotkey = (struct acpi_hotkey *) data;
> +
> + if (!hotkey || !hotkey->device)
> + return;
> +
> + switch(event) {
> + case HKEY_NOTIFY:
> + if (acpi_hotkey_get_key(hotkey))
> + acpi_bus_generate_event(hotkey->device, event,
> hotkey->status);
> + break;
> + default:
> + /* nothing to do */
> + break;
> + }
> +
> + return;
> +}
> +
> +static int
> +acpi_hotkey_add (struct acpi_device *device)
> +{
> + int result = 0;
> + acpi_status status = AE_OK;
> + struct acpi_hotkey *hotkey = NULL;
> +
> + if (!device)
> + return (-EINVAL);
> +
> + hotkey = kmalloc(sizeof(struct acpi_hotkey), GFP_KERNEL);
> + if (!hotkey)
> + return (-ENOMEM);
> +
> + memset(hotkey, 0, sizeof(struct acpi_hotkey));
> +
> + hotkey->device = device;
> + hotkey->handle = device->handle;
> + acpi_driver_data(device) = hotkey;
> + strcpy(acpi_device_name(device), ACPI_HOTKEY_DEVICE_NAME);
> + strcpy(acpi_device_class(device), ACPI_HOTKEY_CLASS);
> +
> + status = acpi_install_notify_handler (
> + hotkey->handle,
> + ACPI_DEVICE_NOTIFY,
> + acpi_hotkey_notify,
> + hotkey);
> + if (ACPI_FAILURE(status))
> + result = -ENODEV;
> +
> + if (result)
> + kfree(hotkey);
> +
> + return (result);
> +}
> +
> +static int
> +acpi_hotkey_remove(struct acpi_device *device, int type)
> +{
> + acpi_status status = 0;
> + struct acpi_hotkey *hotkey = NULL;
> +
> + if (!device || !acpi_driver_data(device))
> + return(-EINVAL);
> +
> + hotkey = acpi_driver_data(device);
> + status = acpi_remove_notify_handler(hotkey->handle,
> + ACPI_DEVICE_NOTIFY, acpi_hotkey_notify);
> + if (ACPI_FAILURE(status))
> + printk(KERN_INFO LOGPREFIX "Error removing notify
> handler\n");
> +
> + kfree(hotkey);
> +
> + return(0);
> +}
> +
> +/*
> + * proc and module init
> +*/
> +
> +ProcItem pcc_proc_items[] =
> +{
> +#ifdef DEBUG_PCC_VGA
> + { "chgd" , read_nothing , write_chgd},
> +#endif
> + { "hkey_status", read_hkey_status, NULL},
> + { "version", read_version , NULL},
> + { NULL , NULL , NULL},
> +};
> +
> +static acpi_status __init
> +add_device(ProcItem *proc_items, struct proc_dir_entry* proc_entry)
> +{
> + struct proc_dir_entry* proc;
> + ProcItem* item;
> +
> + for (item = proc_items; item->name; ++item)
> + {
> + proc = create_proc_read_entry(item->name,
> + S_IFREG | S_IRUGO | S_IWUSR,
> + proc_entry, (read_proc_t*)dispatch_read,
> item);
> + if (proc)
> + proc->owner = THIS_MODULE;
> + if (proc && item->write_func)
> + proc->write_proc =
> (write_proc_t*)dispatch_write;
> + }
> +
> + return(AE_OK);
> +}
> +
> +
> +static int __init
> +pcc_proc_init(void)
> +{
> + acpi_status status = AE_OK;
> +
> + if (unlikely(!(acpi_pcc_dir = proc_mkdir(PROC_PCC,
> acpi_root_dir))))
> + return -ENODEV;
> +
> + acpi_pcc_dir->owner = THIS_MODULE;
> + status = add_device(pcc_proc_items, acpi_pcc_dir);
> + if (ACPI_FAILURE(status)){
> + remove_proc_entry(PROC_PCC, acpi_root_dir);
> + return -ENODEV;
> + }
> +
> + return (status == AE_OK);
> +}
> +
> +static acpi_status __exit
> +remove_device(ProcItem *proc_items, struct proc_dir_entry*
> proc_entry)
> +{
> + ProcItem* item;
> +
> + for (item = proc_items; item->name; ++item)
> + remove_proc_entry(item->name, proc_entry);
> + return(AE_OK);
> +}
> +
> +
> +
> +/* init funcs. */
> +static int __init
> +acpi_pcc_init(void)
> +{
> + acpi_status result = AE_OK;
> +
> + if (acpi_disabled)
> + return -ENODEV;
> +
> + /* simple device detection: look forI method */
> + if (!(is_valid_acpi_path(METHOD_CHGD)))
> + return -ENODEV;
Why is this necessary if you key off the HID with
acpi_bus_register_driver below?
> +
> + result = acpi_bus_register_driver(&acpi_hotkey_driver);
> + if (ACPI_FAILURE(result))
> + printk(KERN_INFO LOGPREFIX "Error registering hotkey
> driver\n");
> +
> + printk(KERN_INFO LOGPREFIX "ACPI PCC HotKey driver version
> %s\n", ACPI_PCC_VERSION);
> +
> + return (pcc_proc_init());
> +
> +}
> +
> +static void __exit
> +acpi_pcc_exit(void)
> +{
> + if (acpi_pcc_dir) {
> + remove_device(pcc_proc_items, acpi_pcc_dir);
> + remove_proc_entry(PROC_PCC, acpi_root_dir);
> + }
> + acpi_bus_unregister_driver(&acpi_hotkey_driver);
> + return;
> +}
> +
> +module_init(acpi_pcc_init);
> +module_exit(acpi_pcc_exit);
>
>
> --
> Hiroshi Miura --- http://www.da-cha.org/ --- miura@da-cha.org
> NTTDATA Corp. OpenSource Software Center. --- miurahr@nttdata.co.jp
> NTTDATA Intellilink Corp. OpenSource Engineering Dev. --
> miurahr@intellilink.co.jp
> Key fingerprint = 9117 9407 5684 FBF1 4063 15B4 401D D077 04AB 8617
>
[-- Attachment #2: bkexport --]
[-- Type: text/plain, Size: 524 bytes --]
#!/bin/sh
# Export a bitkeeper patch, adding author and per-file comments
if [ $# -gt 1 ]; then
CSET=`bk r2c $*`
CSET="-r$CSET"
else
CSET=$1
fi
echo -n "#### AUTHOR "
bk cset $CSET |\
awk -F\| "{printf \"bk prs -r%s -h -d '\$if(:DPN:=ChangeSet){:USER:@:HOST:\\n}' %s\n\", \$2, \$1}" |\
sh
echo "#### COMMENT START"
bk cset $CSET |\
awk -F\| "{printf \"bk prs -r%s -h -d '### Comments for :DPN:\\n\$each(:C:){(:C:)\\n}' %s\n\", \$2, \$1}" |\
sh
echo "#### COMMENT END"
echo
bk export -tpatch -du $CSET
[-- Attachment #3: bkimport --]
[-- Type: text/plain, Size: 608 bytes --]
#!/bin/sh
# Import a bitkeeper patch, preserving author and per-file comments
_import() {
PATCH=$1
FROM=`grep '^#### AUTHOR' $PATCH`
export BK_USER=`echo $FROM | sed -e 's/^#### AUTHOR //' -e 's/@.*//'`
export BK_HOST=`echo $FROM | sed -e 's/.*@//'`
echo Importing $PATCH from $BK_USER@$BK_HOST
#bk import -tpatch -qR $PATCH .
bk import -tpatch -vR $PATCH .
if [ $? -ne 0 ]; then
echo $PATCH: import failed
exit 0
fi
cat $PATCH |\
awk "/#### COMMENT START/ {p=1; next}; /#### COMMENT END/ {exit}; p==1" |\
bk comments -
}
for P in $@; do
_import $P
done
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH][ACPI] Panasonic Hotkey Driver
2004-08-18 5:04 ` Len Brown
@ 2004-08-18 14:52 ` John Belmonte
2004-08-19 3:41 ` Hiroshi Miura
2004-08-19 3:50 ` Hiroshi Miura
1 sibling, 1 reply; 6+ messages in thread
From: John Belmonte @ 2004-08-18 14:52 UTC (permalink / raw)
To: Len Brown; +Cc: Hiroshi Miura, linux-kernel, ACPI Developers, letsnote-tech
Len Brown wrote:
> Ah yes, another battle in the war on hot-keys;-)
>
> On Sat, 2004-07-31 at 10:17, Hiroshi Miura wrote:
>
>>+/*
>>+ * Panasonic HotKey control Extra driver
>>+ * (C) 2004 Hiroshi Miura <miura@da-cha.org>
>>+ * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
>>+ * All Rights Reserved
>>+ *
>>+ * 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
>>+ *
>>+ * The devolpment page for this driver will be located at
>>+ * http://www.da-cha.org/
>>+ *
>>+
>>*---------------------------------------------------------------------------
>>+ *
>>+ * ChangeLog:
>>+ * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org>
>>+ * - v0.4 first post version
>>+ * - add debug 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 based on acpi video driver
>>+ *
>
>
> would be polite to credit the exact files that you leveraged.
I think it's a little beyond a politeness issue. Large verbatim blocks
of toshiba_acpi.c are used, with my copyright notice nowhere in sight.
-John
--
http://giftfile.org/ :: giftfile project
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH][ACPI] Panasonic Hotkey Driver
2004-08-18 14:52 ` John Belmonte
@ 2004-08-19 3:41 ` Hiroshi Miura
0 siblings, 0 replies; 6+ messages in thread
From: Hiroshi Miura @ 2004-08-19 3:41 UTC (permalink / raw)
To: John Belmonte; +Cc: Len Brown, linux-kernel, ACPI Developers, letsnote-tech
I'm sorry, it's my mistake.
At Wed, 18 Aug 2004 10:52:23 -0400,
John Belmonte wrote:
> >>+ * Jul.17, 2004 Hiroshi Miura <miura@da-cha.org>
> >>+ * - v0.1 based on acpi video driver
> >>+ *
> >
> >
> > would be polite to credit the exact files that you leveraged.
>
> I think it's a little beyond a politeness issue. Large verbatim blocks
> of toshiba_acpi.c are used, with my copyright notice nowhere in sight.
You are right. This driver based on my test video
driver that start from toshiba_acpi.c. acpi_video driver is still in development.
I want to fix credit and description asap.
--
Hiroshi Miura --- http://www.da-cha.org/ --- miura@da-cha.org
NTTDATA Corp. OpenSource Software Center. --- miurahr@nttdata.co.jp
NTTDATA Intellilink Corp. OpenSource Engineering Dev. -- miurahr@intellilink.co.jp
Key fingerprint = 9117 9407 5684 FBF1 4063 15B4 401D D077 04AB 8617
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH][ACPI] Panasonic Hotkey Driver
2004-08-18 5:04 ` Len Brown
2004-08-18 14:52 ` John Belmonte
@ 2004-08-19 3:50 ` Hiroshi Miura
1 sibling, 0 replies; 6+ messages in thread
From: Hiroshi Miura @ 2004-08-19 3:50 UTC (permalink / raw)
To: Len Brown; +Cc: linux-kernel, ACPI Developers, letsnote-tech
Hi,
At 18 Aug 2004 01:04:34 -0400,
Len Brown wrote:
> >
> > The event is for example 'HKEY HKEY 00000080 0000001' for Fn+F1.
>
> Would be good if you had a comment that listed what hot keys are
> available etc.
ok, I will do.
> > # This is a BitKeeper generated diff -Nru style patch.
>
> Since you're using bitkeeper, one option is to preserve your check-in
> comments by sending me the patch via bjorn's bkexport script (attached).
> Though I reserve the right to edit all comments;-)
It's good. I want to try it.
> >
> > +config ACPI_PCC
> > + tristate "Panasonic Laptop Extras"
>
> how about calling it a hot key driver instead of an "extras driver",
> unless there is something other than hot keys coming.
now I implemented controller for lcd brightness in this driver.
I will post it soon.
> > + *
> > + * Jul.17, 2004 Hiroshi Miura <miura@da-cha.org>
> > + * - v0.1 based on acpi video driver
> > + *
>
> would be polite to credit the exact files that you leveraged.
Sorry, I will fix it as another post.
> > +/****************************************************
> > + * Define ACPI PATHs
> > + ****************************************************/
> > +/* crt/lcd hot key definitions */
> > +#define DEVICE_NAME_VGA "\\_SB_.PCI0.GRFX"
> > +#define DEVICE_NAME_CRT "CRT1"
> > +#define DEVICE_NAME_LCD "LCD1"
>
> These three are unused and should be deleted.
> (they should be part of the video driver)
Yes these are part of video driver.
> > +#define METHOD_CHGD "\\_SB_.CHGD"
I will remove it as same as above.
> > +#if 0
> > +static int
> > +write_acpi_int(const char* methodName, int val)
> > +{
> > + struct acpi_object_list params;
> > + union acpi_object in_objs[1];
> > + acpi_status status;
> > +
> > + 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 = val;
> > +
> > + status = acpi_evaluate_object(0, (char*)methodName, ¶ms,
> > 0);
> > + return (status == AE_OK);
> > +}
> > +#endif
>
> hmm, this dead code above looks familiar:-)
>
> we'll want to clean out the #if 0's, or at least
> put them under a descriptive #ifdef, yes?
will remove.
> > +/*
> > + * proc file handlers
> > + */
>
> Of course we're trying to get away from /proc at this point and head for
> sysfs...
Uuum, I must study... will rewrite.
> > +/* device(HKEY) definitions */
> > +#define HKEY_HID "MAT0019"
>
> I'm extremely pleased to see this keys off a HID.
> > +/* init funcs. */
> > +static int __init
> > +acpi_pcc_init(void)
> > +{
> > + acpi_status result = AE_OK;
> > +
> > + if (acpi_disabled)
> > + return -ENODEV;
> > +
> > + /* simple device detection: look forI method */
> > + if (!(is_valid_acpi_path(METHOD_CHGD)))
> > + return -ENODEV;
>
> Why is this necessary if you key off the HID with
> acpi_bus_register_driver below?
It's my first acpi driver. My understanding of acpi functions is
not enough at that time. I want to rewrite it.
--
Hiroshi Miura --- http://www.da-cha.org/ --- miura@da-cha.org
NTTDATA Corp. OpenSource Software Center. --- miurahr@nttdata.co.jp
NTTDATA Intellilink Corp. OpenSource Engineering Dev. -- miurahr@intellilink.co.jp
Key fingerprint = 9117 9407 5684 FBF1 4063 15B4 401D D077 04AB 8617
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH][ACPI] Panasonic Hotkey Driver
@ 2004-08-19 6:35 David Bronaugh
0 siblings, 0 replies; 6+ messages in thread
From: David Bronaugh @ 2004-08-19 6:35 UTC (permalink / raw)
To: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 2158 bytes --]
Hi,
The following patch adds brightness setting support to the driver and
cleans up the code a bit. It builds on the work of Hiroshi Miura and
takes into account the comments of Len Brown and John Belmonte. The
patch is against 2.6.8.1-mm1 (though the only thing that might differ
between -mm1 and vanilla is the Makefile).
I've tested this on my Panasonic CF-R1, and it works beautifully.
As far as I am concerned, besides code cleanups (and possibly figuring
out the monitor switch thing) this driver is complete.
I hope I haven't stepped on any toes here.
David Bronaugh
ps: I'm not on linux-kernel; I am on acpi-devel; forgot to CC this list
when sending to acpi-devel
---------
Supporting bits:
# /etc/acpi/events/hotkey
# This script handles hotkey events on Panasonic notebooks
event=HKEY.*
action=/etc/acpi/hotkey.sh %e
----------------------
#!/bin/bash
# Handles hotkey events for Panasonic notebooks
KEY=$4
BRIGHTNESS_CONTROL=/proc/acpi/pcc/brightness
VOLADJUST=5
GETVOLCMD="amixer cget numid=2"
GETMUTECMD="amixer cget numid=1"
SETVOLCMD="amixer cset numid=2"
SETMUTECMD="amixer cset numid=1"
case "$KEY" in
00000001)
logger "acpid: received a down brightness event"
BRIGHT=`cat /proc/acpi/pcc/brightness`
let BRIGHT=BRIGHT-1
echo $BRIGHT > $BRIGHTNESS_CONTROL
;;
00000002)
logger "acpid: received an up brightness event"
BRIGHT=`cat /proc/acpi/pcc/brightness`
let BRIGHT=BRIGHT+1
echo $BRIGHT > $BRIGHTNESS_CONTROL
;;
00000003)
logger "acpid: received a monitor switch event (unhandled)"
;;
00000004)
logger "acpid: received a sound mute event"
;;
00000005)
logger "acpid: received a volume down event"
;;
00000006)
logger "acpid: received a volume up event"
;;
00000007)
logger "acpid: received a suspend-to-RAM event (unhandled)"
;;
00000009)
logger "acpid: received a disk spindown event"
;;
0000000a)
logger "acpid: received a suspend-to-disk event"
;;
*)
logger "acpid: received unhandled event $KEY"
;;
esac
[-- Attachment #2: patch --]
[-- Type: text/plain, Size: 16160 bytes --]
diff -Nru lb-2.6.8.1/drivers/acpi/Kconfig linux-2.6.8.1/drivers/acpi/Kconfig
--- lb-2.6.8.1/drivers/acpi/Kconfig 2004-08-18 22:31:04.000000000 -0700
+++ linux-2.6.8.1/drivers/acpi/Kconfig 2004-08-18 22:40:19.000000000 -0700
@@ -204,6 +204,25 @@
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
+ default m
+ ---help---
+ This driver adds support for hotkeys and screen brightness setting
+ on Panasonic Let's Note laptops.
+
+ For CRT/LCD switching, see the userspace utility i810switch.
+
+ More information about this driver is available at
+ <http://www.da-cha.org/letsnote/>
+
+ Note: In order to effectively use this driver, you must set up your
+ acpid to handle 'hotkey' events. See the website for more details.
+
+ If you have a panasonic lets note laptop (such as the CF-T2, Y2,
+ R1, R2, W2, R3), say Y.
+
config ACPI_DEBUG
bool "Debug Statements"
depends on ACPI_INTERPRETER
diff -Nru lb-2.6.8.1/drivers/acpi/Makefile linux-2.6.8.1/drivers/acpi/Makefile
--- lb-2.6.8.1/drivers/acpi/Makefile 2004-08-18 22:31:18.000000000 -0700
+++ linux-2.6.8.1/drivers/acpi/Makefile 2004-08-18 19:00:56.000000000 -0700
@@ -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 motherboard.o
diff -Nru lb-2.6.8.1/drivers/acpi/pcc_acpi.c linux-2.6.8.1/drivers/acpi/pcc_acpi.c
--- lb-2.6.8.1/drivers/acpi/pcc_acpi.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.8.1/drivers/acpi/pcc_acpi.c 2004-08-18 22:54:59.000000000 -0700
@@ -0,0 +1,566 @@
+/*
+ * Panasonic HotKey control Extra driver
+ * (C) 2004 Hiroshi Miura <miura@da-cha.org>
+ * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
+ * (C) 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * All Rights Reserved
+ *
+ * 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
+ *
+ * The devolpment page for this driver will be located at
+ * http://www.da-cha.org/
+ *
+ *---------------------------------------------------------------------------
+ *
+ * ChangeLog:
+ * Aug.17, 2004 David Bronaugh (dbronaugh@linuxboxen.org)
+ * - v0.5 Added screen brightness setting interface
+ * - Thanks to the FreeBSD crew (acpi_panasonic.c authors)
+ * - for the ideas I needed to accomplish it
+ *
+ * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.4 first post version
+ * - add debug 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 Based on the toshiba_acpi.c video driver by
+ * - John Belmonte -- see toshiba_acpi.c for more details
+ *
+ * TODO
+ * - Figure out the display switch key: is it a part of the ACPI standard?
+ */
+
+#define ACPI_PCC_VERSION "0.5"
+#define PROC_INTERFACE_VERSION 2
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Hiroshi Miura");
+MODULE_DESCRIPTION("ACPI HotKey driver for lets note");
+MODULE_LICENSE("GPL");
+
+#define LOGPREFIX "acpi_pcc: "
+
+/****************************************************
+ * Define ACPI PATHs
+ ****************************************************/
+#define METHOD_CHGD "\\_SB_.CHGD"
+
+/* Lets note hotkeys definitions */
+#define DEVICE_NAME_HKEY "\\_SB_.HKEY"
+#define METHOD_HKEY_QUERY "HINF"
+
+/* ACPI BIOS inside use only? */
+#define METHOD_HKEY_RESET "HRES"
+#define METHOD_HKEY_SAVE "HSAV"
+#define METHOD_HKEY_HIND "HIND"
+
+/* event read/write functions */
+#define METHOD_HKEY_SQTY "SQTY"
+#define METHOD_HKEY_SINF "SINF"
+#define METHOD_HKEY_SSET "SSET"
+
+/* device(HKEY) definitions */
+#define HKEY_HID "MAT0019"
+#define HKEY_NOTIFY 0x80
+
+#define LCD_MAX_BRIGHTNESS 255
+
+/* This may be magical -- beware */
+#define LCD_BRIGHTNESS_INCREMENT 17
+
+/* Registers of SINF */
+#define SINF_LCD_BRIGHTNESS 4
+
+/*******************************************************************
+ *
+ * definitions for /proc/ interface
+ *
+ *******************************************************************/
+#define PROC_PCC "pcc"
+
+#define ACPI_HOTKEY_DRIVER_NAME "PCC HotKey Driver"
+#define ACPI_HOTKEY_DEVICE_NAME "HotKey"
+#define ACPI_HOTKEY_CLASS "HKEY"
+
+static int acpi_hotkey_add(struct acpi_device *device);
+static int acpi_hotkey_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_hotkey_driver = {
+ .name = ACPI_HOTKEY_DRIVER_NAME,
+ .class = ACPI_HOTKEY_CLASS,
+ .ids = HKEY_HID,
+ .ops = {
+ .add = acpi_hotkey_add,
+ .remove = acpi_hotkey_remove,
+ },
+};
+
+struct acpi_hotkey {
+ acpi_handle handle;
+ struct acpi_device *device;
+ unsigned long status;
+};
+
+/*
+ * utility functions
+ */
+static __inline__ void _set_bit(u32 * word, u32 mask, int value)
+{
+ *word = (*word & ~mask) | (mask * value);
+}
+
+/* acpi interface wrappers
+ */
+static int is_valid_acpi_path(const char *methodName)
+{
+ acpi_handle handle;
+ acpi_status status;
+
+ status = acpi_get_handle(0, (char *)methodName, &handle);
+ return !ACPI_FAILURE(status);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *methodName, int *pVal)
+{
+ struct acpi_buffer results;
+ union acpi_object out_objs[1];
+ acpi_status status;
+
+ results.length = sizeof(out_objs);
+ results.pointer = out_objs;
+
+ status = acpi_evaluate_object(handle, (char *)methodName, 0, &results);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO "acpi evaluate error on %s\n", methodName);
+ return (-EFAULT);
+ }
+
+ if (out_objs[0].type == ACPI_TYPE_INTEGER) {
+ *pVal = out_objs[0].integer.value;
+ } else {
+ printk(KERN_INFO "return value is not int\n");
+ status = AE_ERROR;
+ }
+
+ return (status == AE_OK);
+}
+
+static struct proc_dir_entry *acpi_pcc_dir;
+
+typedef struct _ProcItem {
+ const char *name;
+ char *(*read_func) (char *);
+ unsigned long (*write_func) (const char *, unsigned long);
+} ProcItem;
+
+/* register utils for proc handler */
+static int dispatch_read(char *page, char **start, off_t off, int count,
+ int *eof, ProcItem * item)
+{
+ char *p = page;
+ int len;
+
+ if (off == 0) {
+ p = item->read_func(p);
+ }
+
+ /* ISSUE: I don't understand this code */
+ len = (p - page);
+ if (len <= off + count) {
+ *eof = 1;
+ }
+ *start = page + off;
+ len -= off;
+ if (len > count) {
+ len = count;
+ }
+ if (len < 0) {
+ len = 0;
+ }
+ return len;
+}
+
+static int dispatch_write(struct file *file, __user const char *buffer,
+ unsigned long count, ProcItem * item)
+{
+ int result;
+ char *tmp_buffer;
+
+ /* Arg buffer points to userspace memory, which can't be accessed
+ * directly. Since we're making a copy, zero-terminate the
+ * destination so that sscanf can be used on it safely.
+ */
+ tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
+ if (copy_from_user(tmp_buffer, buffer, count)) {
+ result = -EFAULT;
+ } else {
+ tmp_buffer[count] = 0;
+ result = item->write_func(tmp_buffer, count);
+ }
+ kfree(tmp_buffer);
+ return result;
+}
+
+/*
+ * proc file handlers
+ */
+#ifdef DEBUG_PCC_VGA
+static unsigned long write_chgd(const char *buffer, unsigned long count)
+{
+ int value;
+ acpi_status status;
+
+ if (sscanf(buffer, "%i", &value) == 1 && value >= 0 && value < 2) {
+ if (value == 0) {
+ /* do nothing */
+ status = AE_OK;
+ } else {
+ status = acpi_evaluate_object(0, METHOD_CHGD, 0, 0);
+ }
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO LOGPREFIX "fail evaluate CHGD()\n");
+ return -EFAULT;
+ }
+ }
+ return count;
+
+}
+
+static char *read_nothing(char *p)
+{
+ /* nothing to do */
+ return p;
+}
+#endif
+
+static char *read_hkey_status(char *p)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *hkey = NULL;
+ int i, num_sifr;
+
+ if (!read_acpi_int(NULL, DEVICE_NAME_HKEY "." METHOD_HKEY_SQTY,
+ &num_sifr)) {
+ printk(KERN_INFO LOGPREFIX "evaluation error HKEY.SQTY\n");
+ return p;
+ }
+
+ status = acpi_evaluate_object(NULL,
+ DEVICE_NAME_HKEY "." METHOD_HKEY_SINF,
+ 0, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO LOGPREFIX "evaluation error HEKY.SINF\n");
+ return p;
+ }
+ hkey = (union acpi_object *)buffer.pointer;
+ if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
+ printk(KERN_INFO LOGPREFIX "Invalid HKEY.SINF\n");
+ goto end;
+ }
+
+ if (num_sifr != hkey->package.count) {
+ printk(KERN_INFO LOGPREFIX
+ "SQTY is not equal to SINF length?\n");
+ 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)) {
+ p += sprintf(p, "0x%02x,\n",
+ (unsigned int)element->integer.value);
+ } else
+ printk(KERN_INFO LOGPREFIX "Invalid HKEY.SINF value\n");
+ }
+ end:
+ acpi_os_free(buffer.pointer);
+ return p;
+}
+
+static char *read_version(char *p)
+{
+ p += sprintf(p, "%s version %s\n", ACPI_HOTKEY_DRIVER_NAME,
+ ACPI_PCC_VERSION);
+ p += sprintf(p, "proc_interface version %d\n", PROC_INTERFACE_VERSION);
+ return p;
+}
+
+static char *read_brightness(char *p)
+{
+ uint32_t brightness;
+ union acpi_object *resource;
+ struct acpi_buffer entries = { ACPI_ALLOCATE_BUFFER, NULL };
+ int status;
+
+ status = acpi_evaluate_object(NULL,
+ DEVICE_NAME_HKEY "." METHOD_HKEY_SINF,
+ NULL, &entries);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO "Could not get SINF\n");
+ return p;
+ }
+
+ resource = (union acpi_object *)entries.pointer;
+ if (!resource || resource->type != ACPI_TYPE_PACKAGE) {
+ printk(KERN_INFO "Could not read display brightness\n");
+ return p;
+ } else {
+ union acpi_object *element =
+ &(resource->package.elements[SINF_LCD_BRIGHTNESS]);
+ brightness = element->integer.value;
+ }
+ acpi_os_free(entries.pointer);
+
+ p += sprintf(p, "%i\n", brightness / LCD_BRIGHTNESS_INCREMENT);
+ return p;
+}
+
+static unsigned long write_brightness(const char *p, unsigned long count)
+{
+ int brightness = simple_strtol(p, NULL, 10) * LCD_BRIGHTNESS_INCREMENT;
+ union acpi_object data[2];
+ struct acpi_object_list args;
+ uint32_t status;
+
+ /* Clean up incoming data */
+ if (brightness > LCD_MAX_BRIGHTNESS) {
+ brightness = LCD_MAX_BRIGHTNESS;
+ } else if (brightness < 0) {
+ brightness = 0;
+ }
+
+ data[0].type = ACPI_TYPE_INTEGER;
+ data[0].integer.value = SINF_LCD_BRIGHTNESS;
+ data[1].type = ACPI_TYPE_INTEGER;
+ data[1].integer.value = brightness;
+ args.pointer = data;
+ args.count = 2;
+
+ status = acpi_evaluate_object(NULL,
+ DEVICE_NAME_HKEY "." METHOD_HKEY_SSET,
+ &args, NULL);
+
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO "Could not write display brightness");
+ }
+
+ return count;
+}
+
+/* hotkey driver */
+static int acpi_hotkey_get_key(struct acpi_hotkey *hotkey)
+{
+ int result;
+ int status;
+
+ status = read_acpi_int(hotkey->handle, METHOD_HKEY_QUERY, &result);
+ if (!status) {
+ printk(KERN_INFO LOGPREFIX "error getting hotkey status\n");
+ } else
+ hotkey->status = result;
+
+ return (status);
+}
+
+void acpi_hotkey_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct acpi_hotkey *hotkey = (struct acpi_hotkey *)data;
+
+ if (!hotkey || !hotkey->device)
+ return;
+
+ switch (event) {
+ case HKEY_NOTIFY:
+ if (acpi_hotkey_get_key(hotkey))
+ acpi_bus_generate_event(hotkey->device, event,
+ hotkey->status);
+ break;
+ default:
+ /* nothing to do */
+ break;
+ }
+
+ return;
+}
+
+static int acpi_hotkey_add(struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_hotkey *hotkey = NULL;
+
+ if (!device)
+ return (-EINVAL);
+
+ hotkey = kmalloc(sizeof(struct acpi_hotkey), GFP_KERNEL);
+ if (!hotkey)
+ return (-ENOMEM);
+
+ memset(hotkey, 0, sizeof(struct acpi_hotkey));
+
+ hotkey->device = device;
+ hotkey->handle = device->handle;
+ acpi_driver_data(device) = hotkey;
+ strcpy(acpi_device_name(device), ACPI_HOTKEY_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_HOTKEY_CLASS);
+
+ status = acpi_install_notify_handler(hotkey->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_hotkey_notify, hotkey);
+ if (ACPI_FAILURE(status))
+ result = -ENODEV;
+
+ if (result)
+ kfree(hotkey);
+
+ return (result);
+}
+
+static int acpi_hotkey_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+ struct acpi_hotkey *hotkey = NULL;
+
+ if (!device || !acpi_driver_data(device))
+ return (-EINVAL);
+
+ hotkey = acpi_driver_data(device);
+ status = acpi_remove_notify_handler(hotkey->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_hotkey_notify);
+ if (ACPI_FAILURE(status))
+ printk(KERN_INFO LOGPREFIX "Error removing notify handler\n");
+
+ kfree(hotkey);
+
+ return (0);
+}
+
+/*
+ * proc and module init
+*/
+
+ProcItem pcc_proc_items[] = {
+#ifdef DEBUG_PCC_VGA
+ {"chgd", read_nothing, write_chgd}
+ ,
+#endif
+ {"brightness", read_brightness, write_brightness}
+ ,
+ {"hkey_status", read_hkey_status, NULL}
+ ,
+ {"version", read_version, NULL}
+ ,
+ {NULL, NULL, NULL}
+ ,
+};
+
+static acpi_status __init
+add_device(ProcItem * proc_items, struct proc_dir_entry *proc_entry)
+{
+ struct proc_dir_entry *proc;
+ ProcItem *item;
+
+ for (item = proc_items; item->name; ++item) {
+ proc = create_proc_read_entry(item->name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ proc_entry,
+ (read_proc_t *) dispatch_read,
+ item);
+ if (proc)
+ proc->owner = THIS_MODULE;
+ if (proc && item->write_func)
+ proc->write_proc = (write_proc_t *) dispatch_write;
+ }
+
+ return (AE_OK);
+}
+
+static int __init pcc_proc_init(void)
+{
+ acpi_status status = AE_OK;
+
+ if (unlikely(!(acpi_pcc_dir = proc_mkdir(PROC_PCC, acpi_root_dir))))
+ return -ENODEV;
+
+ acpi_pcc_dir->owner = THIS_MODULE;
+ status = add_device(pcc_proc_items, acpi_pcc_dir);
+ if (ACPI_FAILURE(status)) {
+ remove_proc_entry(PROC_PCC, acpi_root_dir);
+ return -ENODEV;
+ }
+
+ return (status == AE_OK);
+}
+
+static acpi_status __exit
+remove_device(ProcItem * proc_items, struct proc_dir_entry *proc_entry)
+{
+ ProcItem *item;
+
+ for (item = proc_items; item->name; ++item)
+ remove_proc_entry(item->name, proc_entry);
+ return (AE_OK);
+}
+
+/* init funcs. */
+static int __init acpi_pcc_init(void)
+{
+ acpi_status result = AE_OK;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ /* simple device detection: look forI method */
+ if (!(is_valid_acpi_path(METHOD_CHGD)))
+ return -ENODEV;
+
+ result = acpi_bus_register_driver(&acpi_hotkey_driver);
+ if (ACPI_FAILURE(result))
+ printk(KERN_INFO LOGPREFIX "Error registering hotkey driver\n");
+
+ printk(KERN_INFO LOGPREFIX "ACPI PCC HotKey driver version %s\n",
+ ACPI_PCC_VERSION);
+
+ return (pcc_proc_init());
+
+}
+
+static void __exit acpi_pcc_exit(void)
+{
+ if (acpi_pcc_dir) {
+ remove_device(pcc_proc_items, acpi_pcc_dir);
+ remove_proc_entry(PROC_PCC, acpi_root_dir);
+ }
+ acpi_bus_unregister_driver(&acpi_hotkey_driver);
+ return;
+}
+
+module_init(acpi_pcc_init);
+module_exit(acpi_pcc_exit);
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2004-08-19 6:41 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-07-31 14:17 [PATCH][ACPI] Panasonic Hotkey Driver Hiroshi Miura
2004-08-18 5:04 ` Len Brown
2004-08-18 14:52 ` John Belmonte
2004-08-19 3:41 ` Hiroshi Miura
2004-08-19 3:50 ` Hiroshi Miura
-- strict thread matches above, loose matches on Subject: below --
2004-08-19 6:35 David Bronaugh
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox