Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Luming Yu and committed by
Len Brown
fb9802fa d58da590

+1094 -1
+35
Documentation/acpi-hotkey.txt
··· 1 + driver/acpi/hotkey.c implement: 2 + 1. /proc/acpi/hotkey/event_config 3 + (event based hotkey or event config interface): 4 + a. add a event based hotkey(event) : 5 + echo "0:bus::action:method:num:num" > event_config 6 + 7 + b. delete a event based hotkey(event): 8 + echo "1:::::num:num" > event_config 9 + 10 + c. modify a event based hotkey(event): 11 + echo "2:bus::action:method:num:num" > event_config 12 + 13 + 2. /proc/acpi/hotkey/poll_config 14 + (polling based hotkey or event config interface): 15 + a.add a polling based hotkey(event) : 16 + echo "0:bus:method:action:method:num" > poll_config 17 + this adding command will create a proc file 18 + /proc/acpi/hotkey/method, which is used to get 19 + result of polling. 20 + 21 + b.delete a polling based hotkey(event): 22 + echo "1:::::num" > event_config 23 + 24 + c.modify a polling based hotkey(event): 25 + echo "2:bus:method:action:method:num" > poll_config 26 + 27 + 3./proc/acpi/hotkey/action 28 + (interface to call aml method associated with a 29 + specific hotkey(event)) 30 + echo "event_num:event_type:event_argument" > 31 + /proc/acpi/hotkey/action. 32 + The result of the execution of this aml method is 33 + attached to /proc/acpi/hotkey/poll_method, which is dnyamically 34 + created. Please use command "cat /proc/acpi/hotkey/polling_method" 35 + to retrieve it.
+9
drivers/acpi/Kconfig
··· 123 123 Note that this is an ref. implementation only. It may or may not work 124 124 for your integrated video device. 125 125 126 + config 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 + 126 135 config ACPI_FAN 127 136 tristate "Fan" 128 137 depends on !IA64_SGI_SN
+2 -1
drivers/acpi/Makefile
··· 42 42 obj-$(CONFIG_ACPI_BUTTON) += button.o 43 43 obj-$(CONFIG_ACPI_EC) += ec.o 44 44 obj-$(CONFIG_ACPI_FAN) += fan.o 45 - obj-$(CONFIG_ACPI_VIDEO) += video.o 45 + obj-$(CONFIG_ACPI_VIDEO) += video.o 46 + obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o 46 47 obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o 47 48 obj-$(CONFIG_ACPI_POWER) += power.o 48 49 obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
+4
drivers/acpi/asus_acpi.c
··· 1204 1204 if (acpi_disabled) 1205 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 1211 asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); 1208 1212 if (!asus_proc_dir) { 1209 1213 printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
+1018
drivers/acpi/hotkey.c
··· 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 62 + ACPI_MODULE_NAME("acpi_hotkey") 63 + 64 + MODULE_AUTHOR("luming.yu@intel.com"); 65 + MODULE_DESCRIPTION(ACPI_HOTK_NAME); 66 + MODULE_LICENSE("GPL"); 67 + 68 + /* standardized internal hotkey number/event */ 69 + enum { 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 */ 94 + static struct proc_dir_entry *hotkey_proc_dir; 95 + static struct proc_dir_entry *hotkey_config; 96 + static struct proc_dir_entry *hotkey_poll_config; 97 + static struct proc_dir_entry *hotkey_action; 98 + static struct proc_dir_entry *hotkey_info; 99 + 100 + /* linkage for all type of hotkey */ 101 + struct 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 */ 108 + struct 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 */ 127 + struct 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 */ 139 + union 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 */ 147 + struct acpi_hotkey_list { 148 + struct list_head *entries; 149 + int count; 150 + }; 151 + 152 + static int auto_hotkey_add(struct acpi_device *device); 153 + static int auto_hotkey_remove(struct acpi_device *device, int type); 154 + 155 + static 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 + 165 + static int hotkey_open_config(struct inode *inode, struct file *file); 166 + static ssize_t hotkey_write_config(struct file *file, 167 + const char __user * buffer, 168 + size_t count, loff_t * data); 169 + static ssize_t hotkey_write_poll_config(struct file *file, 170 + const char __user * buffer, 171 + size_t count, loff_t * data); 172 + static int hotkey_info_open_fs(struct inode *inode, struct file *file); 173 + static int hotkey_action_open_fs(struct inode *inode, struct file *file); 174 + static ssize_t hotkey_execute_aml_method(struct file *file, 175 + const char __user * buffer, 176 + size_t count, loff_t * data); 177 + static int hotkey_config_seq_show(struct seq_file *seq, void *offset); 178 + static int hotkey_polling_open_fs(struct inode *inode, struct file *file); 179 + 180 + /* event based config */ 181 + static 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 */ 190 + static 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 */ 199 + static 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 */ 207 + static 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 */ 216 + static 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 + 223 + struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */ 224 + struct list_head hotkey_entries; /* head of the list of hotkey_list */ 225 + 226 + static 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 + 235 + static 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 + 240 + static 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 + 253 + static 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 + 266 + static 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 + 271 + static 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 */ 277 + static 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 + 297 + static void 298 + acpi_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 */ 315 + static 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 */ 322 + static 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 */ 329 + static 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 + 355 + static 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 + 365 + static 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 + 372 + static 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 + 399 + static 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 + 420 + static 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 + 446 + static 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 + 467 + static int 468 + init_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 + 491 + static int 492 + init_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 + 519 + static 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 + 526 + static 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 + 533 + static 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 + 578 + static int 579 + get_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 */ 620 + static 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 */ 686 + static 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 + */ 759 + static 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 + 777 + static 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 + 793 + static acpi_handle 794 + get_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 + 809 + static 810 + char *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 + 826 + static 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 + 851 + static 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 + 900 + static 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 + 993 + static 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 + 1017 + module_init(hotkey_init); 1018 + module_exit(hotkey_exit);
+4
drivers/acpi/ibm_acpi.c
··· 1185 1185 if (acpi_disabled) 1186 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 1192 /* these handles are required */ 1189 1193 if (IBM_HANDLE_INIT(ec, 1) < 0 || 1190 1194 IBM_HANDLE_INIT(hkey, 1) < 0 ||
+12
drivers/acpi/osl.c
··· 71 71 extern char line_buf[80]; 72 72 #endif /*ENABLE_DEBUGGER*/ 73 73 74 + int acpi_specific_hotkey_enabled; 75 + EXPORT_SYMBOL(acpi_specific_hotkey_enabled); 76 + 74 77 static unsigned int acpi_irq_irq; 75 78 static acpi_osd_handler acpi_irq_handler; 76 79 static void *acpi_irq_context; ··· 1154 1151 } 1155 1152 1156 1153 __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); 1154 + 1155 + int __init 1156 + acpi_hotkey_setup(char *str) 1157 + { 1158 + acpi_specific_hotkey_enabled = TRUE; 1159 + return 1; 1160 + } 1161 + 1162 + __setup("acpi_specific_hotkey", acpi_hotkey_setup); 1157 1163 1158 1164 /* 1159 1165 * max_cstate is defined in the base kernel so modules can
+5
drivers/acpi/toshiba_acpi.c
··· 529 529 530 530 if (acpi_disabled) 531 531 return -ENODEV; 532 + 533 + if (!acpi_specific_hotkey_enabled){ 534 + printk(MY_INFO "Using generic hotkey driver\n"); 535 + return -ENODEV; 536 + } 532 537 /* simple device detection: look for HCI method */ 533 538 if (is_valid_acpi_path(METHOD_HCI_1)) 534 539 method_hci = METHOD_HCI_1;
+5
include/acpi/acpi_drivers.h
··· 108 108 109 109 int acpi_processor_set_thermal_limit(acpi_handle handle, int type); 110 110 111 + /* -------------------------------------------------------------------------- 112 + Hot Keys 113 + -------------------------------------------------------------------------- */ 114 + 115 + extern int acpi_specific_hotkey_enabled; 111 116 112 117 #endif /*__ACPI_DRIVERS_H__*/