ia64/linux-2.6.18-xen.hg

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