aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuming Yu <luming.yu@intel.com>2005-03-18 18:03:45 -0500
committerLen Brown <len.brown@intel.com>2005-07-11 23:27:04 -0400
commitfb9802fa59b196d7f90bb3c2e33c555c6bdc4c54 (patch)
treeaca6fd906629c6da124a73b43e6f6c50f81b90b4
parentd58da590451cf6ae75379a2ebf96d3afb8d810d8 (diff)
[ACPI] generic Hot Key support
See Documentation/acpi-hotkey.txt Use cmdline "acpi_specific_hotkey" to enable legacy platform specific drivers. http://bugzilla.kernel.org/show_bug.cgi?id=3887 Signed-off-by: Luming Yu <luming.yu@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--Documentation/acpi-hotkey.txt35
-rw-r--r--drivers/acpi/Kconfig9
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/asus_acpi.c4
-rw-r--r--drivers/acpi/hotkey.c1018
-rw-r--r--drivers/acpi/ibm_acpi.c4
-rw-r--r--drivers/acpi/osl.c12
-rw-r--r--drivers/acpi/toshiba_acpi.c5
-rw-r--r--include/acpi/acpi_drivers.h5
9 files changed, 1094 insertions, 1 deletions
diff --git a/Documentation/acpi-hotkey.txt b/Documentation/acpi-hotkey.txt
new file mode 100644
index 000000000000..4c115a7bb826
--- /dev/null
+++ b/Documentation/acpi-hotkey.txt
@@ -0,0 +1,35 @@
1driver/acpi/hotkey.c implement:
21. /proc/acpi/hotkey/event_config
3(event based hotkey or event config interface):
4a. add a event based hotkey(event) :
5echo "0:bus::action:method:num:num" > event_config
6
7b. delete a event based hotkey(event):
8echo "1:::::num:num" > event_config
9
10c. modify a event based hotkey(event):
11echo "2:bus::action:method:num:num" > event_config
12
132. /proc/acpi/hotkey/poll_config
14(polling based hotkey or event config interface):
15a.add a polling based hotkey(event) :
16echo "0:bus:method:action:method:num" > poll_config
17this adding command will create a proc file
18/proc/acpi/hotkey/method, which is used to get
19result of polling.
20
21b.delete a polling based hotkey(event):
22echo "1:::::num" > event_config
23
24c.modify a polling based hotkey(event):
25echo "2:bus:method:action:method:num" > poll_config
26
273./proc/acpi/hotkey/action
28(interface to call aml method associated with a
29specific hotkey(event))
30echo "event_num:event_type:event_argument" >
31 /proc/acpi/hotkey/action.
32The result of the execution of this aml method is
33attached to /proc/acpi/hotkey/poll_method, which is dnyamically
34created. Please use command "cat /proc/acpi/hotkey/polling_method"
35to retrieve it.
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index ceecc5634e74..fa7f43451891 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -123,6 +123,15 @@ config ACPI_VIDEO
123 Note that this is an ref. implementation only. It may or may not work 123 Note that this is an ref. implementation only. It may or may not work
124 for your integrated video device. 124 for your integrated video device.
125 125
126config ACPI_HOTKEY
127 tristate "Generic Hotkey"
128 depends on ACPI_INTERPRETER
129 depends on EXPERIMENTAL
130 depends on !IA64_SGI_SN
131 default m
132 help
133 ACPI generic hotkey
134
126config ACPI_FAN 135config ACPI_FAN
127 tristate "Fan" 136 tristate "Fan"
128 depends on !IA64_SGI_SN 137 depends on !IA64_SGI_SN
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 65c92e20566d..24eb397e17b8 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -42,7 +42,8 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o
42obj-$(CONFIG_ACPI_BUTTON) += button.o 42obj-$(CONFIG_ACPI_BUTTON) += button.o
43obj-$(CONFIG_ACPI_EC) += ec.o 43obj-$(CONFIG_ACPI_EC) += ec.o
44obj-$(CONFIG_ACPI_FAN) += fan.o 44obj-$(CONFIG_ACPI_FAN) += fan.o
45obj-$(CONFIG_ACPI_VIDEO) += video.o 45obj-$(CONFIG_ACPI_VIDEO) += video.o
46obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o
46obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o 47obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o
47obj-$(CONFIG_ACPI_POWER) += power.o 48obj-$(CONFIG_ACPI_POWER) += power.o
48obj-$(CONFIG_ACPI_PROCESSOR) += processor.o 49obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index a75cb565caeb..a560b1e2da77 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -1204,6 +1204,10 @@ static int __init asus_acpi_init(void)
1204 if (acpi_disabled) 1204 if (acpi_disabled)
1205 return -ENODEV; 1205 return -ENODEV;
1206 1206
1207 if (!acpi_specific_hotkey_enabled){
1208 printk(KERN_ERR "Using generic hotkey driver\n");
1209 return -ENODEV;
1210 }
1207 asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); 1211 asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
1208 if (!asus_proc_dir) { 1212 if (!asus_proc_dir) {
1209 printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); 1213 printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c
new file mode 100644
index 000000000000..0aef9fc449c5
--- /dev/null
+++ b/drivers/acpi/hotkey.c
@@ -0,0 +1,1018 @@
1/*
2 * hotkey.c - ACPI Hotkey Driver ($Revision:$)
3 *
4 * Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
5 *
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/init.h>
27#include <linux/types.h>
28#include <linux/proc_fs.h>
29#include <linux/sched.h>
30#include <linux/kmod.h>
31#include <linux/seq_file.h>
32#include <acpi/acpi_drivers.h>
33#include <acpi/acpi_bus.h>
34#include <asm/uaccess.h>
35
36#define HOTKEY_ACPI_VERSION "0.1"
37
38#define HOTKEY_PROC "hotkey"
39#define HOTKEY_EV_CONFIG "event_config"
40#define HOTKEY_PL_CONFIG "poll_config"
41#define HOTKEY_ACTION "action"
42#define HOTKEY_INFO "info"
43
44#define ACPI_HOTK_NAME "Generic Hotkey Driver"
45#define ACPI_HOTK_CLASS "Hotkey"
46#define ACPI_HOTK_DEVICE_NAME "Hotkey"
47#define ACPI_HOTK_HID "Unknown?"
48#define ACPI_HOTKEY_COMPONENT 0x20000000
49
50#define ACPI_HOTKEY_EVENT 0x1
51#define ACPI_HOTKEY_POLLING 0x2
52#define ACPI_UNDEFINED_EVENT 0xf
53
54#define MAX_CONFIG_RECORD_LEN 80
55#define MAX_NAME_PATH_LEN 80
56#define MAX_CALL_PARM 80
57
58#define IS_EVENT(e) 0xff /* ((e) & 0x40000000) */
59#define IS_POLL(e) 0xff /* (~((e) & 0x40000000)) */
60
61#define _COMPONENT ACPI_HOTKEY_COMPONENT
62ACPI_MODULE_NAME("acpi_hotkey")
63
64 MODULE_AUTHOR("luming.yu@intel.com");
65MODULE_DESCRIPTION(ACPI_HOTK_NAME);
66MODULE_LICENSE("GPL");
67
68/* standardized internal hotkey number/event */
69enum {
70 /* Video Extension event */
71 HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80,
72 HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE,
73 HK_EVENT_CYCLE_DISPLAY_OUTPUT,
74 HK_EVENT_NEXT_DISPLAY_OUTPUT,
75 HK_EVENT_PREVIOUS_DISPLAY_OUTPUT,
76 HK_EVENT_CYCLE_BRIGHTNESS,
77 HK_EVENT_INCREASE_BRIGHTNESS,
78 HK_EVENT_DECREASE_BRIGHTNESS,
79 HK_EVENT_ZERO_BRIGHTNESS,
80 HK_EVENT_DISPLAY_DEVICE_OFF,
81
82 /* Snd Card event */
83 HK_EVENT_VOLUME_MUTE,
84 HK_EVENT_VOLUME_INCLREASE,
85 HK_EVENT_VOLUME_DECREASE,
86
87 /* running state control */
88 HK_EVENT_ENTERRING_S3,
89 HK_EVENT_ENTERRING_S4,
90 HK_EVENT_ENTERRING_S5,
91};
92
93/* procdir we use */
94static struct proc_dir_entry *hotkey_proc_dir;
95static struct proc_dir_entry *hotkey_config;
96static struct proc_dir_entry *hotkey_poll_config;
97static struct proc_dir_entry *hotkey_action;
98static struct proc_dir_entry *hotkey_info;
99
100/* linkage for all type of hotkey */
101struct acpi_hotkey_link {
102 struct list_head entries;
103 int hotkey_type; /* event or polling based hotkey */
104 int hotkey_standard_num; /* standardized hotkey(event) number */
105};
106
107/* event based hotkey */
108struct acpi_event_hotkey {
109 struct acpi_hotkey_link hotkey_link;
110 int flag;
111 acpi_handle bus_handle; /* bus to install notify handler */
112 int external_hotkey_num; /* external hotkey/event number */
113 acpi_handle action_handle; /* acpi handle attached aml action method */
114 char *action_method; /* action method */
115};
116
117/*
118 * There are two ways to poll status
119 * 1. directy call read_xxx method, without any arguments passed in
120 * 2. call write_xxx method, with arguments passed in, you need
121 * the result is saved in acpi_polling_hotkey.poll_result.
122 * anthoer read command through polling interface.
123 *
124 */
125
126/* polling based hotkey */
127struct acpi_polling_hotkey {
128 struct acpi_hotkey_link hotkey_link;
129 int flag;
130 acpi_handle poll_handle; /* acpi handle attached polling method */
131 char *poll_method; /* poll method */
132 acpi_handle action_handle; /* acpi handle attached action method */
133 char *action_method; /* action method */
134 void *poll_result; /* polling_result */
135 struct proc_dir_entry *proc;
136};
137
138/* hotkey object union */
139union acpi_hotkey {
140 struct list_head entries;
141 struct acpi_hotkey_link link;
142 struct acpi_event_hotkey event_hotkey;
143 struct acpi_polling_hotkey poll_hotkey;
144};
145
146/* hotkey object list */
147struct acpi_hotkey_list {
148 struct list_head *entries;
149 int count;
150};
151
152static int auto_hotkey_add(struct acpi_device *device);
153static int auto_hotkey_remove(struct acpi_device *device, int type);
154
155static struct acpi_driver hotkey_driver = {
156 .name = ACPI_HOTK_NAME,
157 .class = ACPI_HOTK_CLASS,
158 .ids = ACPI_HOTK_HID,
159 .ops = {
160 .add = auto_hotkey_add,
161 .remove = auto_hotkey_remove,
162 },
163};
164
165static int hotkey_open_config(struct inode *inode, struct file *file);
166static ssize_t hotkey_write_config(struct file *file,
167 const char __user * buffer,
168 size_t count, loff_t * data);
169static ssize_t hotkey_write_poll_config(struct file *file,
170 const char __user * buffer,
171 size_t count, loff_t * data);
172static int hotkey_info_open_fs(struct inode *inode, struct file *file);
173static int hotkey_action_open_fs(struct inode *inode, struct file *file);
174static ssize_t hotkey_execute_aml_method(struct file *file,
175 const char __user * buffer,
176 size_t count, loff_t * data);
177static int hotkey_config_seq_show(struct seq_file *seq, void *offset);
178static int hotkey_polling_open_fs(struct inode *inode, struct file *file);
179
180/* event based config */
181static struct file_operations hotkey_config_fops = {
182 .open = hotkey_open_config,
183 .read = seq_read,
184 .write = hotkey_write_config,
185 .llseek = seq_lseek,
186 .release = single_release,
187};
188
189/* polling based config */
190static struct file_operations hotkey_poll_config_fops = {
191 .open = hotkey_open_config,
192 .read = seq_read,
193 .write = hotkey_write_poll_config,
194 .llseek = seq_lseek,
195 .release = single_release,
196};
197
198/* hotkey driver info */
199static struct file_operations hotkey_info_fops = {
200 .open = hotkey_info_open_fs,
201 .read = seq_read,
202 .llseek = seq_lseek,
203 .release = single_release,
204};
205
206/* action */
207static struct file_operations hotkey_action_fops = {
208 .open = hotkey_action_open_fs,
209 .read = seq_read,
210 .write = hotkey_execute_aml_method,
211 .llseek = seq_lseek,
212 .release = single_release,
213};
214
215/* polling results */
216static struct file_operations hotkey_polling_fops = {
217 .open = hotkey_polling_open_fs,
218 .read = seq_read,
219 .llseek = seq_lseek,
220 .release = single_release,
221};
222
223struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */
224struct list_head hotkey_entries; /* head of the list of hotkey_list */
225
226static int hotkey_info_seq_show(struct seq_file *seq, void *offset)
227{
228 ACPI_FUNCTION_TRACE("hotkey_info_seq_show");
229
230 seq_printf(seq, "Hotkey generic driver ver: %s", HOTKEY_ACPI_VERSION);
231
232 return_VALUE(0);
233}
234
235static int hotkey_info_open_fs(struct inode *inode, struct file *file)
236{
237 return single_open(file, hotkey_info_seq_show, PDE(inode)->data);
238}
239
240static char *format_result(union acpi_object *object)
241{
242 char *buf = (char *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
243
244 memset(buf, 0, sizeof(union acpi_object));
245
246 /* Now, just support integer type */
247 if (object->type == ACPI_TYPE_INTEGER)
248 sprintf(buf, "%d", (u32) object->integer.value);
249
250 return buf;
251}
252
253static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
254{
255 struct acpi_polling_hotkey *poll_hotkey =
256 (struct acpi_polling_hotkey *)seq->private;
257
258 ACPI_FUNCTION_TRACE("hotkey_polling_seq_show");
259
260 if (poll_hotkey->poll_result)
261 seq_printf(seq, "%s", format_result(poll_hotkey->poll_result));
262
263 return_VALUE(0);
264}
265
266static int hotkey_polling_open_fs(struct inode *inode, struct file *file)
267{
268 return single_open(file, hotkey_polling_seq_show, PDE(inode)->data);
269}
270
271static int hotkey_action_open_fs(struct inode *inode, struct file *file)
272{
273 return single_open(file, hotkey_info_seq_show, PDE(inode)->data);
274}
275
276/* Mapping external hotkey number to standardized hotkey event num */
277static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list)
278{
279 struct list_head *entries, *next;
280 int val = 0;
281
282 ACPI_FUNCTION_TRACE("hotkey_get_internal_event");
283
284 list_for_each_safe(entries, next, list->entries) {
285 union acpi_hotkey *key =
286 container_of(entries, union acpi_hotkey, entries);
287 if (key->link.hotkey_type == ACPI_HOTKEY_EVENT
288 && key->event_hotkey.external_hotkey_num == event)
289 val = key->link.hotkey_standard_num;
290 else
291 val = -1;
292 }
293
294 return_VALUE(val);
295}
296
297static void
298acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data)
299{
300 struct acpi_device *device = NULL;
301 u32 internal_event;
302
303 ACPI_FUNCTION_TRACE("acpi_hotkey_notify_handler");
304
305 if (acpi_bus_get_device(handle, &device))
306 return_VOID;
307
308 internal_event = hotkey_get_internal_event(event, &global_hotkey_list);
309 acpi_bus_generate_event(device, event, 0);
310
311 return_VOID;
312}
313
314/* Need to invent automatically hotkey add method */
315static int auto_hotkey_add(struct acpi_device *device)
316{
317 /* Implement me */
318 return 0;
319}
320
321/* Need to invent automatically hotkey remove method */
322static int auto_hotkey_remove(struct acpi_device *device, int type)
323{
324 /* Implement me */
325 return 0;
326}
327
328/* Create a proc file for each polling method */
329static int create_polling_proc(union acpi_hotkey *device)
330{
331 struct proc_dir_entry *proc;
332
333 ACPI_FUNCTION_TRACE("create_polling_proc");
334 mode_t mode = S_IFREG | S_IRUGO | S_IWUGO;
335
336 proc = create_proc_entry(device->poll_hotkey.action_method,
337 mode, hotkey_proc_dir);
338
339 if (!proc) {
340 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
341 "Hotkey: Unable to create %s entry\n",
342 device->poll_hotkey.poll_method));
343 return_VALUE(-ENODEV);
344 } else {
345 proc->proc_fops = &hotkey_polling_fops;
346 proc->owner = THIS_MODULE;
347 proc->data = device;
348 proc->uid = 0;
349 proc->gid = 0;
350 device->poll_hotkey.proc = proc;
351 }
352 return_VALUE(0);
353}
354
355static int is_valid_acpi_path(const char *pathname)
356{
357 acpi_handle handle;
358 acpi_status status;
359 ACPI_FUNCTION_TRACE("is_valid_acpi_path");
360
361 status = acpi_get_handle(NULL, (char *)pathname, &handle);
362 return_VALUE(!ACPI_FAILURE(status));
363}
364
365static int is_valid_hotkey(union acpi_hotkey *device)
366{
367 ACPI_FUNCTION_TRACE("is_valid_hotkey");
368 /* Implement valid check */
369 return_VALUE(1);
370}
371
372static int hotkey_add(union acpi_hotkey *device)
373{
374 int status = 0;
375 struct acpi_device *dev = NULL;
376
377 ACPI_FUNCTION_TRACE("hotkey_add");
378
379 if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) {
380 status =
381 acpi_bus_get_device(device->event_hotkey.bus_handle, &dev);
382 if (status)
383 return_VALUE(status);
384
385 status = acpi_install_notify_handler(dev->handle,
386 ACPI_SYSTEM_NOTIFY,
387 acpi_hotkey_notify_handler,
388 device);
389 } else /* Add polling hotkey */
390 create_polling_proc(device);
391
392 global_hotkey_list.count++;
393
394 list_add_tail(&device->link.entries, global_hotkey_list.entries);
395
396 return_VALUE(status);
397}
398
399static int hotkey_remove(union acpi_hotkey *device)
400{
401 struct list_head *entries, *next;
402
403 ACPI_FUNCTION_TRACE("hotkey_remove");
404
405 list_for_each_safe(entries, next, global_hotkey_list.entries) {
406 union acpi_hotkey *key =
407 container_of(entries, union acpi_hotkey, entries);
408 if (key->link.hotkey_standard_num ==
409 device->link.hotkey_standard_num) {
410 list_del(&key->link.entries);
411 remove_proc_entry(key->poll_hotkey.action_method,
412 hotkey_proc_dir);
413 global_hotkey_list.count--;
414 break;
415 }
416 }
417 return_VALUE(0);
418}
419
420static void hotkey_update(union acpi_hotkey *key)
421{
422 struct list_head *entries, *next;
423
424 ACPI_FUNCTION_TRACE("hotkey_update");
425
426 list_for_each_safe(entries, next, global_hotkey_list.entries) {
427 union acpi_hotkey *key =
428 container_of(entries, union acpi_hotkey, entries);
429 if (key->link.hotkey_standard_num ==
430 key->link.hotkey_standard_num) {
431 key->event_hotkey.bus_handle =
432 key->event_hotkey.bus_handle;
433 key->event_hotkey.external_hotkey_num =
434 key->event_hotkey.external_hotkey_num;
435 key->event_hotkey.action_handle =
436 key->event_hotkey.action_handle;
437 key->event_hotkey.action_method =
438 key->event_hotkey.action_method;
439 break;
440 }
441 }
442
443 return_VOID;
444}
445
446static void free_hotkey_device(union acpi_hotkey *key)
447{
448 struct acpi_device *dev;
449 int status;
450
451 ACPI_FUNCTION_TRACE("free_hotkey_device");
452
453 if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
454 status =
455 acpi_bus_get_device(key->event_hotkey.bus_handle, &dev);
456 if (dev->handle)
457 acpi_remove_notify_handler(dev->handle,
458 ACPI_SYSTEM_NOTIFY,
459 acpi_hotkey_notify_handler);
460 } else
461 remove_proc_entry(key->poll_hotkey.action_method,
462 hotkey_proc_dir);
463 kfree(key);
464 return_VOID;
465}
466
467static int
468init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str,
469 char *method, int std_num, int external_num)
470{
471 ACPI_FUNCTION_TRACE("init_hotkey_device");
472
473 key->link.hotkey_type = ACPI_HOTKEY_EVENT;
474 key->link.hotkey_standard_num = std_num;
475 key->event_hotkey.flag = 0;
476 if (is_valid_acpi_path(bus_str))
477 acpi_get_handle((acpi_handle) 0,
478 bus_str, &(key->event_hotkey.bus_handle));
479 else
480 return_VALUE(-ENODEV);
481 key->event_hotkey.external_hotkey_num = external_num;
482 if (is_valid_acpi_path(action_str))
483 acpi_get_handle((acpi_handle) 0,
484 action_str, &(key->event_hotkey.action_handle));
485 key->event_hotkey.action_method = kmalloc(sizeof(method), GFP_KERNEL);
486 strcpy(key->event_hotkey.action_method, method);
487
488 return_VALUE(!is_valid_hotkey(key));
489}
490
491static int
492init_poll_hotkey_device(union acpi_hotkey *key,
493 char *poll_str,
494 char *poll_method,
495 char *action_str, char *action_method, int std_num)
496{
497 ACPI_FUNCTION_TRACE("init_poll_hotkey_device");
498
499 key->link.hotkey_type = ACPI_HOTKEY_POLLING;
500 key->link.hotkey_standard_num = std_num;
501 key->poll_hotkey.flag = 0;
502 if (is_valid_acpi_path(poll_str))
503 acpi_get_handle((acpi_handle) 0,
504 poll_str, &(key->poll_hotkey.poll_handle));
505 else
506 return_VALUE(-ENODEV);
507 key->poll_hotkey.poll_method = poll_method;
508 if (is_valid_acpi_path(action_str))
509 acpi_get_handle((acpi_handle) 0,
510 action_str, &(key->poll_hotkey.action_handle));
511 key->poll_hotkey.action_method =
512 kmalloc(sizeof(action_method), GFP_KERNEL);
513 strcpy(key->poll_hotkey.action_method, action_method);
514 key->poll_hotkey.poll_result =
515 (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
516 return_VALUE(is_valid_hotkey(key));
517}
518
519static int check_hotkey_valid(union acpi_hotkey *key,
520 struct acpi_hotkey_list *list)
521{
522 ACPI_FUNCTION_TRACE("check_hotkey_valid");
523 return_VALUE(0);
524}
525
526static int hotkey_open_config(struct inode *inode, struct file *file)
527{
528 ACPI_FUNCTION_TRACE("hotkey_open_config");
529 return_VALUE(single_open
530 (file, hotkey_config_seq_show, PDE(inode)->data));
531}
532
533static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
534{
535 struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
536 struct list_head *entries, *next;
537 char bus_name[ACPI_PATHNAME_MAX] = { 0 };
538 char action_name[ACPI_PATHNAME_MAX] = { 0 };
539 struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
540 struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name };
541
542 ACPI_FUNCTION_TRACE(("hotkey_config_seq_show"));
543
544 if (!hotkey_list)
545 goto end;
546
547 list_for_each_safe(entries, next, hotkey_list->entries) {
548 union acpi_hotkey *key =
549 container_of(entries, union acpi_hotkey, entries);
550 if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
551 acpi_get_name(key->event_hotkey.bus_handle,
552 ACPI_NAME_TYPE_MAX, &bus);
553 acpi_get_name(key->event_hotkey.action_handle,
554 ACPI_NAME_TYPE_MAX, &act);
555 seq_printf(seq, "%s:%s:%s:%d:%d", bus_name,
556 action_name,
557 key->event_hotkey.action_method,
558 key->link.hotkey_standard_num,
559 key->event_hotkey.external_hotkey_num);
560 } /* ACPI_HOTKEY_POLLING */
561 else {
562 acpi_get_name(key->poll_hotkey.poll_handle,
563 ACPI_NAME_TYPE_MAX, &bus);
564 acpi_get_name(key->poll_hotkey.action_handle,
565 ACPI_NAME_TYPE_MAX, &act);
566 seq_printf(seq, "%s:%s:%s:%s:%d", bus_name,
567 key->poll_hotkey.poll_method,
568 action_name,
569 key->poll_hotkey.action_method,
570 key->link.hotkey_standard_num);
571 }
572 }
573 seq_puts(seq, "\n");
574 end:
575 return_VALUE(0);
576}
577
578static int
579get_parms(char *config_record,
580 int *cmd,
581 char *bus_handle,
582 char *bus_method,
583 char *action_handle,
584 char *method, int *internal_event_num, int *external_event_num)
585{
586 char *tmp, *tmp1;
587 ACPI_FUNCTION_TRACE(("get_parms"));
588
589 sscanf(config_record, "%d", cmd);
590
591 tmp = strchr(config_record, ':');
592 tmp++;
593 tmp1 = strchr(tmp, ':');
594 strncpy(bus_handle, tmp, tmp1 - tmp);
595 bus_handle[tmp1 - tmp] = 0;
596
597 tmp = tmp1;
598 tmp++;
599 tmp1 = strchr(tmp, ':');
600 strncpy(bus_method, tmp, tmp1 - tmp);
601 bus_method[tmp1 - tmp] = 0;
602
603 tmp = tmp1;
604 tmp++;
605 tmp1 = strchr(tmp, ':');
606 strncpy(action_handle, tmp, tmp1 - tmp);
607 action_handle[tmp1 - tmp] = 0;
608
609 tmp = tmp1;
610 tmp++;
611 tmp1 = strchr(tmp, ':');
612 strncpy(method, tmp, tmp1 - tmp);
613 method[tmp1 - tmp] = 0;
614
615 sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num);
616 return_VALUE(6);
617}
618
619/* count is length for one input record */
620static ssize_t hotkey_write_config(struct file *file,
621 const char __user * buffer,
622 size_t count, loff_t * data)
623{
624 struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
625 char config_record[MAX_CONFIG_RECORD_LEN];
626 char bus_handle[MAX_NAME_PATH_LEN];
627 char bus_method[MAX_NAME_PATH_LEN];
628 char action_handle[MAX_NAME_PATH_LEN];
629 char method[20];
630 int cmd, internal_event_num, external_event_num;
631 int ret = 0;
632 union acpi_hotkey *key = NULL;
633
634 ACPI_FUNCTION_TRACE(("hotkey_write_config"));
635
636 if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) {
637 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n"));
638 return_VALUE(-EINVAL);
639 }
640
641 if (copy_from_user(config_record, buffer, count)) {
642 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n"));
643 return_VALUE(-EINVAL);
644 }
645 config_record[count] = '\0';
646
647 ret = get_parms(config_record,
648 &cmd,
649 bus_handle,
650 bus_method,
651 action_handle,
652 method, &internal_event_num, &external_event_num);
653 if (ret != 6) {
654 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
655 "Invalid data format ret=%d\n", ret));
656 return_VALUE(-EINVAL);
657 }
658
659 key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
660 ret = init_hotkey_device(key, bus_handle, action_handle, method,
661 internal_event_num, external_event_num);
662
663 if (ret || check_hotkey_valid(key, hotkey_list)) {
664 kfree(key);
665 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n"));
666 return_VALUE(-EINVAL);
667 }
668 switch (cmd) {
669 case 0:
670 hotkey_add(key);
671 break;
672 case 1:
673 hotkey_remove(key);
674 free_hotkey_device(key);
675 break;
676 case 2:
677 hotkey_update(key);
678 break;
679 default:
680 break;
681 }
682 return_VALUE(count);
683}
684
685/* count is length for one input record */
686static ssize_t hotkey_write_poll_config(struct file *file,
687 const char __user * buffer,
688 size_t count, loff_t * data)
689{
690 struct seq_file *m = (struct seq_file *)file->private_data;
691 struct acpi_hotkey_list *hotkey_list =
692 (struct acpi_hotkey_list *)m->private;
693
694 char config_record[MAX_CONFIG_RECORD_LEN];
695 char polling_handle[MAX_NAME_PATH_LEN];
696 char action_handle[MAX_NAME_PATH_LEN];
697 char poll_method[20], action_method[20];
698 int ret, internal_event_num, cmd, external_event_num;
699 union acpi_hotkey *key = NULL;
700
701 ACPI_FUNCTION_TRACE("hotkey_write_poll_config");
702
703 if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) {
704 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n"));
705 return_VALUE(-EINVAL);
706 }
707
708 if (copy_from_user(config_record, buffer, count)) {
709 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n"));
710 return_VALUE(-EINVAL);
711 }
712 config_record[count] = '\0';
713
714 ret = get_parms(config_record,
715 &cmd,
716 polling_handle,
717 poll_method,
718 action_handle,
719 action_method,
720 &internal_event_num, &external_event_num);
721
722 if (ret != 6) {
723 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
724 return_VALUE(-EINVAL);
725 }
726
727 key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
728 ret = init_poll_hotkey_device(key, polling_handle, poll_method,
729 action_handle, action_method,
730 internal_event_num);
731 if (ret || check_hotkey_valid(key, hotkey_list)) {
732 kfree(key);
733 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n"));
734 return_VALUE(-EINVAL);
735 }
736 switch (cmd) {
737 case 0:
738 hotkey_add(key);
739 break;
740 case 1:
741 hotkey_remove(key);
742 break;
743 case 2:
744 hotkey_update(key);
745 break;
746 default:
747 break;
748 }
749 return_VALUE(count);
750}
751
752/*
753 * This function evaluates an ACPI method, given an int as parameter, the
754 * method is searched within the scope of the handle, can be NULL. The output
755 * of the method is written is output, which can also be NULL
756 *
757 * returns 1 if write is successful, 0 else.
758 */
759static int write_acpi_int(acpi_handle handle, const char *method, int val,
760 struct acpi_buffer *output)
761{
762 struct acpi_object_list params; /* list of input parameters (an int here) */
763 union acpi_object in_obj; /* the only param we use */
764 acpi_status status;
765
766 ACPI_FUNCTION_TRACE("write_acpi_int");
767 params.count = 1;
768 params.pointer = &in_obj;
769 in_obj.type = ACPI_TYPE_INTEGER;
770 in_obj.integer.value = val;
771
772 status = acpi_evaluate_object(handle, (char *)method, &params, output);
773
774 return_VALUE(status == AE_OK);
775}
776
777static int read_acpi_int(acpi_handle handle, const char *method, int *val)
778{
779 struct acpi_buffer output;
780 union acpi_object out_obj;
781 acpi_status status;
782
783 ACPI_FUNCTION_TRACE("read_acpi_int");
784 output.length = sizeof(out_obj);
785 output.pointer = &out_obj;
786
787 status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
788 *val = out_obj.integer.value;
789 return_VALUE((status == AE_OK)
790 && (out_obj.type == ACPI_TYPE_INTEGER));
791}
792
793static acpi_handle
794get_handle_from_hotkeylist(struct acpi_hotkey_list *hotkey_list, int event_num)
795{
796 struct list_head *entries, *next;
797
798 list_for_each_safe(entries, next, hotkey_list->entries) {
799 union acpi_hotkey *key =
800 container_of(entries, union acpi_hotkey, entries);
801 if (key->link.hotkey_type == ACPI_HOTKEY_EVENT
802 && key->link.hotkey_standard_num == event_num) {
803 return (key->event_hotkey.action_handle);
804 }
805 }
806 return (NULL);
807}
808
809static
810char *get_method_from_hotkeylist(struct acpi_hotkey_list *hotkey_list,
811 int event_num)
812{
813 struct list_head *entries, *next;
814
815 list_for_each_safe(entries, next, hotkey_list->entries) {
816 union acpi_hotkey *key =
817 container_of(entries, union acpi_hotkey, entries);
818
819 if (key->link.hotkey_type == ACPI_HOTKEY_EVENT &&
820 key->link.hotkey_standard_num == event_num)
821 return (key->event_hotkey.action_method);
822 }
823 return (NULL);
824}
825
826static struct acpi_polling_hotkey *get_hotkey_by_event(struct
827 acpi_hotkey_list
828 *hotkey_list, int event)
829{
830 struct list_head *entries, *next;
831
832 list_for_each_safe(entries, next, hotkey_list->entries) {
833 union acpi_hotkey *key =
834 container_of(entries, union acpi_hotkey, entries);
835 if (key->link.hotkey_type == ACPI_HOTKEY_POLLING
836 && key->link.hotkey_standard_num == event) {
837 return (&key->poll_hotkey);
838 }
839 }
840 return (NULL);
841}
842
843/*
844 * user call AML method interface:
845 * Call convention:
846 * echo "event_num: arg type : value"
847 * example: echo "1:1:30" > /proc/acpi/action
848 * Just support 1 integer arg passing to AML method
849 */
850
851static ssize_t hotkey_execute_aml_method(struct file *file,
852 const char __user * buffer,
853 size_t count, loff_t * data)
854{
855 struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
856 char arg[MAX_CALL_PARM];
857 int event, type, value;
858
859 char *method;
860 acpi_handle handle;
861
862 ACPI_FUNCTION_TRACE("hotkey_execte_aml_method");
863
864 if (!hotkey_list || count > MAX_CALL_PARM) {
865 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 1"));
866 return_VALUE(-EINVAL);
867 }
868
869 if (copy_from_user(arg, buffer, count)) {
870 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 2"));
871 return_VALUE(-EINVAL);
872 }
873
874 arg[count] = '\0';
875
876 if (sscanf(arg, "%d:%d:%d", &event, &type, &value) != 3) {
877 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 3"));
878 return_VALUE(-EINVAL);
879 }
880
881 if (type == ACPI_TYPE_INTEGER) {
882 handle = get_handle_from_hotkeylist(hotkey_list, event);
883 method = (char *)get_method_from_hotkeylist(hotkey_list, event);
884 if (IS_EVENT(event))
885 write_acpi_int(handle, method, value, NULL);
886 else if (IS_POLL(event)) {
887 struct acpi_polling_hotkey *key;
888 key = (struct acpi_polling_hotkey *)
889 get_hotkey_by_event(hotkey_list, event);
890 read_acpi_int(handle, method, key->poll_result);
891 }
892 } else {
893 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Not supported"));
894 return_VALUE(-EINVAL);
895 }
896
897 return_VALUE(count);
898}
899
900static int __init hotkey_init(void)
901{
902 int result;
903 mode_t mode = S_IFREG | S_IRUGO | S_IWUGO;
904
905 ACPI_FUNCTION_TRACE("hotkey_init");
906
907 if (acpi_disabled)
908 return -ENODEV;
909
910 if (acpi_specific_hotkey_enabled) {
911 printk("Using specific hotkey driver\n");
912 return -ENODEV;
913 }
914
915 hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir);
916 if (!hotkey_proc_dir) {
917 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
918 "Hotkey: Unable to create %s entry\n",
919 HOTKEY_PROC));
920 return (-ENODEV);
921 }
922 hotkey_proc_dir->owner = THIS_MODULE;
923
924 hotkey_config =
925 create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir);
926 if (!hotkey_config) {
927 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
928 "Hotkey: Unable to create %s entry\n",
929 HOTKEY_EV_CONFIG));
930 return (-ENODEV);
931 } else {
932 hotkey_config->proc_fops = &hotkey_config_fops;
933 hotkey_config->data = &global_hotkey_list;
934 hotkey_config->owner = THIS_MODULE;
935 hotkey_config->uid = 0;
936 hotkey_config->gid = 0;
937 }
938
939 hotkey_poll_config =
940 create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir);
941 if (!hotkey_poll_config) {
942 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
943 "Hotkey: Unable to create %s entry\n",
944 HOTKEY_EV_CONFIG));
945 return (-ENODEV);
946 } else {
947 hotkey_poll_config->proc_fops = &hotkey_poll_config_fops;
948 hotkey_poll_config->data = &global_hotkey_list;
949 hotkey_poll_config->owner = THIS_MODULE;
950 hotkey_poll_config->uid = 0;
951 hotkey_poll_config->gid = 0;
952 }
953
954 hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir);
955 if (!hotkey_action) {
956 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
957 "Hotkey: Unable to create %s entry\n",
958 HOTKEY_ACTION));
959 return (-ENODEV);
960 } else {
961 hotkey_action->proc_fops = &hotkey_action_fops;
962 hotkey_action->owner = THIS_MODULE;
963 hotkey_action->uid = 0;
964 hotkey_action->gid = 0;
965 }
966
967 hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir);
968 if (!hotkey_info) {
969 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
970 "Hotkey: Unable to create %s entry\n",
971 HOTKEY_INFO));
972 return (-ENODEV);
973 } else {
974 hotkey_info->proc_fops = &hotkey_info_fops;
975 hotkey_info->owner = THIS_MODULE;
976 hotkey_info->uid = 0;
977 hotkey_info->gid = 0;
978 }
979
980 result = acpi_bus_register_driver(&hotkey_driver);
981 if (result < 0) {
982 remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
983 return (-ENODEV);
984 }
985 global_hotkey_list.count = 0;
986 global_hotkey_list.entries = &hotkey_entries;
987
988 INIT_LIST_HEAD(&hotkey_entries);
989
990 return (0);
991}
992
993static void __exit hotkey_exit(void)
994{
995 struct list_head *entries, *next;
996
997 ACPI_FUNCTION_TRACE("hotkey_remove");
998
999 list_for_each_safe(entries, next, global_hotkey_list.entries) {
1000 union acpi_hotkey *key =
1001 container_of(entries, union acpi_hotkey, entries);
1002
1003 acpi_os_wait_events_complete(NULL);
1004 list_del(&key->link.entries);
1005 global_hotkey_list.count--;
1006 free_hotkey_device(key);
1007 }
1008 acpi_bus_unregister_driver(&hotkey_driver);
1009 remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir);
1010 remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir);
1011 remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir);
1012 remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir);
1013 remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
1014 return;
1015}
1016
1017module_init(hotkey_init);
1018module_exit(hotkey_exit);
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 0fb731a470dc..6c8291c3e774 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -1185,6 +1185,10 @@ static int __init acpi_ibm_init(void)
1185 if (acpi_disabled) 1185 if (acpi_disabled)
1186 return -ENODEV; 1186 return -ENODEV;
1187 1187
1188 if (!acpi_specific_hotkey_enabled){
1189 printk(IBM_ERR "Using generic hotkey driver\n");
1190 return -ENODEV;
1191 }
1188 /* these handles are required */ 1192 /* these handles are required */
1189 if (IBM_HANDLE_INIT(ec, 1) < 0 || 1193 if (IBM_HANDLE_INIT(ec, 1) < 0 ||
1190 IBM_HANDLE_INIT(hkey, 1) < 0 || 1194 IBM_HANDLE_INIT(hkey, 1) < 0 ||
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 5a9128de6226..bdd9f37f8101 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -71,6 +71,9 @@ EXPORT_SYMBOL(acpi_in_debugger);
71extern char line_buf[80]; 71extern char line_buf[80];
72#endif /*ENABLE_DEBUGGER*/ 72#endif /*ENABLE_DEBUGGER*/
73 73
74int acpi_specific_hotkey_enabled;
75EXPORT_SYMBOL(acpi_specific_hotkey_enabled);
76
74static unsigned int acpi_irq_irq; 77static unsigned int acpi_irq_irq;
75static acpi_osd_handler acpi_irq_handler; 78static acpi_osd_handler acpi_irq_handler;
76static void *acpi_irq_context; 79static void *acpi_irq_context;
@@ -1152,6 +1155,15 @@ acpi_wake_gpes_always_on_setup(char *str)
1152 1155
1153__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); 1156__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
1154 1157
1158int __init
1159acpi_hotkey_setup(char *str)
1160{
1161 acpi_specific_hotkey_enabled = TRUE;
1162 return 1;
1163}
1164
1165__setup("acpi_specific_hotkey", acpi_hotkey_setup);
1166
1155/* 1167/*
1156 * max_cstate is defined in the base kernel so modules can 1168 * max_cstate is defined in the base kernel so modules can
1157 * change it w/o depending on the state of the processor module. 1169 * change it w/o depending on the state of the processor module.
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index c84997c9f964..bed8e53a5ee8 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -529,6 +529,11 @@ toshiba_acpi_init(void)
529 529
530 if (acpi_disabled) 530 if (acpi_disabled)
531 return -ENODEV; 531 return -ENODEV;
532
533 if (!acpi_specific_hotkey_enabled){
534 printk(MY_INFO "Using generic hotkey driver\n");
535 return -ENODEV;
536 }
532 /* simple device detection: look for HCI method */ 537 /* simple device detection: look for HCI method */
533 if (is_valid_acpi_path(METHOD_HCI_1)) 538 if (is_valid_acpi_path(METHOD_HCI_1))
534 method_hci = METHOD_HCI_1; 539 method_hci = METHOD_HCI_1;
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index c62e92ec43b2..e00d9289201b 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -108,5 +108,10 @@ int acpi_ec_ecdt_probe (void);
108 108
109int acpi_processor_set_thermal_limit(acpi_handle handle, int type); 109int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
110 110
111/* --------------------------------------------------------------------------
112 Hot Keys
113 -------------------------------------------------------------------------- */
114
115extern int acpi_specific_hotkey_enabled;
111 116
112#endif /*__ACPI_DRIVERS_H__*/ 117#endif /*__ACPI_DRIVERS_H__*/