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

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.15-rc4 1126 lines 30 kB view raw
1/* 2 * hotkey.c - ACPI Hotkey Driver ($Revision: 0.2 $) 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 RESULT_STR_LEN 80 55 56#define ACTION_METHOD 0 57#define POLL_METHOD 1 58 59#define IS_EVENT(e) ((e) <= 10000 && (e) >0) 60#define IS_POLL(e) ((e) > 10000) 61#define IS_OTHERS(e) ((e)<=0 || (e)>=20000) 62#define _COMPONENT ACPI_HOTKEY_COMPONENT 63ACPI_MODULE_NAME("acpi_hotkey") 64 65 MODULE_AUTHOR("luming.yu@intel.com"); 66MODULE_DESCRIPTION(ACPI_HOTK_NAME); 67MODULE_LICENSE("GPL"); 68 69/* standardized internal hotkey number/event */ 70enum { 71 /* Video Extension event */ 72 HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80, 73 HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE, 74 HK_EVENT_CYCLE_DISPLAY_OUTPUT, 75 HK_EVENT_NEXT_DISPLAY_OUTPUT, 76 HK_EVENT_PREVIOUS_DISPLAY_OUTPUT, 77 HK_EVENT_CYCLE_BRIGHTNESS, 78 HK_EVENT_INCREASE_BRIGHTNESS, 79 HK_EVENT_DECREASE_BRIGHTNESS, 80 HK_EVENT_ZERO_BRIGHTNESS, 81 HK_EVENT_DISPLAY_DEVICE_OFF, 82 83 /* Snd Card event */ 84 HK_EVENT_VOLUME_MUTE, 85 HK_EVENT_VOLUME_INCLREASE, 86 HK_EVENT_VOLUME_DECREASE, 87 88 /* running state control */ 89 HK_EVENT_ENTERRING_S3, 90 HK_EVENT_ENTERRING_S4, 91 HK_EVENT_ENTERRING_S5, 92}; 93 94/* procdir we use */ 95static struct proc_dir_entry *hotkey_proc_dir; 96static struct proc_dir_entry *hotkey_config; 97static struct proc_dir_entry *hotkey_poll_config; 98static struct proc_dir_entry *hotkey_action; 99static struct proc_dir_entry *hotkey_info; 100 101/* linkage for all type of hotkey */ 102struct acpi_hotkey_link { 103 struct list_head entries; 104 int hotkey_type; /* event or polling based hotkey */ 105 int hotkey_standard_num; /* standardized hotkey(event) number */ 106}; 107 108/* event based hotkey */ 109struct acpi_event_hotkey { 110 struct acpi_hotkey_link hotkey_link; 111 int flag; 112 acpi_handle bus_handle; /* bus to install notify handler */ 113 int external_hotkey_num; /* external hotkey/event number */ 114 acpi_handle action_handle; /* acpi handle attached aml action method */ 115 char *action_method; /* action method */ 116}; 117 118/* 119 * There are two ways to poll status 120 * 1. directy call read_xxx method, without any arguments passed in 121 * 2. call write_xxx method, with arguments passed in, you need 122 * the result is saved in acpi_polling_hotkey.poll_result. 123 * anthoer read command through polling interface. 124 * 125 */ 126 127/* polling based hotkey */ 128struct acpi_polling_hotkey { 129 struct acpi_hotkey_link hotkey_link; 130 int flag; 131 acpi_handle poll_handle; /* acpi handle attached polling method */ 132 char *poll_method; /* poll method */ 133 acpi_handle action_handle; /* acpi handle attached action method */ 134 char *action_method; /* action method */ 135 union acpi_object *poll_result; /* polling_result */ 136 struct proc_dir_entry *proc; 137}; 138 139/* hotkey object union */ 140union acpi_hotkey { 141 struct list_head entries; 142 struct acpi_hotkey_link link; 143 struct acpi_event_hotkey event_hotkey; 144 struct acpi_polling_hotkey poll_hotkey; 145}; 146 147/* hotkey object list */ 148struct acpi_hotkey_list { 149 struct list_head *entries; 150 int count; 151}; 152 153static int auto_hotkey_add(struct acpi_device *device); 154static int auto_hotkey_remove(struct acpi_device *device, int type); 155 156static struct acpi_driver hotkey_driver = { 157 .name = ACPI_HOTK_NAME, 158 .class = ACPI_HOTK_CLASS, 159 .ids = ACPI_HOTK_HID, 160 .ops = { 161 .add = auto_hotkey_add, 162 .remove = auto_hotkey_remove, 163 }, 164}; 165 166static void free_hotkey_device(union acpi_hotkey *key); 167static void free_hotkey_buffer(union acpi_hotkey *key); 168static void free_poll_hotkey_buffer(union acpi_hotkey *key); 169static int hotkey_open_config(struct inode *inode, struct file *file); 170static int hotkey_poll_open_config(struct inode *inode, struct file *file); 171static ssize_t hotkey_write_config(struct file *file, 172 const char __user * buffer, 173 size_t count, loff_t * data); 174static int hotkey_info_open_fs(struct inode *inode, struct file *file); 175static int hotkey_action_open_fs(struct inode *inode, struct file *file); 176static ssize_t hotkey_execute_aml_method(struct file *file, 177 const char __user * buffer, 178 size_t count, loff_t * data); 179static int hotkey_config_seq_show(struct seq_file *seq, void *offset); 180static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset); 181static int hotkey_polling_open_fs(struct inode *inode, struct file *file); 182static union acpi_hotkey *get_hotkey_by_event(struct 183 acpi_hotkey_list 184 *hotkey_list, int event); 185 186/* event based config */ 187static struct file_operations hotkey_config_fops = { 188 .open = hotkey_open_config, 189 .read = seq_read, 190 .write = hotkey_write_config, 191 .llseek = seq_lseek, 192 .release = single_release, 193}; 194 195/* polling based config */ 196static struct file_operations hotkey_poll_config_fops = { 197 .open = hotkey_poll_open_config, 198 .read = seq_read, 199 .write = hotkey_write_config, 200 .llseek = seq_lseek, 201 .release = single_release, 202}; 203 204/* hotkey driver info */ 205static struct file_operations hotkey_info_fops = { 206 .open = hotkey_info_open_fs, 207 .read = seq_read, 208 .llseek = seq_lseek, 209 .release = single_release, 210}; 211 212/* action */ 213static struct file_operations hotkey_action_fops = { 214 .open = hotkey_action_open_fs, 215 .read = seq_read, 216 .write = hotkey_execute_aml_method, 217 .llseek = seq_lseek, 218 .release = single_release, 219}; 220 221/* polling results */ 222static struct file_operations hotkey_polling_fops = { 223 .open = hotkey_polling_open_fs, 224 .read = seq_read, 225 .llseek = seq_lseek, 226 .release = single_release, 227}; 228 229struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */ 230struct list_head hotkey_entries; /* head of the list of hotkey_list */ 231 232static int hotkey_info_seq_show(struct seq_file *seq, void *offset) 233{ 234 ACPI_FUNCTION_TRACE("hotkey_info_seq_show"); 235 236 seq_printf(seq, "Hotkey generic driver ver: %s\n", HOTKEY_ACPI_VERSION); 237 238 return_VALUE(0); 239} 240 241static int hotkey_info_open_fs(struct inode *inode, struct file *file) 242{ 243 return single_open(file, hotkey_info_seq_show, PDE(inode)->data); 244} 245 246static char *format_result(union acpi_object *object) 247{ 248 char *buf = NULL; 249 250 buf = (char *)kmalloc(RESULT_STR_LEN, GFP_KERNEL); 251 if (buf) 252 memset(buf, 0, RESULT_STR_LEN); 253 else 254 goto do_fail; 255 256 /* Now, just support integer type */ 257 if (object->type == ACPI_TYPE_INTEGER) 258 sprintf(buf, "%d\n", (u32) object->integer.value); 259 do_fail: 260 return (buf); 261} 262 263static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) 264{ 265 struct acpi_polling_hotkey *poll_hotkey = 266 (struct acpi_polling_hotkey *)seq->private; 267 char *buf; 268 269 ACPI_FUNCTION_TRACE("hotkey_polling_seq_show"); 270 271 if (poll_hotkey->poll_result) { 272 buf = format_result(poll_hotkey->poll_result); 273 if (buf) 274 seq_printf(seq, "%s", buf); 275 kfree(buf); 276 } 277 return_VALUE(0); 278} 279 280static int hotkey_polling_open_fs(struct inode *inode, struct file *file) 281{ 282 return single_open(file, hotkey_polling_seq_show, PDE(inode)->data); 283} 284 285static int hotkey_action_open_fs(struct inode *inode, struct file *file) 286{ 287 return single_open(file, hotkey_info_seq_show, PDE(inode)->data); 288} 289 290/* Mapping external hotkey number to standardized hotkey event num */ 291static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list) 292{ 293 struct list_head *entries; 294 int val = -1; 295 296 ACPI_FUNCTION_TRACE("hotkey_get_internal_event"); 297 298 list_for_each(entries, list->entries) { 299 union acpi_hotkey *key = 300 container_of(entries, union acpi_hotkey, entries); 301 if (key->link.hotkey_type == ACPI_HOTKEY_EVENT 302 && key->event_hotkey.external_hotkey_num == event) { 303 val = key->link.hotkey_standard_num; 304 break; 305 } 306 } 307 308 return_VALUE(val); 309} 310 311static void 312acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data) 313{ 314 struct acpi_device *device = NULL; 315 u32 internal_event; 316 317 ACPI_FUNCTION_TRACE("acpi_hotkey_notify_handler"); 318 319 if (acpi_bus_get_device(handle, &device)) 320 return_VOID; 321 322 internal_event = hotkey_get_internal_event(event, &global_hotkey_list); 323 acpi_bus_generate_event(device, internal_event, 0); 324 325 return_VOID; 326} 327 328/* Need to invent automatically hotkey add method */ 329static int auto_hotkey_add(struct acpi_device *device) 330{ 331 /* Implement me */ 332 return 0; 333} 334 335/* Need to invent automatically hotkey remove method */ 336static int auto_hotkey_remove(struct acpi_device *device, int type) 337{ 338 /* Implement me */ 339 return 0; 340} 341 342/* Create a proc file for each polling method */ 343static int create_polling_proc(union acpi_hotkey *device) 344{ 345 struct proc_dir_entry *proc; 346 char proc_name[80]; 347 mode_t mode; 348 349 ACPI_FUNCTION_TRACE("create_polling_proc"); 350 mode = S_IFREG | S_IRUGO | S_IWUGO; 351 352 sprintf(proc_name, "%d", device->link.hotkey_standard_num); 353 /* 354 strcat(proc_name, device->poll_hotkey.poll_method); 355 */ 356 proc = create_proc_entry(proc_name, mode, hotkey_proc_dir); 357 358 if (!proc) { 359 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 360 "Hotkey: Unable to create %s entry\n", 361 device->poll_hotkey.poll_method)); 362 return_VALUE(-ENODEV); 363 } else { 364 proc->proc_fops = &hotkey_polling_fops; 365 proc->owner = THIS_MODULE; 366 proc->data = device; 367 proc->uid = 0; 368 proc->gid = 0; 369 device->poll_hotkey.proc = proc; 370 } 371 return_VALUE(0); 372} 373 374static int hotkey_add(union acpi_hotkey *device) 375{ 376 int status = 0; 377 struct acpi_device *dev = NULL; 378 379 ACPI_FUNCTION_TRACE("hotkey_add"); 380 381 if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) { 382 acpi_bus_get_device(device->event_hotkey.bus_handle, &dev); 383 status = acpi_install_notify_handler(dev->handle, 384 ACPI_DEVICE_NOTIFY, 385 acpi_hotkey_notify_handler, 386 dev); 387 } else /* Add polling hotkey */ 388 create_polling_proc(device); 389 390 global_hotkey_list.count++; 391 392 list_add_tail(&device->link.entries, global_hotkey_list.entries); 393 394 return_VALUE(status); 395} 396 397static int hotkey_remove(union acpi_hotkey *device) 398{ 399 struct list_head *entries, *next; 400 401 ACPI_FUNCTION_TRACE("hotkey_remove"); 402 403 list_for_each_safe(entries, next, global_hotkey_list.entries) { 404 union acpi_hotkey *key = 405 container_of(entries, union acpi_hotkey, entries); 406 if (key->link.hotkey_standard_num == 407 device->link.hotkey_standard_num) { 408 list_del(&key->link.entries); 409 free_hotkey_device(key); 410 global_hotkey_list.count--; 411 break; 412 } 413 } 414 kfree(device); 415 return_VALUE(0); 416} 417 418static int hotkey_update(union acpi_hotkey *key) 419{ 420 struct list_head *entries; 421 422 ACPI_FUNCTION_TRACE("hotkey_update"); 423 424 list_for_each(entries, global_hotkey_list.entries) { 425 union acpi_hotkey *tmp = 426 container_of(entries, union acpi_hotkey, entries); 427 if (tmp->link.hotkey_standard_num == 428 key->link.hotkey_standard_num) { 429 if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { 430 free_hotkey_buffer(tmp); 431 tmp->event_hotkey.bus_handle = 432 key->event_hotkey.bus_handle; 433 tmp->event_hotkey.external_hotkey_num = 434 key->event_hotkey.external_hotkey_num; 435 tmp->event_hotkey.action_handle = 436 key->event_hotkey.action_handle; 437 tmp->event_hotkey.action_method = 438 key->event_hotkey.action_method; 439 kfree(key); 440 } else { 441 /* 442 char proc_name[80]; 443 444 sprintf(proc_name, "%d", tmp->link.hotkey_standard_num); 445 strcat(proc_name, tmp->poll_hotkey.poll_method); 446 remove_proc_entry(proc_name,hotkey_proc_dir); 447 */ 448 free_poll_hotkey_buffer(tmp); 449 tmp->poll_hotkey.poll_handle = 450 key->poll_hotkey.poll_handle; 451 tmp->poll_hotkey.poll_method = 452 key->poll_hotkey.poll_method; 453 tmp->poll_hotkey.action_handle = 454 key->poll_hotkey.action_handle; 455 tmp->poll_hotkey.action_method = 456 key->poll_hotkey.action_method; 457 tmp->poll_hotkey.poll_result = 458 key->poll_hotkey.poll_result; 459 /* 460 create_polling_proc(tmp); 461 */ 462 kfree(key); 463 } 464 return_VALUE(0); 465 break; 466 } 467 } 468 469 return_VALUE(-ENODEV); 470} 471 472static void free_hotkey_device(union acpi_hotkey *key) 473{ 474 struct acpi_device *dev; 475 476 ACPI_FUNCTION_TRACE("free_hotkey_device"); 477 478 if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { 479 acpi_bus_get_device(key->event_hotkey.bus_handle, &dev); 480 if (dev->handle) 481 acpi_remove_notify_handler(dev->handle, 482 ACPI_DEVICE_NOTIFY, 483 acpi_hotkey_notify_handler); 484 free_hotkey_buffer(key); 485 } else { 486 char proc_name[80]; 487 488 sprintf(proc_name, "%d", key->link.hotkey_standard_num); 489 /* 490 strcat(proc_name, key->poll_hotkey.poll_method); 491 */ 492 remove_proc_entry(proc_name, hotkey_proc_dir); 493 free_poll_hotkey_buffer(key); 494 } 495 kfree(key); 496 return_VOID; 497} 498 499static void free_hotkey_buffer(union acpi_hotkey *key) 500{ 501 kfree(key->event_hotkey.action_method); 502} 503 504static void free_poll_hotkey_buffer(union acpi_hotkey *key) 505{ 506 kfree(key->poll_hotkey.action_method); 507 kfree(key->poll_hotkey.poll_method); 508 kfree(key->poll_hotkey.poll_result); 509} 510static int 511init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str, 512 char *method, int std_num, int external_num) 513{ 514 acpi_handle tmp_handle; 515 acpi_status status = AE_OK; 516 517 ACPI_FUNCTION_TRACE("init_hotkey_device"); 518 519 if (std_num < 0 || IS_POLL(std_num) || !key) 520 goto do_fail; 521 522 if (!bus_str || !action_str || !method) 523 goto do_fail; 524 525 key->link.hotkey_type = ACPI_HOTKEY_EVENT; 526 key->link.hotkey_standard_num = std_num; 527 key->event_hotkey.flag = 0; 528 key->event_hotkey.action_method = method; 529 530 status = 531 acpi_get_handle(NULL, bus_str, &(key->event_hotkey.bus_handle)); 532 if (ACPI_FAILURE(status)) 533 goto do_fail; 534 key->event_hotkey.external_hotkey_num = external_num; 535 status = 536 acpi_get_handle(NULL, action_str, 537 &(key->event_hotkey.action_handle)); 538 if (ACPI_FAILURE(status)) 539 goto do_fail; 540 status = acpi_get_handle(key->event_hotkey.action_handle, 541 method, &tmp_handle); 542 if (ACPI_FAILURE(status)) 543 goto do_fail; 544 return_VALUE(AE_OK); 545 do_fail: 546 return_VALUE(-ENODEV); 547} 548 549static int 550init_poll_hotkey_device(union acpi_hotkey *key, 551 char *poll_str, 552 char *poll_method, 553 char *action_str, char *action_method, int std_num) 554{ 555 acpi_status status = AE_OK; 556 acpi_handle tmp_handle; 557 558 ACPI_FUNCTION_TRACE("init_poll_hotkey_device"); 559 560 if (std_num < 0 || IS_EVENT(std_num) || !key) 561 goto do_fail; 562 563 if (!poll_str || !poll_method || !action_str || !action_method) 564 goto do_fail; 565 566 key->link.hotkey_type = ACPI_HOTKEY_POLLING; 567 key->link.hotkey_standard_num = std_num; 568 key->poll_hotkey.flag = 0; 569 key->poll_hotkey.poll_method = poll_method; 570 key->poll_hotkey.action_method = action_method; 571 572 status = 573 acpi_get_handle(NULL, poll_str, &(key->poll_hotkey.poll_handle)); 574 if (ACPI_FAILURE(status)) 575 goto do_fail; 576 status = acpi_get_handle(key->poll_hotkey.poll_handle, 577 poll_method, &tmp_handle); 578 if (ACPI_FAILURE(status)) 579 goto do_fail; 580 status = 581 acpi_get_handle(NULL, action_str, 582 &(key->poll_hotkey.action_handle)); 583 if (ACPI_FAILURE(status)) 584 goto do_fail; 585 status = acpi_get_handle(key->poll_hotkey.action_handle, 586 action_method, &tmp_handle); 587 if (ACPI_FAILURE(status)) 588 goto do_fail; 589 key->poll_hotkey.poll_result = 590 (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL); 591 if (!key->poll_hotkey.poll_result) 592 goto do_fail; 593 return_VALUE(AE_OK); 594 do_fail: 595 return_VALUE(-ENODEV); 596} 597 598static int hotkey_open_config(struct inode *inode, struct file *file) 599{ 600 ACPI_FUNCTION_TRACE("hotkey_open_config"); 601 return_VALUE(single_open 602 (file, hotkey_config_seq_show, PDE(inode)->data)); 603} 604 605static int hotkey_poll_open_config(struct inode *inode, struct file *file) 606{ 607 ACPI_FUNCTION_TRACE("hotkey_poll_open_config"); 608 return_VALUE(single_open 609 (file, hotkey_poll_config_seq_show, PDE(inode)->data)); 610} 611 612static int hotkey_config_seq_show(struct seq_file *seq, void *offset) 613{ 614 struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; 615 struct list_head *entries; 616 char bus_name[ACPI_PATHNAME_MAX] = { 0 }; 617 char action_name[ACPI_PATHNAME_MAX] = { 0 }; 618 struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; 619 struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; 620 621 ACPI_FUNCTION_TRACE(("hotkey_config_seq_show")); 622 623 list_for_each(entries, hotkey_list->entries) { 624 union acpi_hotkey *key = 625 container_of(entries, union acpi_hotkey, entries); 626 if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { 627 acpi_get_name(key->event_hotkey.bus_handle, 628 ACPI_NAME_TYPE_MAX, &bus); 629 acpi_get_name(key->event_hotkey.action_handle, 630 ACPI_NAME_TYPE_MAX, &act); 631 seq_printf(seq, "%s:%s:%s:%d:%d\n", bus_name, 632 action_name, 633 key->event_hotkey.action_method, 634 key->link.hotkey_standard_num, 635 key->event_hotkey.external_hotkey_num); 636 } 637 } 638 seq_puts(seq, "\n"); 639 return_VALUE(0); 640} 641 642static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset) 643{ 644 struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; 645 struct list_head *entries; 646 char bus_name[ACPI_PATHNAME_MAX] = { 0 }; 647 char action_name[ACPI_PATHNAME_MAX] = { 0 }; 648 struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; 649 struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; 650 651 ACPI_FUNCTION_TRACE(("hotkey_config_seq_show")); 652 653 list_for_each(entries, hotkey_list->entries) { 654 union acpi_hotkey *key = 655 container_of(entries, union acpi_hotkey, entries); 656 if (key->link.hotkey_type == ACPI_HOTKEY_POLLING) { 657 acpi_get_name(key->poll_hotkey.poll_handle, 658 ACPI_NAME_TYPE_MAX, &bus); 659 acpi_get_name(key->poll_hotkey.action_handle, 660 ACPI_NAME_TYPE_MAX, &act); 661 seq_printf(seq, "%s:%s:%s:%s:%d\n", bus_name, 662 key->poll_hotkey.poll_method, 663 action_name, 664 key->poll_hotkey.action_method, 665 key->link.hotkey_standard_num); 666 } 667 } 668 seq_puts(seq, "\n"); 669 return_VALUE(0); 670} 671 672static int 673get_parms(char *config_record, 674 int *cmd, 675 char **bus_handle, 676 char **bus_method, 677 char **action_handle, 678 char **method, int *internal_event_num, int *external_event_num) 679{ 680 char *tmp, *tmp1, count; 681 ACPI_FUNCTION_TRACE(("get_parms")); 682 683 sscanf(config_record, "%d", cmd); 684 685 if (*cmd == 1) { 686 if (sscanf(config_record, "%d:%d", cmd, internal_event_num) != 687 2) 688 goto do_fail; 689 else 690 return (6); 691 } 692 tmp = strchr(config_record, ':'); 693 if (!tmp) 694 goto do_fail; 695 tmp++; 696 tmp1 = strchr(tmp, ':'); 697 if (!tmp1) 698 goto do_fail; 699 700 count = tmp1 - tmp; 701 *bus_handle = (char *)kmalloc(count + 1, GFP_KERNEL); 702 if (!*bus_handle) 703 goto do_fail; 704 strncpy(*bus_handle, tmp, count); 705 *(*bus_handle + count) = 0; 706 707 tmp = tmp1; 708 tmp++; 709 tmp1 = strchr(tmp, ':'); 710 if (!tmp1) 711 goto do_fail; 712 count = tmp1 - tmp; 713 *bus_method = (char *)kmalloc(count + 1, GFP_KERNEL); 714 if (!*bus_method) 715 goto do_fail; 716 strncpy(*bus_method, tmp, count); 717 *(*bus_method + count) = 0; 718 719 tmp = tmp1; 720 tmp++; 721 tmp1 = strchr(tmp, ':'); 722 if (!tmp1) 723 goto do_fail; 724 count = tmp1 - tmp; 725 *action_handle = (char *)kmalloc(count + 1, GFP_KERNEL); 726 strncpy(*action_handle, tmp, count); 727 *(*action_handle + count) = 0; 728 729 tmp = tmp1; 730 tmp++; 731 tmp1 = strchr(tmp, ':'); 732 if (!tmp1) 733 goto do_fail; 734 count = tmp1 - tmp; 735 *method = (char *)kmalloc(count + 1, GFP_KERNEL); 736 if (!*method) 737 goto do_fail; 738 strncpy(*method, tmp, count); 739 *(*method + count) = 0; 740 741 if (sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num) <= 742 0) 743 goto do_fail; 744 745 return_VALUE(6); 746 do_fail: 747 return_VALUE(-1); 748} 749 750/* count is length for one input record */ 751static ssize_t hotkey_write_config(struct file *file, 752 const char __user * buffer, 753 size_t count, loff_t * data) 754{ 755 char *config_record = NULL; 756 char *bus_handle = NULL; 757 char *bus_method = NULL; 758 char *action_handle = NULL; 759 char *method = NULL; 760 int cmd, internal_event_num, external_event_num; 761 int ret = 0; 762 union acpi_hotkey *key = NULL; 763 764 ACPI_FUNCTION_TRACE(("hotkey_write_config")); 765 766 config_record = (char *)kmalloc(count + 1, GFP_KERNEL); 767 if (!config_record) 768 return_VALUE(-ENOMEM); 769 770 if (copy_from_user(config_record, buffer, count)) { 771 kfree(config_record); 772 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n")); 773 return_VALUE(-EINVAL); 774 } 775 config_record[count] = 0; 776 777 ret = get_parms(config_record, 778 &cmd, 779 &bus_handle, 780 &bus_method, 781 &action_handle, 782 &method, &internal_event_num, &external_event_num); 783 784 kfree(config_record); 785 if (IS_OTHERS(internal_event_num)) 786 goto do_fail; 787 if (ret != 6) { 788 do_fail: 789 kfree(bus_handle); 790 kfree(bus_method); 791 kfree(action_handle); 792 kfree(method); 793 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 794 "Invalid data format ret=%d\n", ret)); 795 return_VALUE(-EINVAL); 796 } 797 798 key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL); 799 if (!key) 800 goto do_fail; 801 memset(key, 0, sizeof(union acpi_hotkey)); 802 if (cmd == 1) { 803 union acpi_hotkey *tmp = NULL; 804 tmp = get_hotkey_by_event(&global_hotkey_list, 805 internal_event_num); 806 if (!tmp) 807 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid key")); 808 else 809 memcpy(key, tmp, sizeof(union acpi_hotkey)); 810 goto cont_cmd; 811 } 812 if (IS_EVENT(internal_event_num)) { 813 kfree(bus_method); 814 ret = init_hotkey_device(key, bus_handle, action_handle, method, 815 internal_event_num, 816 external_event_num); 817 } else 818 ret = init_poll_hotkey_device(key, bus_handle, bus_method, 819 action_handle, method, 820 internal_event_num); 821 if (ret) { 822 kfree(bus_handle); 823 kfree(action_handle); 824 if (IS_EVENT(internal_event_num)) 825 free_hotkey_buffer(key); 826 else 827 free_poll_hotkey_buffer(key); 828 kfree(key); 829 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n")); 830 return_VALUE(-EINVAL); 831 } 832 833 cont_cmd: 834 kfree(bus_handle); 835 kfree(action_handle); 836 837 switch (cmd) { 838 case 0: 839 if (get_hotkey_by_event 840 (&global_hotkey_list, key->link.hotkey_standard_num)) 841 goto fail_out; 842 else 843 hotkey_add(key); 844 break; 845 case 1: 846 hotkey_remove(key); 847 break; 848 case 2: 849 if (hotkey_update(key)) 850 goto fail_out; 851 break; 852 default: 853 goto fail_out; 854 break; 855 } 856 return_VALUE(count); 857 fail_out: 858 if (IS_EVENT(internal_event_num)) 859 free_hotkey_buffer(key); 860 else 861 free_poll_hotkey_buffer(key); 862 kfree(key); 863 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid key\n")); 864 return_VALUE(-EINVAL); 865} 866 867/* 868 * This function evaluates an ACPI method, given an int as parameter, the 869 * method is searched within the scope of the handle, can be NULL. The output 870 * of the method is written is output, which can also be NULL 871 * 872 * returns 1 if write is successful, 0 else. 873 */ 874static int write_acpi_int(acpi_handle handle, const char *method, int val, 875 struct acpi_buffer *output) 876{ 877 struct acpi_object_list params; /* list of input parameters (an int here) */ 878 union acpi_object in_obj; /* the only param we use */ 879 acpi_status status; 880 881 ACPI_FUNCTION_TRACE("write_acpi_int"); 882 params.count = 1; 883 params.pointer = &in_obj; 884 in_obj.type = ACPI_TYPE_INTEGER; 885 in_obj.integer.value = val; 886 887 status = acpi_evaluate_object(handle, (char *)method, &params, output); 888 889 return_VALUE(status == AE_OK); 890} 891 892static int read_acpi_int(acpi_handle handle, const char *method, 893 union acpi_object *val) 894{ 895 struct acpi_buffer output; 896 union acpi_object out_obj; 897 acpi_status status; 898 899 ACPI_FUNCTION_TRACE("read_acpi_int"); 900 output.length = sizeof(out_obj); 901 output.pointer = &out_obj; 902 903 status = acpi_evaluate_object(handle, (char *)method, NULL, &output); 904 if (val) { 905 val->integer.value = out_obj.integer.value; 906 val->type = out_obj.type; 907 } else 908 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "null val pointer")); 909 return_VALUE((status == AE_OK) 910 && (out_obj.type == ACPI_TYPE_INTEGER)); 911} 912 913static union acpi_hotkey *get_hotkey_by_event(struct 914 acpi_hotkey_list 915 *hotkey_list, int event) 916{ 917 struct list_head *entries; 918 919 list_for_each(entries, hotkey_list->entries) { 920 union acpi_hotkey *key = 921 container_of(entries, union acpi_hotkey, entries); 922 if (key->link.hotkey_standard_num == event) { 923 return (key); 924 } 925 } 926 return (NULL); 927} 928 929/* 930 * user call AML method interface: 931 * Call convention: 932 * echo "event_num: arg type : value" 933 * example: echo "1:1:30" > /proc/acpi/action 934 * Just support 1 integer arg passing to AML method 935 */ 936 937static ssize_t hotkey_execute_aml_method(struct file *file, 938 const char __user * buffer, 939 size_t count, loff_t * data) 940{ 941 struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; 942 char *arg; 943 int event, method_type, type, value; 944 union acpi_hotkey *key; 945 946 ACPI_FUNCTION_TRACE("hotkey_execte_aml_method"); 947 948 arg = (char *)kmalloc(count + 1, GFP_KERNEL); 949 if (!arg) 950 return_VALUE(-ENOMEM); 951 arg[count] = 0; 952 953 if (copy_from_user(arg, buffer, count)) { 954 kfree(arg); 955 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 2")); 956 return_VALUE(-EINVAL); 957 } 958 959 if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) != 960 4) { 961 kfree(arg); 962 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 3")); 963 return_VALUE(-EINVAL); 964 } 965 kfree(arg); 966 if (type == ACPI_TYPE_INTEGER) { 967 key = get_hotkey_by_event(hotkey_list, event); 968 if (!key) 969 goto do_fail; 970 if (IS_EVENT(event)) 971 write_acpi_int(key->event_hotkey.action_handle, 972 key->event_hotkey.action_method, value, 973 NULL); 974 else if (IS_POLL(event)) { 975 if (method_type == POLL_METHOD) 976 read_acpi_int(key->poll_hotkey.poll_handle, 977 key->poll_hotkey.poll_method, 978 key->poll_hotkey.poll_result); 979 else if (method_type == ACTION_METHOD) 980 write_acpi_int(key->poll_hotkey.action_handle, 981 key->poll_hotkey.action_method, 982 value, NULL); 983 else 984 goto do_fail; 985 986 } 987 } else { 988 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Not supported")); 989 return_VALUE(-EINVAL); 990 } 991 return_VALUE(count); 992 do_fail: 993 return_VALUE(-EINVAL); 994 995} 996 997static int __init hotkey_init(void) 998{ 999 int result; 1000 mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; 1001 1002 ACPI_FUNCTION_TRACE("hotkey_init"); 1003 1004 if (acpi_disabled) 1005 return -ENODEV; 1006 1007 if (acpi_specific_hotkey_enabled) { 1008 printk("Using specific hotkey driver\n"); 1009 return -ENODEV; 1010 } 1011 1012 hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir); 1013 if (!hotkey_proc_dir) { 1014 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 1015 "Hotkey: Unable to create %s entry\n", 1016 HOTKEY_PROC)); 1017 return (-ENODEV); 1018 } 1019 hotkey_proc_dir->owner = THIS_MODULE; 1020 1021 hotkey_config = 1022 create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir); 1023 if (!hotkey_config) { 1024 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 1025 "Hotkey: Unable to create %s entry\n", 1026 HOTKEY_EV_CONFIG)); 1027 goto do_fail1; 1028 } else { 1029 hotkey_config->proc_fops = &hotkey_config_fops; 1030 hotkey_config->data = &global_hotkey_list; 1031 hotkey_config->owner = THIS_MODULE; 1032 hotkey_config->uid = 0; 1033 hotkey_config->gid = 0; 1034 } 1035 1036 hotkey_poll_config = 1037 create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir); 1038 if (!hotkey_poll_config) { 1039 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 1040 "Hotkey: Unable to create %s entry\n", 1041 HOTKEY_EV_CONFIG)); 1042 1043 goto do_fail2; 1044 } else { 1045 hotkey_poll_config->proc_fops = &hotkey_poll_config_fops; 1046 hotkey_poll_config->data = &global_hotkey_list; 1047 hotkey_poll_config->owner = THIS_MODULE; 1048 hotkey_poll_config->uid = 0; 1049 hotkey_poll_config->gid = 0; 1050 } 1051 1052 hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir); 1053 if (!hotkey_action) { 1054 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 1055 "Hotkey: Unable to create %s entry\n", 1056 HOTKEY_ACTION)); 1057 goto do_fail3; 1058 } else { 1059 hotkey_action->proc_fops = &hotkey_action_fops; 1060 hotkey_action->owner = THIS_MODULE; 1061 hotkey_action->uid = 0; 1062 hotkey_action->gid = 0; 1063 } 1064 1065 hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir); 1066 if (!hotkey_info) { 1067 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 1068 "Hotkey: Unable to create %s entry\n", 1069 HOTKEY_INFO)); 1070 goto do_fail4; 1071 } else { 1072 hotkey_info->proc_fops = &hotkey_info_fops; 1073 hotkey_info->owner = THIS_MODULE; 1074 hotkey_info->uid = 0; 1075 hotkey_info->gid = 0; 1076 } 1077 1078 result = acpi_bus_register_driver(&hotkey_driver); 1079 if (result < 0) 1080 goto do_fail5; 1081 global_hotkey_list.count = 0; 1082 global_hotkey_list.entries = &hotkey_entries; 1083 1084 INIT_LIST_HEAD(&hotkey_entries); 1085 1086 return (0); 1087 1088 do_fail5: 1089 remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); 1090 do_fail4: 1091 remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); 1092 do_fail3: 1093 remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); 1094 do_fail2: 1095 remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); 1096 do_fail1: 1097 remove_proc_entry(HOTKEY_PROC, acpi_root_dir); 1098 return (-ENODEV); 1099} 1100 1101static void __exit hotkey_exit(void) 1102{ 1103 struct list_head *entries, *next; 1104 1105 ACPI_FUNCTION_TRACE("hotkey_exit"); 1106 1107 list_for_each_safe(entries, next, global_hotkey_list.entries) { 1108 union acpi_hotkey *key = 1109 container_of(entries, union acpi_hotkey, entries); 1110 1111 acpi_os_wait_events_complete(NULL); 1112 list_del(&key->link.entries); 1113 global_hotkey_list.count--; 1114 free_hotkey_device(key); 1115 } 1116 acpi_bus_unregister_driver(&hotkey_driver); 1117 remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); 1118 remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); 1119 remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); 1120 remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); 1121 remove_proc_entry(HOTKEY_PROC, acpi_root_dir); 1122 return; 1123} 1124 1125module_init(hotkey_init); 1126module_exit(hotkey_exit);