1 /* 2 * acpi_button.c - ACPI Button Driver ($Revision: 30 $) 3 * 4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 6 * 7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or (at 12 * your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write to the Free Software Foundation, Inc., 21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 22 * 23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 24 */ 25 26 #include <linux/kernel.h> 27 #include <linux/module.h> 28 #include <linux/init.h> 29 #include <linux/types.h> 30 #include <linux/proc_fs.h> 31 #include <linux/seq_file.h> 32 #include <linux/input.h> 33 #include <acpi/acpi_bus.h> 34 #include <acpi/acpi_drivers.h> 35 36 #define ACPI_BUTTON_COMPONENT 0x00080000 37 #define ACPI_BUTTON_CLASS "button" 38 #define ACPI_BUTTON_FILE_INFO "info" 39 #define ACPI_BUTTON_FILE_STATE "state" 40 #define ACPI_BUTTON_TYPE_UNKNOWN 0x00 41 #define ACPI_BUTTON_NOTIFY_STATUS 0x80 42 43 #define ACPI_BUTTON_SUBCLASS_POWER "power" 44 #define ACPI_BUTTON_HID_POWER "PNP0C0C" 45 #define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)" 46 #define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)" 47 #define ACPI_BUTTON_TYPE_POWER 0x01 48 #define ACPI_BUTTON_TYPE_POWERF 0x02 49 50 #define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" 51 #define ACPI_BUTTON_HID_SLEEP "PNP0C0E" 52 #define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)" 53 #define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)" 54 #define ACPI_BUTTON_TYPE_SLEEP 0x03 55 #define ACPI_BUTTON_TYPE_SLEEPF 0x04 56 57 #define ACPI_BUTTON_SUBCLASS_LID "lid" 58 #define ACPI_BUTTON_HID_LID "PNP0C0D" 59 #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" 60 #define ACPI_BUTTON_TYPE_LID 0x05 61 62 #define _COMPONENT ACPI_BUTTON_COMPONENT 63 ACPI_MODULE_NAME("button"); 64 65 MODULE_AUTHOR("Paul Diefenbaugh"); 66 MODULE_DESCRIPTION("ACPI Button Driver"); 67 MODULE_LICENSE("GPL"); 68 69 static const struct acpi_device_id button_device_ids[] = { 70 {ACPI_BUTTON_HID_LID, 0}, 71 {ACPI_BUTTON_HID_SLEEP, 0}, 72 {ACPI_BUTTON_HID_SLEEPF, 0}, 73 {ACPI_BUTTON_HID_POWER, 0}, 74 {ACPI_BUTTON_HID_POWERF, 0}, 75 {"", 0}, 76 }; 77 MODULE_DEVICE_TABLE(acpi, button_device_ids); 78 79 static int acpi_button_add(struct acpi_device *device); 80 static int acpi_button_remove(struct acpi_device *device, int type); 81 static int acpi_button_info_open_fs(struct inode *inode, struct file *file); 82 static int acpi_button_state_open_fs(struct inode *inode, struct file *file); 83 84 static struct acpi_driver acpi_button_driver = { 85 .name = "button", 86 .class = ACPI_BUTTON_CLASS, 87 .ids = button_device_ids, 88 .ops = { 89 .add = acpi_button_add, 90 .remove = acpi_button_remove, 91 }, 92 }; 93 94 struct acpi_button { 95 struct acpi_device *device; /* Fixed button kludge */ 96 unsigned int type; 97 struct input_dev *input; 98 char phys[32]; /* for input device */ 99 unsigned long pushed; 100 }; 101 102 static const struct file_operations acpi_button_info_fops = { 103 .open = acpi_button_info_open_fs, 104 .read = seq_read, 105 .llseek = seq_lseek, 106 .release = single_release, 107 }; 108 109 static const struct file_operations acpi_button_state_fops = { 110 .open = acpi_button_state_open_fs, 111 .read = seq_read, 112 .llseek = seq_lseek, 113 .release = single_release, 114 }; 115 116 /* -------------------------------------------------------------------------- 117 FS Interface (/proc) 118 -------------------------------------------------------------------------- */ 119 120 static struct proc_dir_entry *acpi_button_dir; 121 122 static int acpi_button_info_seq_show(struct seq_file *seq, void *offset) 123 { 124 struct acpi_button *button = seq->private; 125 126 if (!button || !button->device) 127 return 0; 128 129 seq_printf(seq, "type: %s\n", 130 acpi_device_name(button->device)); 131 132 return 0; 133 } 134 135 static int acpi_button_info_open_fs(struct inode *inode, struct file *file) 136 { 137 return single_open(file, acpi_button_info_seq_show, PDE(inode)->data); 138 } 139 140 static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) 141 { 142 struct acpi_button *button = seq->private; 143 acpi_status status; 144 unsigned long state; 145 146 if (!button || !button->device) 147 return 0; 148 149 status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state); 150 seq_printf(seq, "state: %s\n", 151 ACPI_FAILURE(status) ? "unsupported" : 152 (state ? "open" : "closed")); 153 return 0; 154 } 155 156 static int acpi_button_state_open_fs(struct inode *inode, struct file *file) 157 { 158 return single_open(file, acpi_button_state_seq_show, PDE(inode)->data); 159 } 160 161 static struct proc_dir_entry *acpi_power_dir; 162 static struct proc_dir_entry *acpi_sleep_dir; 163 static struct proc_dir_entry *acpi_lid_dir; 164 165 static int acpi_button_add_fs(struct acpi_device *device) 166 { 167 struct proc_dir_entry *entry = NULL; 168 struct acpi_button *button; 169 170 if (!device || !acpi_driver_data(device)) 171 return -EINVAL; 172 173 button = acpi_driver_data(device); 174 175 switch (button->type) { 176 case ACPI_BUTTON_TYPE_POWER: 177 case ACPI_BUTTON_TYPE_POWERF: 178 if (!acpi_power_dir) 179 acpi_power_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER, 180 acpi_button_dir); 181 entry = acpi_power_dir; 182 break; 183 case ACPI_BUTTON_TYPE_SLEEP: 184 case ACPI_BUTTON_TYPE_SLEEPF: 185 if (!acpi_sleep_dir) 186 acpi_sleep_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP, 187 acpi_button_dir); 188 entry = acpi_sleep_dir; 189 break; 190 case ACPI_BUTTON_TYPE_LID: 191 if (!acpi_lid_dir) 192 acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, 193 acpi_button_dir); 194 entry = acpi_lid_dir; 195 break; 196 } 197 198 if (!entry) 199 return -ENODEV; 200 entry->owner = THIS_MODULE; 201 202 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry); 203 if (!acpi_device_dir(device)) 204 return -ENODEV; 205 acpi_device_dir(device)->owner = THIS_MODULE; 206 207 /* 'info' [R] */ 208 entry = create_proc_entry(ACPI_BUTTON_FILE_INFO, 209 S_IRUGO, acpi_device_dir(device)); 210 if (!entry) 211 return -ENODEV; 212 else { 213 entry->proc_fops = &acpi_button_info_fops; 214 entry->data = acpi_driver_data(device); 215 entry->owner = THIS_MODULE; 216 } 217 218 /* show lid state [R] */ 219 if (button->type == ACPI_BUTTON_TYPE_LID) { 220 entry = create_proc_entry(ACPI_BUTTON_FILE_STATE, 221 S_IRUGO, acpi_device_dir(device)); 222 if (!entry) 223 return -ENODEV; 224 else { 225 entry->proc_fops = &acpi_button_state_fops; 226 entry->data = acpi_driver_data(device); 227 entry->owner = THIS_MODULE; 228 } 229 } 230 231 return 0; 232 } 233 234 static int acpi_button_remove_fs(struct acpi_device *device) 235 { 236 struct acpi_button *button = acpi_driver_data(device); 237 238 if (acpi_device_dir(device)) { 239 if (button->type == ACPI_BUTTON_TYPE_LID) 240 remove_proc_entry(ACPI_BUTTON_FILE_STATE, 241 acpi_device_dir(device)); 242 remove_proc_entry(ACPI_BUTTON_FILE_INFO, 243 acpi_device_dir(device)); 244 245 remove_proc_entry(acpi_device_bid(device), 246 acpi_device_dir(device)->parent); 247 acpi_device_dir(device) = NULL; 248 } 249 250 return 0; 251 } 252 253 /* -------------------------------------------------------------------------- 254 Driver Interface 255 -------------------------------------------------------------------------- */ 256 257 static void acpi_button_notify(acpi_handle handle, u32 event, void *data) 258 { 259 struct acpi_button *button = data; 260 struct input_dev *input; 261 262 if (!button || !button->device) 263 return; 264 265 switch (event) { 266 case ACPI_BUTTON_NOTIFY_STATUS: 267 input = button->input; 268 269 if (button->type == ACPI_BUTTON_TYPE_LID) { 270 struct acpi_handle *handle = button->device->handle; 271 unsigned long state; 272 273 if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID", 274 NULL, &state))) 275 input_report_switch(input, SW_LID, !state); 276 277 } else { 278 int keycode = test_bit(KEY_SLEEP, input->keybit) ? 279 KEY_SLEEP : KEY_POWER; 280 281 input_report_key(input, keycode, 1); 282 input_sync(input); 283 input_report_key(input, keycode, 0); 284 } 285 input_sync(input); 286 287 acpi_bus_generate_event(button->device, event, 288 ++button->pushed); 289 break; 290 default: 291 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 292 "Unsupported event [0x%x]\n", event)); 293 break; 294 } 295 296 return; 297 } 298 299 static acpi_status acpi_button_notify_fixed(void *data) 300 { 301 struct acpi_button *button = data; 302 303 if (!button) 304 return AE_BAD_PARAMETER; 305 306 acpi_button_notify(button->device->handle, ACPI_BUTTON_NOTIFY_STATUS, button); 307 308 return AE_OK; 309 } 310 311 static int acpi_button_install_notify_handlers(struct acpi_button *button) 312 { 313 acpi_status status; 314 315 switch (button->type) { 316 case ACPI_BUTTON_TYPE_POWERF: 317 status = 318 acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, 319 acpi_button_notify_fixed, 320 button); 321 break; 322 case ACPI_BUTTON_TYPE_SLEEPF: 323 status = 324 acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, 325 acpi_button_notify_fixed, 326 button); 327 break; 328 default: 329 status = acpi_install_notify_handler(button->device->handle, 330 ACPI_DEVICE_NOTIFY, 331 acpi_button_notify, 332 button); 333 break; 334 } 335 336 return ACPI_FAILURE(status) ? -ENODEV : 0; 337 } 338 339 static void acpi_button_remove_notify_handlers(struct acpi_button *button) 340 { 341 switch (button->type) { 342 case ACPI_BUTTON_TYPE_POWERF: 343 acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, 344 acpi_button_notify_fixed); 345 break; 346 case ACPI_BUTTON_TYPE_SLEEPF: 347 acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, 348 acpi_button_notify_fixed); 349 break; 350 default: 351 acpi_remove_notify_handler(button->device->handle, 352 ACPI_DEVICE_NOTIFY, 353 acpi_button_notify); 354 break; 355 } 356 } 357 358 static int acpi_button_add(struct acpi_device *device) 359 { 360 int error; 361 struct acpi_button *button; 362 struct input_dev *input; 363 364 if (!device) 365 return -EINVAL; 366 367 button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL); 368 if (!button) 369 return -ENOMEM; 370 371 button->device = device; 372 acpi_driver_data(device) = button; 373 374 button->input = input = input_allocate_device(); 375 if (!input) { 376 error = -ENOMEM; 377 goto err_free_button; 378 } 379 380 /* 381 * Determine the button type (via hid), as fixed-feature buttons 382 * need to be handled a bit differently than generic-space. 383 */ 384 if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) { 385 button->type = ACPI_BUTTON_TYPE_POWER; 386 strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_POWER); 387 sprintf(acpi_device_class(device), "%s/%s", 388 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); 389 } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) { 390 button->type = ACPI_BUTTON_TYPE_POWERF; 391 strcpy(acpi_device_name(device), 392 ACPI_BUTTON_DEVICE_NAME_POWERF); 393 sprintf(acpi_device_class(device), "%s/%s", 394 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); 395 } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) { 396 button->type = ACPI_BUTTON_TYPE_SLEEP; 397 strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_SLEEP); 398 sprintf(acpi_device_class(device), "%s/%s", 399 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); 400 } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) { 401 button->type = ACPI_BUTTON_TYPE_SLEEPF; 402 strcpy(acpi_device_name(device), 403 ACPI_BUTTON_DEVICE_NAME_SLEEPF); 404 sprintf(acpi_device_class(device), "%s/%s", 405 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); 406 } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) { 407 button->type = ACPI_BUTTON_TYPE_LID; 408 strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_LID); 409 sprintf(acpi_device_class(device), "%s/%s", 410 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); 411 } else { 412 printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", 413 acpi_device_hid(device)); 414 error = -ENODEV; 415 goto err_free_input; 416 } 417 418 error = acpi_button_add_fs(device); 419 if (error) 420 goto err_free_input; 421 422 error = acpi_button_install_notify_handlers(button); 423 if (error) 424 goto err_remove_fs; 425 426 snprintf(button->phys, sizeof(button->phys), 427 "%s/button/input0", acpi_device_hid(device)); 428 429 input->name = acpi_device_name(device); 430 input->phys = button->phys; 431 input->id.bustype = BUS_HOST; 432 input->id.product = button->type; 433 434 switch (button->type) { 435 case ACPI_BUTTON_TYPE_POWER: 436 case ACPI_BUTTON_TYPE_POWERF: 437 input->evbit[0] = BIT(EV_KEY); 438 set_bit(KEY_POWER, input->keybit); 439 break; 440 441 case ACPI_BUTTON_TYPE_SLEEP: 442 case ACPI_BUTTON_TYPE_SLEEPF: 443 input->evbit[0] = BIT(EV_KEY); 444 set_bit(KEY_SLEEP, input->keybit); 445 break; 446 447 case ACPI_BUTTON_TYPE_LID: 448 input->evbit[0] = BIT(EV_SW); 449 set_bit(SW_LID, input->swbit); 450 break; 451 } 452 453 error = input_register_device(input); 454 if (error) 455 goto err_remove_handlers; 456 457 if (device->wakeup.flags.valid) { 458 /* Button's GPE is run-wake GPE */ 459 acpi_set_gpe_type(device->wakeup.gpe_device, 460 device->wakeup.gpe_number, 461 ACPI_GPE_TYPE_WAKE_RUN); 462 acpi_enable_gpe(device->wakeup.gpe_device, 463 device->wakeup.gpe_number, ACPI_NOT_ISR); 464 device->wakeup.state.enabled = 1; 465 } 466 467 printk(KERN_INFO PREFIX "%s [%s]\n", 468 acpi_device_name(device), acpi_device_bid(device)); 469 470 return 0; 471 472 err_remove_handlers: 473 acpi_button_remove_notify_handlers(button); 474 err_remove_fs: 475 acpi_button_remove_fs(device); 476 err_free_input: 477 input_free_device(input); 478 err_free_button: 479 kfree(button); 480 return error; 481 } 482 483 static int acpi_button_remove(struct acpi_device *device, int type) 484 { 485 struct acpi_button *button; 486 487 if (!device || !acpi_driver_data(device)) 488 return -EINVAL; 489 490 button = acpi_driver_data(device); 491 492 acpi_button_remove_notify_handlers(button); 493 acpi_button_remove_fs(device); 494 input_unregister_device(button->input); 495 kfree(button); 496 497 return 0; 498 } 499 500 static int __init acpi_button_init(void) 501 { 502 int result; 503 504 acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); 505 if (!acpi_button_dir) 506 return -ENODEV; 507 acpi_button_dir->owner = THIS_MODULE; 508 result = acpi_bus_register_driver(&acpi_button_driver); 509 if (result < 0) { 510 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); 511 return -ENODEV; 512 } 513 514 return 0; 515 } 516 517 static void __exit acpi_button_exit(void) 518 { 519 acpi_bus_unregister_driver(&acpi_button_driver); 520 521 if (acpi_power_dir) 522 remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, acpi_button_dir); 523 if (acpi_sleep_dir) 524 remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, acpi_button_dir); 525 if (acpi_lid_dir) 526 remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); 527 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); 528 } 529 530 module_init(acpi_button_init); 531 module_exit(acpi_button_exit); 532