ia64/linux-2.6.18-xen.hg

annotate drivers/acpi/button.c @ 912:dd42cdb0ab89

[IA64] Build blktap2 driver by default in x86 builds.

add CONFIG_XEN_BLKDEV_TAP2=y to buildconfigs/linux-defconfig_xen_ia64.

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