ia64/linux-2.6.18-xen.hg

view drivers/acpi/ibm_acpi.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 * ibm_acpi.c - IBM ThinkPad ACPI Extras
3 *
4 *
5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
22 #define IBM_VERSION "0.12a"
24 /*
25 * Changelog:
26 *
27 * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
28 * 2005-03-17 0.11 support for 600e, 770x
29 * thanks to Jamie Lentin <lentinj@dial.pipex.com>
30 * support for 770e, G41
31 * G40 and G41 don't have a thinklight
32 * temperatures no longer experimental
33 * experimental brightness control
34 * experimental volume control
35 * experimental fan enable/disable
36 * 2005-01-16 0.10 fix module loading on R30, R31
37 * 2005-01-16 0.9 support for 570, R30, R31
38 * ultrabay support on A22p, A3x
39 * limit arg for cmos, led, beep, drop experimental status
40 * more capable led control on A21e, A22p, T20-22, X20
41 * experimental temperatures and fan speed
42 * experimental embedded controller register dump
43 * mark more functions as __init, drop incorrect __exit
44 * use MODULE_VERSION
45 * thanks to Henrik Brix Andersen <brix@gentoo.org>
46 * fix parameter passing on module loading
47 * thanks to Rusty Russell <rusty@rustcorp.com.au>
48 * thanks to Jim Radford <radford@blackbean.org>
49 * 2004-11-08 0.8 fix init error case, don't return from a macro
50 * thanks to Chris Wright <chrisw@osdl.org>
51 * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20
52 * fix led control on A21e
53 * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device
54 * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20
55 * proc file format changed
56 * video_switch command
57 * experimental cmos control
58 * experimental led control
59 * experimental acpi sounds
60 * 2004-09-16 0.4 support for module parameters
61 * hotkey mask can be prefixed by 0x
62 * video output switching
63 * video expansion control
64 * ultrabay eject support
65 * removed lcd brightness/on/off control, didn't work
66 * 2004-08-17 0.3 support for R40
67 * lcd off, brightness control
68 * thinklight on/off
69 * 2004-08-14 0.2 support for T series, X20
70 * bluetooth enable/disable
71 * hotkey events disabled by default
72 * removed fan control, currently useless
73 * 2004-08-09 0.1 initial release, support for X series
74 */
76 #include <linux/kernel.h>
77 #include <linux/module.h>
78 #include <linux/init.h>
79 #include <linux/types.h>
80 #include <linux/proc_fs.h>
81 #include <asm/uaccess.h>
83 #include <acpi/acpi_drivers.h>
84 #include <acpi/acnamesp.h>
86 #define IBM_NAME "ibm"
87 #define IBM_DESC "IBM ThinkPad ACPI Extras"
88 #define IBM_FILE "ibm_acpi"
89 #define IBM_URL "http://ibm-acpi.sf.net/"
91 MODULE_AUTHOR("Borislav Deianov");
92 MODULE_DESCRIPTION(IBM_DESC);
93 MODULE_VERSION(IBM_VERSION);
94 MODULE_LICENSE("GPL");
96 #define IBM_DIR IBM_NAME
98 #define IBM_LOG IBM_FILE ": "
99 #define IBM_ERR KERN_ERR IBM_LOG
100 #define IBM_NOTICE KERN_NOTICE IBM_LOG
101 #define IBM_INFO KERN_INFO IBM_LOG
102 #define IBM_DEBUG KERN_DEBUG IBM_LOG
104 #define IBM_MAX_ACPI_ARGS 3
106 #define __unused __attribute__ ((unused))
108 static int experimental;
109 module_param(experimental, int, 0);
111 static acpi_handle root_handle = NULL;
113 #define IBM_HANDLE(object, parent, paths...) \
114 static acpi_handle object##_handle; \
115 static acpi_handle *object##_parent = &parent##_handle; \
116 static char *object##_path; \
117 static char *object##_paths[] = { paths }
119 /*
120 * The following models are supported to various degrees:
121 *
122 * 570, 600e, 600x, 770e, 770x
123 * A20m, A21e, A21m, A21p, A22p, A30, A30p, A31, A31p
124 * G40, G41
125 * R30, R31, R32, R40, R40e, R50, R50e, R50p, R51
126 * T20, T21, T22, T23, T30, T40, T40p, T41, T41p, T42, T42p, T43
127 * X20, X21, X22, X23, X24, X30, X31, X40
128 *
129 * The following models have no supported features:
130 *
131 * 240, 240x, i1400
132 *
133 * Still missing DSDTs for the following models:
134 *
135 * A20p, A22e, A22m
136 * R52
137 * S31
138 * T43p
139 */
141 IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
142 "\\_SB.PCI.ISA.EC", /* 570 */
143 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
144 "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
145 "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */
146 "\\_SB.PCI0.ICH3.EC0", /* R31 */
147 "\\_SB.PCI0.LPC.EC", /* all others */
148 );
150 IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
151 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
152 "\\_SB.PCI0.VID0", /* 770e */
153 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
154 "\\_SB.PCI0.AGP.VID", /* all others */
155 ); /* R30, R31 */
157 IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
159 IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
160 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
161 "\\CMS", /* R40, R40e */
162 ); /* all others */
163 #ifdef CONFIG_ACPI_IBM_DOCK
164 IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
165 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
166 "\\_SB.PCI0.PCI1.DOCK", /* all others */
167 "\\_SB.PCI.ISA.SLCE", /* 570 */
168 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
169 #endif
170 IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
171 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
172 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
173 ); /* A21e, R30, R31 */
175 IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
176 "_EJ0", /* all others */
177 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
179 IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
180 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
181 ); /* all others */
183 IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
184 "_EJ0", /* 770x */
185 ); /* all others */
187 /* don't list other alternatives as we install a notify handler on the 570 */
188 IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
190 IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
191 "^HKEY", /* R30, R31 */
192 "HKEY", /* all others */
193 ); /* 570 */
195 IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
196 IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
198 IBM_HANDLE(led, ec, "SLED", /* 570 */
199 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
200 "LED", /* all others */
201 ); /* R30, R31 */
203 IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
204 IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
205 IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
206 IBM_HANDLE(fans, ec, "FANS"); /* X31, X40 */
208 IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
209 "\\FSPD", /* 600e/x, 770e, 770x */
210 ); /* all others */
212 IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
213 "JFNS", /* 770x-JL */
214 ); /* all others */
216 #define IBM_HKEY_HID "IBM0068"
217 #define IBM_PCI_HID "PNP0A03"
219 struct ibm_struct {
220 char *name;
221 char param[32];
223 char *hid;
224 struct acpi_driver *driver;
226 int (*init) (void);
227 int (*read) (char *);
228 int (*write) (char *);
229 void (*exit) (void);
231 void (*notify) (struct ibm_struct *, u32);
232 acpi_handle *handle;
233 int type;
234 struct acpi_device *device;
236 int driver_registered;
237 int proc_created;
238 int init_called;
239 int notify_installed;
241 int experimental;
242 };
244 static struct proc_dir_entry *proc_dir = NULL;
246 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
247 #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
248 #define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
250 static int acpi_evalf(acpi_handle handle,
251 void *res, char *method, char *fmt, ...)
252 {
253 char *fmt0 = fmt;
254 struct acpi_object_list params;
255 union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
256 struct acpi_buffer result, *resultp;
257 union acpi_object out_obj;
258 acpi_status status;
259 va_list ap;
260 char res_type;
261 int success;
262 int quiet;
264 if (!*fmt) {
265 printk(IBM_ERR "acpi_evalf() called with empty format\n");
266 return 0;
267 }
269 if (*fmt == 'q') {
270 quiet = 1;
271 fmt++;
272 } else
273 quiet = 0;
275 res_type = *(fmt++);
277 params.count = 0;
278 params.pointer = &in_objs[0];
280 va_start(ap, fmt);
281 while (*fmt) {
282 char c = *(fmt++);
283 switch (c) {
284 case 'd': /* int */
285 in_objs[params.count].integer.value = va_arg(ap, int);
286 in_objs[params.count++].type = ACPI_TYPE_INTEGER;
287 break;
288 /* add more types as needed */
289 default:
290 printk(IBM_ERR "acpi_evalf() called "
291 "with invalid format character '%c'\n", c);
292 return 0;
293 }
294 }
295 va_end(ap);
297 if (res_type != 'v') {
298 result.length = sizeof(out_obj);
299 result.pointer = &out_obj;
300 resultp = &result;
301 } else
302 resultp = NULL;
304 status = acpi_evaluate_object(handle, method, &params, resultp);
306 switch (res_type) {
307 case 'd': /* int */
308 if (res)
309 *(int *)res = out_obj.integer.value;
310 success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
311 break;
312 case 'v': /* void */
313 success = status == AE_OK;
314 break;
315 /* add more types as needed */
316 default:
317 printk(IBM_ERR "acpi_evalf() called "
318 "with invalid format character '%c'\n", res_type);
319 return 0;
320 }
322 if (!success && !quiet)
323 printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
324 method, fmt0, status);
326 return success;
327 }
329 static void __unused acpi_print_int(acpi_handle handle, char *method)
330 {
331 int i;
333 if (acpi_evalf(handle, &i, method, "d"))
334 printk(IBM_INFO "%s = 0x%x\n", method, i);
335 else
336 printk(IBM_ERR "error calling %s\n", method);
337 }
339 static char *next_cmd(char **cmds)
340 {
341 char *start = *cmds;
342 char *end;
344 while ((end = strchr(start, ',')) && end == start)
345 start = end + 1;
347 if (!end)
348 return NULL;
350 *end = 0;
351 *cmds = end + 1;
352 return start;
353 }
355 static int driver_init(void)
356 {
357 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
358 printk(IBM_INFO "%s\n", IBM_URL);
360 return 0;
361 }
363 static int driver_read(char *p)
364 {
365 int len = 0;
367 len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
368 len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
370 return len;
371 }
373 static int hotkey_supported;
374 static int hotkey_mask_supported;
375 static int hotkey_orig_status;
376 static int hotkey_orig_mask;
378 static int hotkey_get(int *status, int *mask)
379 {
380 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
381 return 0;
383 if (hotkey_mask_supported)
384 if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
385 return 0;
387 return 1;
388 }
390 static int hotkey_set(int status, int mask)
391 {
392 int i;
394 if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
395 return 0;
397 if (hotkey_mask_supported)
398 for (i = 0; i < 32; i++) {
399 int bit = ((1 << i) & mask) != 0;
400 if (!acpi_evalf(hkey_handle,
401 NULL, "MHKM", "vdd", i + 1, bit))
402 return 0;
403 }
405 return 1;
406 }
408 static int hotkey_init(void)
409 {
410 /* hotkey not supported on 570 */
411 hotkey_supported = hkey_handle != NULL;
413 if (hotkey_supported) {
414 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
415 A30, R30, R31, T20-22, X20-21, X22-24 */
416 hotkey_mask_supported =
417 acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
419 if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
420 return -ENODEV;
421 }
423 return 0;
424 }
426 static int hotkey_read(char *p)
427 {
428 int status, mask;
429 int len = 0;
431 if (!hotkey_supported) {
432 len += sprintf(p + len, "status:\t\tnot supported\n");
433 return len;
434 }
436 if (!hotkey_get(&status, &mask))
437 return -EIO;
439 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
440 if (hotkey_mask_supported) {
441 len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
442 len += sprintf(p + len,
443 "commands:\tenable, disable, reset, <mask>\n");
444 } else {
445 len += sprintf(p + len, "mask:\t\tnot supported\n");
446 len += sprintf(p + len, "commands:\tenable, disable, reset\n");
447 }
449 return len;
450 }
452 static int hotkey_write(char *buf)
453 {
454 int status, mask;
455 char *cmd;
456 int do_cmd = 0;
458 if (!hotkey_supported)
459 return -ENODEV;
461 if (!hotkey_get(&status, &mask))
462 return -EIO;
464 while ((cmd = next_cmd(&buf))) {
465 if (strlencmp(cmd, "enable") == 0) {
466 status = 1;
467 } else if (strlencmp(cmd, "disable") == 0) {
468 status = 0;
469 } else if (strlencmp(cmd, "reset") == 0) {
470 status = hotkey_orig_status;
471 mask = hotkey_orig_mask;
472 } else if (sscanf(cmd, "0x%x", &mask) == 1) {
473 /* mask set */
474 } else if (sscanf(cmd, "%x", &mask) == 1) {
475 /* mask set */
476 } else
477 return -EINVAL;
478 do_cmd = 1;
479 }
481 if (do_cmd && !hotkey_set(status, mask))
482 return -EIO;
484 return 0;
485 }
487 static void hotkey_exit(void)
488 {
489 if (hotkey_supported)
490 hotkey_set(hotkey_orig_status, hotkey_orig_mask);
491 }
493 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
494 {
495 int hkey;
497 if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
498 acpi_bus_generate_event(ibm->device, event, hkey);
499 else {
500 printk(IBM_ERR "unknown hotkey event %d\n", event);
501 acpi_bus_generate_event(ibm->device, event, 0);
502 }
503 }
505 static int bluetooth_supported;
507 static int bluetooth_init(void)
508 {
509 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
510 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
511 bluetooth_supported = hkey_handle &&
512 acpi_evalf(hkey_handle, NULL, "GBDC", "qv");
514 return 0;
515 }
517 static int bluetooth_status(void)
518 {
519 int status;
521 if (!bluetooth_supported ||
522 !acpi_evalf(hkey_handle, &status, "GBDC", "d"))
523 status = 0;
525 return status;
526 }
528 static int bluetooth_read(char *p)
529 {
530 int len = 0;
531 int status = bluetooth_status();
533 if (!bluetooth_supported)
534 len += sprintf(p + len, "status:\t\tnot supported\n");
535 else if (!(status & 1))
536 len += sprintf(p + len, "status:\t\tnot installed\n");
537 else {
538 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
539 len += sprintf(p + len, "commands:\tenable, disable\n");
540 }
542 return len;
543 }
545 static int bluetooth_write(char *buf)
546 {
547 int status = bluetooth_status();
548 char *cmd;
549 int do_cmd = 0;
551 if (!bluetooth_supported)
552 return -ENODEV;
554 while ((cmd = next_cmd(&buf))) {
555 if (strlencmp(cmd, "enable") == 0) {
556 status |= 2;
557 } else if (strlencmp(cmd, "disable") == 0) {
558 status &= ~2;
559 } else
560 return -EINVAL;
561 do_cmd = 1;
562 }
564 if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
565 return -EIO;
567 return 0;
568 }
570 static int wan_supported;
572 static int wan_init(void)
573 {
574 wan_supported = hkey_handle &&
575 acpi_evalf(hkey_handle, NULL, "GWAN", "qv");
577 return 0;
578 }
580 static int wan_status(void)
581 {
582 int status;
584 if (!wan_supported ||
585 !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
586 status = 0;
588 return status;
589 }
591 static int wan_read(char *p)
592 {
593 int len = 0;
594 int status = wan_status();
596 if (!wan_supported)
597 len += sprintf(p + len, "status:\t\tnot supported\n");
598 else if (!(status & 1))
599 len += sprintf(p + len, "status:\t\tnot installed\n");
600 else {
601 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
602 len += sprintf(p + len, "commands:\tenable, disable\n");
603 }
605 return len;
606 }
608 static int wan_write(char *buf)
609 {
610 int status = wan_status();
611 char *cmd;
612 int do_cmd = 0;
614 if (!wan_supported)
615 return -ENODEV;
617 while ((cmd = next_cmd(&buf))) {
618 if (strlencmp(cmd, "enable") == 0) {
619 status |= 2;
620 } else if (strlencmp(cmd, "disable") == 0) {
621 status &= ~2;
622 } else
623 return -EINVAL;
624 do_cmd = 1;
625 }
627 if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
628 return -EIO;
630 return 0;
631 }
633 static int video_supported;
634 static int video_orig_autosw;
636 #define VIDEO_570 1
637 #define VIDEO_770 2
638 #define VIDEO_NEW 3
640 static int video_init(void)
641 {
642 int ivga;
644 if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
645 /* G41, assume IVGA doesn't change */
646 vid_handle = vid2_handle;
648 if (!vid_handle)
649 /* video switching not supported on R30, R31 */
650 video_supported = 0;
651 else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
652 /* 570 */
653 video_supported = VIDEO_570;
654 else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
655 /* 600e/x, 770e, 770x */
656 video_supported = VIDEO_770;
657 else
658 /* all others */
659 video_supported = VIDEO_NEW;
661 return 0;
662 }
664 static int video_status(void)
665 {
666 int status = 0;
667 int i;
669 if (video_supported == VIDEO_570) {
670 if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
671 status = i & 3;
672 } else if (video_supported == VIDEO_770) {
673 if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
674 status |= 0x01 * i;
675 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
676 status |= 0x02 * i;
677 } else if (video_supported == VIDEO_NEW) {
678 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
679 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
680 status |= 0x02 * i;
682 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0);
683 if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
684 status |= 0x01 * i;
685 if (acpi_evalf(NULL, &i, "\\VCDD", "d"))
686 status |= 0x08 * i;
687 }
689 return status;
690 }
692 static int video_autosw(void)
693 {
694 int autosw = 0;
696 if (video_supported == VIDEO_570)
697 acpi_evalf(vid_handle, &autosw, "SWIT", "d");
698 else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW)
699 acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
701 return autosw & 1;
702 }
704 static int video_read(char *p)
705 {
706 int status = video_status();
707 int autosw = video_autosw();
708 int len = 0;
710 if (!video_supported) {
711 len += sprintf(p + len, "status:\t\tnot supported\n");
712 return len;
713 }
715 len += sprintf(p + len, "status:\t\tsupported\n");
716 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
717 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
718 if (video_supported == VIDEO_NEW)
719 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
720 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
721 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
722 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
723 if (video_supported == VIDEO_NEW)
724 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
725 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
726 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
728 return len;
729 }
731 static int video_switch(void)
732 {
733 int autosw = video_autosw();
734 int ret;
736 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
737 return -EIO;
738 ret = video_supported == VIDEO_570 ?
739 acpi_evalf(ec_handle, NULL, "_Q16", "v") :
740 acpi_evalf(vid_handle, NULL, "VSWT", "v");
741 acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
743 return ret;
744 }
746 static int video_expand(void)
747 {
748 if (video_supported == VIDEO_570)
749 return acpi_evalf(ec_handle, NULL, "_Q17", "v");
750 else if (video_supported == VIDEO_770)
751 return acpi_evalf(vid_handle, NULL, "VEXP", "v");
752 else
753 return acpi_evalf(NULL, NULL, "\\VEXP", "v");
754 }
756 static int video_switch2(int status)
757 {
758 int ret;
760 if (video_supported == VIDEO_570) {
761 ret = acpi_evalf(NULL, NULL,
762 "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
763 } else if (video_supported == VIDEO_770) {
764 int autosw = video_autosw();
765 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
766 return -EIO;
768 ret = acpi_evalf(vid_handle, NULL,
769 "ASWT", "vdd", status * 0x100, 0);
771 acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
772 } else {
773 ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
774 acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
775 }
777 return ret;
778 }
780 static int video_write(char *buf)
781 {
782 char *cmd;
783 int enable, disable, status;
785 if (!video_supported)
786 return -ENODEV;
788 enable = disable = 0;
790 while ((cmd = next_cmd(&buf))) {
791 if (strlencmp(cmd, "lcd_enable") == 0) {
792 enable |= 0x01;
793 } else if (strlencmp(cmd, "lcd_disable") == 0) {
794 disable |= 0x01;
795 } else if (strlencmp(cmd, "crt_enable") == 0) {
796 enable |= 0x02;
797 } else if (strlencmp(cmd, "crt_disable") == 0) {
798 disable |= 0x02;
799 } else if (video_supported == VIDEO_NEW &&
800 strlencmp(cmd, "dvi_enable") == 0) {
801 enable |= 0x08;
802 } else if (video_supported == VIDEO_NEW &&
803 strlencmp(cmd, "dvi_disable") == 0) {
804 disable |= 0x08;
805 } else if (strlencmp(cmd, "auto_enable") == 0) {
806 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
807 return -EIO;
808 } else if (strlencmp(cmd, "auto_disable") == 0) {
809 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0))
810 return -EIO;
811 } else if (strlencmp(cmd, "video_switch") == 0) {
812 if (!video_switch())
813 return -EIO;
814 } else if (strlencmp(cmd, "expand_toggle") == 0) {
815 if (!video_expand())
816 return -EIO;
817 } else
818 return -EINVAL;
819 }
821 if (enable || disable) {
822 status = (video_status() & 0x0f & ~disable) | enable;
823 if (!video_switch2(status))
824 return -EIO;
825 }
827 return 0;
828 }
830 static void video_exit(void)
831 {
832 acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
833 }
835 static int light_supported;
836 static int light_status_supported;
838 static int light_init(void)
839 {
840 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
841 light_supported = (cmos_handle || lght_handle) && !ledb_handle;
843 if (light_supported)
844 /* light status not supported on
845 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
846 light_status_supported = acpi_evalf(ec_handle, NULL,
847 "KBLT", "qv");
849 return 0;
850 }
852 static int light_read(char *p)
853 {
854 int len = 0;
855 int status = 0;
857 if (!light_supported) {
858 len += sprintf(p + len, "status:\t\tnot supported\n");
859 } else if (!light_status_supported) {
860 len += sprintf(p + len, "status:\t\tunknown\n");
861 len += sprintf(p + len, "commands:\ton, off\n");
862 } else {
863 if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
864 return -EIO;
865 len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
866 len += sprintf(p + len, "commands:\ton, off\n");
867 }
869 return len;
870 }
872 static int light_write(char *buf)
873 {
874 int cmos_cmd, lght_cmd;
875 char *cmd;
876 int success;
878 if (!light_supported)
879 return -ENODEV;
881 while ((cmd = next_cmd(&buf))) {
882 if (strlencmp(cmd, "on") == 0) {
883 cmos_cmd = 0x0c;
884 lght_cmd = 1;
885 } else if (strlencmp(cmd, "off") == 0) {
886 cmos_cmd = 0x0d;
887 lght_cmd = 0;
888 } else
889 return -EINVAL;
891 success = cmos_handle ?
892 acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
893 acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
894 if (!success)
895 return -EIO;
896 }
898 return 0;
899 }
901 static int _sta(acpi_handle handle)
902 {
903 int status;
905 if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
906 status = 0;
908 return status;
909 }
910 #ifdef CONFIG_ACPI_IBM_DOCK
911 #define dock_docked() (_sta(dock_handle) & 1)
913 static int dock_read(char *p)
914 {
915 int len = 0;
916 int docked = dock_docked();
918 if (!dock_handle)
919 len += sprintf(p + len, "status:\t\tnot supported\n");
920 else if (!docked)
921 len += sprintf(p + len, "status:\t\tundocked\n");
922 else {
923 len += sprintf(p + len, "status:\t\tdocked\n");
924 len += sprintf(p + len, "commands:\tdock, undock\n");
925 }
927 return len;
928 }
930 static int dock_write(char *buf)
931 {
932 char *cmd;
934 if (!dock_docked())
935 return -ENODEV;
937 while ((cmd = next_cmd(&buf))) {
938 if (strlencmp(cmd, "undock") == 0) {
939 if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
940 !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
941 return -EIO;
942 } else if (strlencmp(cmd, "dock") == 0) {
943 if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
944 return -EIO;
945 } else
946 return -EINVAL;
947 }
949 return 0;
950 }
952 static void dock_notify(struct ibm_struct *ibm, u32 event)
953 {
954 int docked = dock_docked();
955 int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
957 if (event == 1 && !pci) /* 570 */
958 acpi_bus_generate_event(ibm->device, event, 1); /* button */
959 else if (event == 1 && pci) /* 570 */
960 acpi_bus_generate_event(ibm->device, event, 3); /* dock */
961 else if (event == 3 && docked)
962 acpi_bus_generate_event(ibm->device, event, 1); /* button */
963 else if (event == 3 && !docked)
964 acpi_bus_generate_event(ibm->device, event, 2); /* undock */
965 else if (event == 0 && docked)
966 acpi_bus_generate_event(ibm->device, event, 3); /* dock */
967 else {
968 printk(IBM_ERR "unknown dock event %d, status %d\n",
969 event, _sta(dock_handle));
970 acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
971 }
972 }
973 #endif
975 static int bay_status_supported;
976 static int bay_status2_supported;
977 static int bay_eject_supported;
978 static int bay_eject2_supported;
980 static int bay_init(void)
981 {
982 bay_status_supported = bay_handle &&
983 acpi_evalf(bay_handle, NULL, "_STA", "qv");
984 bay_status2_supported = bay2_handle &&
985 acpi_evalf(bay2_handle, NULL, "_STA", "qv");
987 bay_eject_supported = bay_handle && bay_ej_handle &&
988 (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
989 bay_eject2_supported = bay2_handle && bay2_ej_handle &&
990 (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
992 return 0;
993 }
995 #define bay_occupied(b) (_sta(b##_handle) & 1)
997 static int bay_read(char *p)
998 {
999 int len = 0;
1000 int occupied = bay_occupied(bay);
1001 int occupied2 = bay_occupied(bay2);
1002 int eject, eject2;
1004 len += sprintf(p + len, "status:\t\t%s\n", bay_status_supported ?
1005 (occupied ? "occupied" : "unoccupied") :
1006 "not supported");
1007 if (bay_status2_supported)
1008 len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
1009 "occupied" : "unoccupied");
1011 eject = bay_eject_supported && occupied;
1012 eject2 = bay_eject2_supported && occupied2;
1014 if (eject && eject2)
1015 len += sprintf(p + len, "commands:\teject, eject2\n");
1016 else if (eject)
1017 len += sprintf(p + len, "commands:\teject\n");
1018 else if (eject2)
1019 len += sprintf(p + len, "commands:\teject2\n");
1021 return len;
1024 static int bay_write(char *buf)
1026 char *cmd;
1028 if (!bay_eject_supported && !bay_eject2_supported)
1029 return -ENODEV;
1031 while ((cmd = next_cmd(&buf))) {
1032 if (bay_eject_supported && strlencmp(cmd, "eject") == 0) {
1033 if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
1034 return -EIO;
1035 } else if (bay_eject2_supported &&
1036 strlencmp(cmd, "eject2") == 0) {
1037 if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
1038 return -EIO;
1039 } else
1040 return -EINVAL;
1043 return 0;
1046 static void bay_notify(struct ibm_struct *ibm, u32 event)
1048 acpi_bus_generate_event(ibm->device, event, 0);
1051 static int cmos_read(char *p)
1053 int len = 0;
1055 /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
1056 R30, R31, T20-22, X20-21 */
1057 if (!cmos_handle)
1058 len += sprintf(p + len, "status:\t\tnot supported\n");
1059 else {
1060 len += sprintf(p + len, "status:\t\tsupported\n");
1061 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
1064 return len;
1067 static int cmos_eval(int cmos_cmd)
1069 if (cmos_handle)
1070 return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
1071 else
1072 return 1;
1075 static int cmos_write(char *buf)
1077 char *cmd;
1078 int cmos_cmd;
1080 if (!cmos_handle)
1081 return -EINVAL;
1083 while ((cmd = next_cmd(&buf))) {
1084 if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
1085 cmos_cmd >= 0 && cmos_cmd <= 21) {
1086 /* cmos_cmd set */
1087 } else
1088 return -EINVAL;
1090 if (!cmos_eval(cmos_cmd))
1091 return -EIO;
1094 return 0;
1097 static int led_supported;
1099 #define LED_570 1
1100 #define LED_OLD 2
1101 #define LED_NEW 3
1103 static int led_init(void)
1105 if (!led_handle)
1106 /* led not supported on R30, R31 */
1107 led_supported = 0;
1108 else if (strlencmp(led_path, "SLED") == 0)
1109 /* 570 */
1110 led_supported = LED_570;
1111 else if (strlencmp(led_path, "SYSL") == 0)
1112 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
1113 led_supported = LED_OLD;
1114 else
1115 /* all others */
1116 led_supported = LED_NEW;
1118 return 0;
1121 #define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
1123 static int led_read(char *p)
1125 int len = 0;
1127 if (!led_supported) {
1128 len += sprintf(p + len, "status:\t\tnot supported\n");
1129 return len;
1131 len += sprintf(p + len, "status:\t\tsupported\n");
1133 if (led_supported == LED_570) {
1134 /* 570 */
1135 int i, status;
1136 for (i = 0; i < 8; i++) {
1137 if (!acpi_evalf(ec_handle,
1138 &status, "GLED", "dd", 1 << i))
1139 return -EIO;
1140 len += sprintf(p + len, "%d:\t\t%s\n",
1141 i, led_status(status));
1145 len += sprintf(p + len, "commands:\t"
1146 "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
1148 return len;
1151 /* off, on, blink */
1152 static const int led_sled_arg1[] = { 0, 1, 3 };
1153 static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
1154 static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
1155 static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
1157 #define EC_HLCL 0x0c
1158 #define EC_HLBL 0x0d
1159 #define EC_HLMS 0x0e
1161 static int led_write(char *buf)
1163 char *cmd;
1164 int led, ind, ret;
1166 if (!led_supported)
1167 return -ENODEV;
1169 while ((cmd = next_cmd(&buf))) {
1170 if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
1171 return -EINVAL;
1173 if (strstr(cmd, "off")) {
1174 ind = 0;
1175 } else if (strstr(cmd, "on")) {
1176 ind = 1;
1177 } else if (strstr(cmd, "blink")) {
1178 ind = 2;
1179 } else
1180 return -EINVAL;
1182 if (led_supported == LED_570) {
1183 /* 570 */
1184 led = 1 << led;
1185 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
1186 led, led_sled_arg1[ind]))
1187 return -EIO;
1188 } else if (led_supported == LED_OLD) {
1189 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
1190 led = 1 << led;
1191 ret = ec_write(EC_HLMS, led);
1192 if (ret >= 0)
1193 ret =
1194 ec_write(EC_HLBL, led * led_exp_hlbl[ind]);
1195 if (ret >= 0)
1196 ret =
1197 ec_write(EC_HLCL, led * led_exp_hlcl[ind]);
1198 if (ret < 0)
1199 return ret;
1200 } else {
1201 /* all others */
1202 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
1203 led, led_led_arg1[ind]))
1204 return -EIO;
1208 return 0;
1211 static int beep_read(char *p)
1213 int len = 0;
1215 if (!beep_handle)
1216 len += sprintf(p + len, "status:\t\tnot supported\n");
1217 else {
1218 len += sprintf(p + len, "status:\t\tsupported\n");
1219 len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
1222 return len;
1225 static int beep_write(char *buf)
1227 char *cmd;
1228 int beep_cmd;
1230 if (!beep_handle)
1231 return -ENODEV;
1233 while ((cmd = next_cmd(&buf))) {
1234 if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
1235 beep_cmd >= 0 && beep_cmd <= 17) {
1236 /* beep_cmd set */
1237 } else
1238 return -EINVAL;
1239 if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
1240 return -EIO;
1243 return 0;
1246 static int acpi_ec_read(int i, u8 * p)
1248 int v;
1250 if (ecrd_handle) {
1251 if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
1252 return 0;
1253 *p = v;
1254 } else {
1255 if (ec_read(i, p) < 0)
1256 return 0;
1259 return 1;
1262 static int acpi_ec_write(int i, u8 v)
1264 if (ecwr_handle) {
1265 if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
1266 return 0;
1267 } else {
1268 if (ec_write(i, v) < 0)
1269 return 0;
1272 return 1;
1275 static int thermal_tmp_supported;
1276 static int thermal_updt_supported;
1278 static int thermal_init(void)
1280 /* temperatures not supported on 570, G4x, R30, R31, R32 */
1281 thermal_tmp_supported = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
1283 /* 600e/x, 770e, 770x */
1284 thermal_updt_supported = acpi_evalf(ec_handle, NULL, "UPDT", "qv");
1286 return 0;
1289 static int thermal_read(char *p)
1291 int len = 0;
1293 if (!thermal_tmp_supported)
1294 len += sprintf(p + len, "temperatures:\tnot supported\n");
1295 else {
1296 int i, t;
1297 char tmpi[] = "TMPi";
1298 s8 tmp[8];
1300 if (thermal_updt_supported)
1301 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
1302 return -EIO;
1304 for (i = 0; i < 8; i++) {
1305 tmpi[3] = '0' + i;
1306 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
1307 return -EIO;
1308 if (thermal_updt_supported)
1309 tmp[i] = (t - 2732 + 5) / 10;
1310 else
1311 tmp[i] = t;
1314 len += sprintf(p + len,
1315 "temperatures:\t%d %d %d %d %d %d %d %d\n",
1316 tmp[0], tmp[1], tmp[2], tmp[3],
1317 tmp[4], tmp[5], tmp[6], tmp[7]);
1320 return len;
1323 static u8 ecdump_regs[256];
1325 static int ecdump_read(char *p)
1327 int len = 0;
1328 int i, j;
1329 u8 v;
1331 len += sprintf(p + len, "EC "
1332 " +00 +01 +02 +03 +04 +05 +06 +07"
1333 " +08 +09 +0a +0b +0c +0d +0e +0f\n");
1334 for (i = 0; i < 256; i += 16) {
1335 len += sprintf(p + len, "EC 0x%02x:", i);
1336 for (j = 0; j < 16; j++) {
1337 if (!acpi_ec_read(i + j, &v))
1338 break;
1339 if (v != ecdump_regs[i + j])
1340 len += sprintf(p + len, " *%02x", v);
1341 else
1342 len += sprintf(p + len, " %02x", v);
1343 ecdump_regs[i + j] = v;
1345 len += sprintf(p + len, "\n");
1346 if (j != 16)
1347 break;
1350 /* These are way too dangerous to advertise openly... */
1351 #if 0
1352 len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
1353 " (<offset> is 00-ff, <value> is 00-ff)\n");
1354 len += sprintf(p + len, "commands:\t0x<offset> <value> "
1355 " (<offset> is 00-ff, <value> is 0-255)\n");
1356 #endif
1357 return len;
1360 static int ecdump_write(char *buf)
1362 char *cmd;
1363 int i, v;
1365 while ((cmd = next_cmd(&buf))) {
1366 if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
1367 /* i and v set */
1368 } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
1369 /* i and v set */
1370 } else
1371 return -EINVAL;
1372 if (i >= 0 && i < 256 && v >= 0 && v < 256) {
1373 if (!acpi_ec_write(i, v))
1374 return -EIO;
1375 } else
1376 return -EINVAL;
1379 return 0;
1382 static int brightness_offset = 0x31;
1384 static int brightness_read(char *p)
1386 int len = 0;
1387 u8 level;
1389 if (!acpi_ec_read(brightness_offset, &level)) {
1390 len += sprintf(p + len, "level:\t\tunreadable\n");
1391 } else {
1392 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
1393 len += sprintf(p + len, "commands:\tup, down\n");
1394 len += sprintf(p + len, "commands:\tlevel <level>"
1395 " (<level> is 0-7)\n");
1398 return len;
1401 #define BRIGHTNESS_UP 4
1402 #define BRIGHTNESS_DOWN 5
1404 static int brightness_write(char *buf)
1406 int cmos_cmd, inc, i;
1407 u8 level;
1408 int new_level;
1409 char *cmd;
1411 while ((cmd = next_cmd(&buf))) {
1412 if (!acpi_ec_read(brightness_offset, &level))
1413 return -EIO;
1414 level &= 7;
1416 if (strlencmp(cmd, "up") == 0) {
1417 new_level = level == 7 ? 7 : level + 1;
1418 } else if (strlencmp(cmd, "down") == 0) {
1419 new_level = level == 0 ? 0 : level - 1;
1420 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
1421 new_level >= 0 && new_level <= 7) {
1422 /* new_level set */
1423 } else
1424 return -EINVAL;
1426 cmos_cmd = new_level > level ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
1427 inc = new_level > level ? 1 : -1;
1428 for (i = level; i != new_level; i += inc) {
1429 if (!cmos_eval(cmos_cmd))
1430 return -EIO;
1431 if (!acpi_ec_write(brightness_offset, i + inc))
1432 return -EIO;
1436 return 0;
1439 static int volume_offset = 0x30;
1441 static int volume_read(char *p)
1443 int len = 0;
1444 u8 level;
1446 if (!acpi_ec_read(volume_offset, &level)) {
1447 len += sprintf(p + len, "level:\t\tunreadable\n");
1448 } else {
1449 len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
1450 len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
1451 len += sprintf(p + len, "commands:\tup, down, mute\n");
1452 len += sprintf(p + len, "commands:\tlevel <level>"
1453 " (<level> is 0-15)\n");
1456 return len;
1459 #define VOLUME_DOWN 0
1460 #define VOLUME_UP 1
1461 #define VOLUME_MUTE 2
1463 static int volume_write(char *buf)
1465 int cmos_cmd, inc, i;
1466 u8 level, mute;
1467 int new_level, new_mute;
1468 char *cmd;
1470 while ((cmd = next_cmd(&buf))) {
1471 if (!acpi_ec_read(volume_offset, &level))
1472 return -EIO;
1473 new_mute = mute = level & 0x40;
1474 new_level = level = level & 0xf;
1476 if (strlencmp(cmd, "up") == 0) {
1477 if (mute)
1478 new_mute = 0;
1479 else
1480 new_level = level == 15 ? 15 : level + 1;
1481 } else if (strlencmp(cmd, "down") == 0) {
1482 if (mute)
1483 new_mute = 0;
1484 else
1485 new_level = level == 0 ? 0 : level - 1;
1486 } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
1487 new_level >= 0 && new_level <= 15) {
1488 /* new_level set */
1489 } else if (strlencmp(cmd, "mute") == 0) {
1490 new_mute = 0x40;
1491 } else
1492 return -EINVAL;
1494 if (new_level != level) { /* mute doesn't change */
1495 cmos_cmd = new_level > level ? VOLUME_UP : VOLUME_DOWN;
1496 inc = new_level > level ? 1 : -1;
1498 if (mute && (!cmos_eval(cmos_cmd) ||
1499 !acpi_ec_write(volume_offset, level)))
1500 return -EIO;
1502 for (i = level; i != new_level; i += inc)
1503 if (!cmos_eval(cmos_cmd) ||
1504 !acpi_ec_write(volume_offset, i + inc))
1505 return -EIO;
1507 if (mute && (!cmos_eval(VOLUME_MUTE) ||
1508 !acpi_ec_write(volume_offset,
1509 new_level + mute)))
1510 return -EIO;
1513 if (new_mute != mute) { /* level doesn't change */
1514 cmos_cmd = new_mute ? VOLUME_MUTE : VOLUME_UP;
1516 if (!cmos_eval(cmos_cmd) ||
1517 !acpi_ec_write(volume_offset, level + new_mute))
1518 return -EIO;
1522 return 0;
1525 static int fan_status_offset = 0x2f;
1526 static int fan_rpm_offset = 0x84;
1528 static int fan_read(char *p)
1530 int len = 0;
1531 int s;
1532 u8 lo, hi, status;
1534 if (gfan_handle) {
1535 /* 570, 600e/x, 770e, 770x */
1536 if (!acpi_evalf(gfan_handle, &s, NULL, "d"))
1537 return -EIO;
1539 len += sprintf(p + len, "level:\t\t%d\n", s);
1540 } else {
1541 /* all except 570, 600e/x, 770e, 770x */
1542 if (!acpi_ec_read(fan_status_offset, &status))
1543 len += sprintf(p + len, "status:\t\tunreadable\n");
1544 else
1545 len += sprintf(p + len, "status:\t\t%s\n",
1546 enabled(status, 7));
1548 if (!acpi_ec_read(fan_rpm_offset, &lo) ||
1549 !acpi_ec_read(fan_rpm_offset + 1, &hi))
1550 len += sprintf(p + len, "speed:\t\tunreadable\n");
1551 else
1552 len += sprintf(p + len, "speed:\t\t%d\n",
1553 (hi << 8) + lo);
1556 if (sfan_handle)
1557 /* 570, 770x-JL */
1558 len += sprintf(p + len, "commands:\tlevel <level>"
1559 " (<level> is 0-7)\n");
1560 if (!gfan_handle)
1561 /* all except 570, 600e/x, 770e, 770x */
1562 len += sprintf(p + len, "commands:\tenable, disable\n");
1563 if (fans_handle)
1564 /* X31, X40 */
1565 len += sprintf(p + len, "commands:\tspeed <speed>"
1566 " (<speed> is 0-65535)\n");
1568 return len;
1571 static int fan_write(char *buf)
1573 char *cmd;
1574 int level, speed;
1576 while ((cmd = next_cmd(&buf))) {
1577 if (sfan_handle &&
1578 sscanf(cmd, "level %d", &level) == 1 &&
1579 level >= 0 && level <= 7) {
1580 /* 570, 770x-JL */
1581 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
1582 return -EIO;
1583 } else if (!gfan_handle && strlencmp(cmd, "enable") == 0) {
1584 /* all except 570, 600e/x, 770e, 770x */
1585 if (!acpi_ec_write(fan_status_offset, 0x80))
1586 return -EIO;
1587 } else if (!gfan_handle && strlencmp(cmd, "disable") == 0) {
1588 /* all except 570, 600e/x, 770e, 770x */
1589 if (!acpi_ec_write(fan_status_offset, 0x00))
1590 return -EIO;
1591 } else if (fans_handle &&
1592 sscanf(cmd, "speed %d", &speed) == 1 &&
1593 speed >= 0 && speed <= 65535) {
1594 /* X31, X40 */
1595 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
1596 speed, speed, speed))
1597 return -EIO;
1598 } else
1599 return -EINVAL;
1602 return 0;
1605 static struct ibm_struct ibms[] = {
1607 .name = "driver",
1608 .init = driver_init,
1609 .read = driver_read,
1610 },
1612 .name = "hotkey",
1613 .hid = IBM_HKEY_HID,
1614 .init = hotkey_init,
1615 .read = hotkey_read,
1616 .write = hotkey_write,
1617 .exit = hotkey_exit,
1618 .notify = hotkey_notify,
1619 .handle = &hkey_handle,
1620 .type = ACPI_DEVICE_NOTIFY,
1621 },
1623 .name = "bluetooth",
1624 .init = bluetooth_init,
1625 .read = bluetooth_read,
1626 .write = bluetooth_write,
1627 },
1629 .name = "wan",
1630 .init = wan_init,
1631 .read = wan_read,
1632 .write = wan_write,
1633 .experimental = 1,
1634 },
1636 .name = "video",
1637 .init = video_init,
1638 .read = video_read,
1639 .write = video_write,
1640 .exit = video_exit,
1641 },
1643 .name = "light",
1644 .init = light_init,
1645 .read = light_read,
1646 .write = light_write,
1647 },
1648 #ifdef CONFIG_ACPI_IBM_DOCK
1650 .name = "dock",
1651 .read = dock_read,
1652 .write = dock_write,
1653 .notify = dock_notify,
1654 .handle = &dock_handle,
1655 .type = ACPI_SYSTEM_NOTIFY,
1656 },
1658 .name = "dock",
1659 .hid = IBM_PCI_HID,
1660 .notify = dock_notify,
1661 .handle = &pci_handle,
1662 .type = ACPI_SYSTEM_NOTIFY,
1663 },
1664 #endif
1666 .name = "bay",
1667 .init = bay_init,
1668 .read = bay_read,
1669 .write = bay_write,
1670 .notify = bay_notify,
1671 .handle = &bay_handle,
1672 .type = ACPI_SYSTEM_NOTIFY,
1673 },
1675 .name = "cmos",
1676 .read = cmos_read,
1677 .write = cmos_write,
1678 },
1680 .name = "led",
1681 .init = led_init,
1682 .read = led_read,
1683 .write = led_write,
1684 },
1686 .name = "beep",
1687 .read = beep_read,
1688 .write = beep_write,
1689 },
1691 .name = "thermal",
1692 .init = thermal_init,
1693 .read = thermal_read,
1694 },
1696 .name = "ecdump",
1697 .read = ecdump_read,
1698 .write = ecdump_write,
1699 .experimental = 1,
1700 },
1702 .name = "brightness",
1703 .read = brightness_read,
1704 .write = brightness_write,
1705 .experimental = 1,
1706 },
1708 .name = "volume",
1709 .read = volume_read,
1710 .write = volume_write,
1711 .experimental = 1,
1712 },
1714 .name = "fan",
1715 .read = fan_read,
1716 .write = fan_write,
1717 .experimental = 1,
1718 },
1719 };
1721 static int dispatch_read(char *page, char **start, off_t off, int count,
1722 int *eof, void *data)
1724 struct ibm_struct *ibm = (struct ibm_struct *)data;
1725 int len;
1727 if (!ibm || !ibm->read)
1728 return -EINVAL;
1730 len = ibm->read(page);
1731 if (len < 0)
1732 return len;
1734 if (len <= off + count)
1735 *eof = 1;
1736 *start = page + off;
1737 len -= off;
1738 if (len > count)
1739 len = count;
1740 if (len < 0)
1741 len = 0;
1743 return len;
1746 static int dispatch_write(struct file *file, const char __user * userbuf,
1747 unsigned long count, void *data)
1749 struct ibm_struct *ibm = (struct ibm_struct *)data;
1750 char *kernbuf;
1751 int ret;
1753 if (!ibm || !ibm->write)
1754 return -EINVAL;
1756 kernbuf = kmalloc(count + 2, GFP_KERNEL);
1757 if (!kernbuf)
1758 return -ENOMEM;
1760 if (copy_from_user(kernbuf, userbuf, count)) {
1761 kfree(kernbuf);
1762 return -EFAULT;
1765 kernbuf[count] = 0;
1766 strcat(kernbuf, ",");
1767 ret = ibm->write(kernbuf);
1768 if (ret == 0)
1769 ret = count;
1771 kfree(kernbuf);
1773 return ret;
1776 static void dispatch_notify(acpi_handle handle, u32 event, void *data)
1778 struct ibm_struct *ibm = (struct ibm_struct *)data;
1780 if (!ibm || !ibm->notify)
1781 return;
1783 ibm->notify(ibm, event);
1786 static int __init setup_notify(struct ibm_struct *ibm)
1788 acpi_status status;
1789 int ret;
1791 if (!*ibm->handle)
1792 return 0;
1794 ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
1795 if (ret < 0) {
1796 printk(IBM_ERR "%s device not present\n", ibm->name);
1797 return 0;
1800 acpi_driver_data(ibm->device) = ibm;
1801 sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
1803 status = acpi_install_notify_handler(*ibm->handle, ibm->type,
1804 dispatch_notify, ibm);
1805 if (ACPI_FAILURE(status)) {
1806 printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
1807 ibm->name, status);
1808 return -ENODEV;
1811 return 0;
1814 static int __init ibm_device_add(struct acpi_device *device)
1816 return 0;
1819 static int __init register_driver(struct ibm_struct *ibm)
1821 int ret;
1823 ibm->driver = kmalloc(sizeof(struct acpi_driver), GFP_KERNEL);
1824 if (!ibm->driver) {
1825 printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
1826 return -1;
1829 memset(ibm->driver, 0, sizeof(struct acpi_driver));
1830 sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name);
1831 ibm->driver->ids = ibm->hid;
1832 ibm->driver->ops.add = &ibm_device_add;
1834 ret = acpi_bus_register_driver(ibm->driver);
1835 if (ret < 0) {
1836 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
1837 ibm->hid, ret);
1838 kfree(ibm->driver);
1841 return ret;
1844 static int __init ibm_init(struct ibm_struct *ibm)
1846 int ret;
1847 struct proc_dir_entry *entry;
1849 if (ibm->experimental && !experimental)
1850 return 0;
1852 if (ibm->hid) {
1853 ret = register_driver(ibm);
1854 if (ret < 0)
1855 return ret;
1856 ibm->driver_registered = 1;
1859 if (ibm->init) {
1860 ret = ibm->init();
1861 if (ret != 0)
1862 return ret;
1863 ibm->init_called = 1;
1866 if (ibm->read) {
1867 entry = create_proc_entry(ibm->name,
1868 S_IFREG | S_IRUGO | S_IWUSR,
1869 proc_dir);
1870 if (!entry) {
1871 printk(IBM_ERR "unable to create proc entry %s\n",
1872 ibm->name);
1873 return -ENODEV;
1875 entry->owner = THIS_MODULE;
1876 entry->data = ibm;
1877 entry->read_proc = &dispatch_read;
1878 if (ibm->write)
1879 entry->write_proc = &dispatch_write;
1880 ibm->proc_created = 1;
1883 if (ibm->notify) {
1884 ret = setup_notify(ibm);
1885 if (ret < 0)
1886 return ret;
1887 ibm->notify_installed = 1;
1890 return 0;
1893 static void ibm_exit(struct ibm_struct *ibm)
1895 if (ibm->notify_installed)
1896 acpi_remove_notify_handler(*ibm->handle, ibm->type,
1897 dispatch_notify);
1899 if (ibm->proc_created)
1900 remove_proc_entry(ibm->name, proc_dir);
1902 if (ibm->init_called && ibm->exit)
1903 ibm->exit();
1905 if (ibm->driver_registered) {
1906 acpi_bus_unregister_driver(ibm->driver);
1907 kfree(ibm->driver);
1911 static void __init ibm_handle_init(char *name,
1912 acpi_handle * handle, acpi_handle parent,
1913 char **paths, int num_paths, char **path)
1915 int i;
1916 acpi_status status;
1918 for (i = 0; i < num_paths; i++) {
1919 status = acpi_get_handle(parent, paths[i], handle);
1920 if (ACPI_SUCCESS(status)) {
1921 *path = paths[i];
1922 return;
1926 *handle = NULL;
1929 #define IBM_HANDLE_INIT(object) \
1930 ibm_handle_init(#object, &object##_handle, *object##_parent, \
1931 object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
1933 static int set_ibm_param(const char *val, struct kernel_param *kp)
1935 unsigned int i;
1937 for (i = 0; i < ARRAY_SIZE(ibms); i++)
1938 if (strcmp(ibms[i].name, kp->name) == 0 && ibms[i].write) {
1939 if (strlen(val) > sizeof(ibms[i].param) - 2)
1940 return -ENOSPC;
1941 strcpy(ibms[i].param, val);
1942 strcat(ibms[i].param, ",");
1943 return 0;
1946 return -EINVAL;
1949 #define IBM_PARAM(feature) \
1950 module_param_call(feature, set_ibm_param, NULL, NULL, 0)
1952 IBM_PARAM(hotkey);
1953 IBM_PARAM(bluetooth);
1954 IBM_PARAM(video);
1955 IBM_PARAM(light);
1956 #ifdef CONFIG_ACPI_IBM_DOCK
1957 IBM_PARAM(dock);
1958 #endif
1959 IBM_PARAM(bay);
1960 IBM_PARAM(cmos);
1961 IBM_PARAM(led);
1962 IBM_PARAM(beep);
1963 IBM_PARAM(ecdump);
1964 IBM_PARAM(brightness);
1965 IBM_PARAM(volume);
1966 IBM_PARAM(fan);
1968 static void acpi_ibm_exit(void)
1970 int i;
1972 for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
1973 ibm_exit(&ibms[i]);
1975 remove_proc_entry(IBM_DIR, acpi_root_dir);
1978 static int __init acpi_ibm_init(void)
1980 int ret, i;
1982 if (acpi_disabled)
1983 return -ENODEV;
1985 if (!acpi_specific_hotkey_enabled) {
1986 printk(IBM_ERR "using generic hotkey driver\n");
1987 return -ENODEV;
1990 /* ec is required because many other handles are relative to it */
1991 IBM_HANDLE_INIT(ec);
1992 if (!ec_handle) {
1993 printk(IBM_ERR "ec object not found\n");
1994 return -ENODEV;
1997 /* these handles are not required */
1998 IBM_HANDLE_INIT(vid);
1999 IBM_HANDLE_INIT(vid2);
2000 IBM_HANDLE_INIT(ledb);
2001 IBM_HANDLE_INIT(led);
2002 IBM_HANDLE_INIT(hkey);
2003 IBM_HANDLE_INIT(lght);
2004 IBM_HANDLE_INIT(cmos);
2005 #ifdef CONFIG_ACPI_IBM_DOCK
2006 IBM_HANDLE_INIT(dock);
2007 #endif
2008 IBM_HANDLE_INIT(pci);
2009 IBM_HANDLE_INIT(bay);
2010 if (bay_handle)
2011 IBM_HANDLE_INIT(bay_ej);
2012 IBM_HANDLE_INIT(bay2);
2013 if (bay2_handle)
2014 IBM_HANDLE_INIT(bay2_ej);
2015 IBM_HANDLE_INIT(beep);
2016 IBM_HANDLE_INIT(ecrd);
2017 IBM_HANDLE_INIT(ecwr);
2018 IBM_HANDLE_INIT(fans);
2019 IBM_HANDLE_INIT(gfan);
2020 IBM_HANDLE_INIT(sfan);
2022 proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir);
2023 if (!proc_dir) {
2024 printk(IBM_ERR "unable to create proc dir %s", IBM_DIR);
2025 return -ENODEV;
2027 proc_dir->owner = THIS_MODULE;
2029 for (i = 0; i < ARRAY_SIZE(ibms); i++) {
2030 ret = ibm_init(&ibms[i]);
2031 if (ret >= 0 && *ibms[i].param)
2032 ret = ibms[i].write(ibms[i].param);
2033 if (ret < 0) {
2034 acpi_ibm_exit();
2035 return ret;
2039 return 0;
2042 module_init(acpi_ibm_init);
2043 module_exit(acpi_ibm_exit);