ia64/linux-2.6.18-xen.hg

annotate drivers/acpi/button.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
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);