diff options
Diffstat (limited to 'drivers/acpi/ibm_acpi.c')
-rw-r--r-- | drivers/acpi/ibm_acpi.c | 1358 |
1 files changed, 1044 insertions, 314 deletions
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 62233bd7147c..5cc090326ddc 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * ibm_acpi.c - IBM ThinkPad ACPI Extras | 2 | * ibm_acpi.c - IBM ThinkPad ACPI Extras |
3 | * | 3 | * |
4 | * | 4 | * |
5 | * Copyright (C) 2004 Borislav Deianov | 5 | * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 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 | 8 | * it under the terms of the GNU General Public License as published by |
@@ -17,38 +17,62 @@ | |||
17 | * You should have received a copy of the GNU General Public License | 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 | 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 | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | * | 20 | */ |
21 | |||
22 | #define IBM_VERSION "0.12a" | ||
23 | |||
24 | /* | ||
21 | * Changelog: | 25 | * Changelog: |
22 | * | 26 | * |
23 | * 2004-08-09 0.1 initial release, support for X series | 27 | * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels |
24 | * 2004-08-14 0.2 support for T series, X20 | 28 | * 2005-03-17 0.11 support for 600e, 770x |
25 | * bluetooth enable/disable | 29 | * thanks to Jamie Lentin <lentinj@dial.pipex.com> |
26 | * hotkey events disabled by default | 30 | * support for 770e, G41 |
27 | * removed fan control, currently useless | 31 | * G40 and G41 don't have a thinklight |
28 | * 2004-08-17 0.3 support for R40 | 32 | * temperatures no longer experimental |
29 | * lcd off, brightness control | 33 | * experimental brightness control |
30 | * thinklight on/off | 34 | * experimental volume control |
31 | * 2004-09-16 0.4 support for module parameters | 35 | * experimental fan enable/disable |
32 | * hotkey mask can be prefixed by 0x | 36 | * 2005-01-16 0.10 fix module loading on R30, R31 |
33 | * video output switching | 37 | * 2005-01-16 0.9 support for 570, R30, R31 |
34 | * video expansion control | 38 | * ultrabay support on A22p, A3x |
35 | * ultrabay eject support | 39 | * limit arg for cmos, led, beep, drop experimental status |
36 | * removed lcd brightness/on/off control, didn't work | 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 | ||
37 | * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20 | 54 | * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20 |
38 | * proc file format changed | 55 | * proc file format changed |
39 | * video_switch command | 56 | * video_switch command |
40 | * experimental cmos control | 57 | * experimental cmos control |
41 | * experimental led control | 58 | * experimental led control |
42 | * experimental acpi sounds | 59 | * experimental acpi sounds |
43 | * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device | 60 | * 2004-09-16 0.4 support for module parameters |
44 | * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20 | 61 | * hotkey mask can be prefixed by 0x |
45 | * fix LED control on A21e | 62 | * video output switching |
46 | * 2004-11-08 0.8 fix init error case, don't return from a macro | 63 | * video expansion control |
47 | * thanks to Chris Wright <chrisw@osdl.org> | 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 | ||
48 | */ | 74 | */ |
49 | 75 | ||
50 | #define IBM_VERSION "0.8" | ||
51 | |||
52 | #include <linux/kernel.h> | 76 | #include <linux/kernel.h> |
53 | #include <linux/module.h> | 77 | #include <linux/module.h> |
54 | #include <linux/init.h> | 78 | #include <linux/init.h> |
@@ -64,6 +88,11 @@ | |||
64 | #define IBM_FILE "ibm_acpi" | 88 | #define IBM_FILE "ibm_acpi" |
65 | #define IBM_URL "http://ibm-acpi.sf.net/" | 89 | #define IBM_URL "http://ibm-acpi.sf.net/" |
66 | 90 | ||
91 | MODULE_AUTHOR("Borislav Deianov"); | ||
92 | MODULE_DESCRIPTION(IBM_DESC); | ||
93 | MODULE_VERSION(IBM_VERSION); | ||
94 | MODULE_LICENSE("GPL"); | ||
95 | |||
67 | #define IBM_DIR IBM_NAME | 96 | #define IBM_DIR IBM_NAME |
68 | 97 | ||
69 | #define IBM_LOG IBM_FILE ": " | 98 | #define IBM_LOG IBM_FILE ": " |
@@ -84,46 +113,120 @@ static acpi_handle root_handle = NULL; | |||
84 | #define IBM_HANDLE(object, parent, paths...) \ | 113 | #define IBM_HANDLE(object, parent, paths...) \ |
85 | static acpi_handle object##_handle; \ | 114 | static acpi_handle object##_handle; \ |
86 | static acpi_handle *object##_parent = &parent##_handle; \ | 115 | static acpi_handle *object##_parent = &parent##_handle; \ |
116 | static char *object##_path; \ | ||
87 | static char *object##_paths[] = { paths } | 117 | static char *object##_paths[] = { paths } |
88 | 118 | ||
89 | IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC", /* A21e, A22p, T20, T21, X20 */ | 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 | */ | ||
140 | |||
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 */ | ||
90 | "\\_SB.PCI0.LPC.EC", /* all others */ | 147 | "\\_SB.PCI0.LPC.EC", /* all others */ |
91 | ); | 148 | ); |
92 | 149 | ||
93 | IBM_HANDLE(vid, root, "\\_SB.PCI0.VID", /* A21e, G40, X30, X40 */ | 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 */ | ||
94 | "\\_SB.PCI0.AGP.VID", /* all others */ | 154 | "\\_SB.PCI0.AGP.VID", /* all others */ |
95 | ); | 155 | ); /* R30, R31 */ |
156 | |||
157 | IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ | ||
96 | 158 | ||
97 | IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50p, R51, T4x, X31, X40 */ | 159 | IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ |
98 | "\\CMOS", /* A3x, G40, R32, T23, T30, X22, X24, X30 */ | 160 | "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ |
99 | "\\CMS", /* R40, R40e */ | 161 | "\\CMS", /* R40, R40e */ |
100 | ); /* A21e, A22p, T20, T21, X20 */ | 162 | ); /* all others */ |
101 | 163 | ||
102 | IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ | 164 | IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ |
103 | "\\_SB.PCI0.DOCK", /* A22p, T20, T21, X20 */ | 165 | "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ |
104 | "\\_SB.PCI0.PCI1.DOCK", /* all others */ | 166 | "\\_SB.PCI0.PCI1.DOCK", /* all others */ |
105 | ); /* A21e, G40, R32, R40, R40e */ | 167 | "\\_SB.PCI.ISA.SLCE", /* 570 */ |
168 | ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ | ||
169 | |||
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 */ | ||
174 | |||
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 */ | ||
178 | |||
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 */ | ||
182 | |||
183 | IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ | ||
184 | "_EJ0", /* 770x */ | ||
185 | ); /* all others */ | ||
186 | |||
187 | /* don't list other alternatives as we install a notify handler on the 570 */ | ||
188 | IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ | ||
106 | 189 | ||
107 | IBM_HANDLE(bay, root, "\\_SB.PCI0.IDE0.SCND.MSTR"); /* all except A21e */ | 190 | IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ |
108 | IBM_HANDLE(bayej, root, "\\_SB.PCI0.IDE0.SCND.MSTR._EJ0"); /* all except A2x, A3x */ | 191 | "^HKEY", /* R30, R31 */ |
192 | "HKEY", /* all others */ | ||
193 | ); /* 570 */ | ||
109 | 194 | ||
110 | IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A22p, T20, T21, X20 */ | 195 | IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ |
111 | IBM_HANDLE(hkey, ec, "HKEY"); /* all */ | 196 | IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ |
112 | IBM_HANDLE(led, ec, "LED"); /* all except A21e, A22p, T20, T21, X20 */ | 197 | |
113 | IBM_HANDLE(sysl, ec, "SYSL"); /* A21e, A22p, T20, T21, X20 */ | 198 | IBM_HANDLE(led, ec, "SLED", /* 570 */ |
114 | IBM_HANDLE(bled, ec, "BLED"); /* A22p, T20, T21, X20 */ | 199 | "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ |
115 | IBM_HANDLE(beep, ec, "BEEP"); /* all models */ | 200 | "LED", /* all others */ |
201 | ); /* R30, R31 */ | ||
202 | |||
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 */ | ||
207 | |||
208 | IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ | ||
209 | "\\FSPD", /* 600e/x, 770e, 770x */ | ||
210 | ); /* all others */ | ||
211 | |||
212 | IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ | ||
213 | "JFNS", /* 770x-JL */ | ||
214 | ); /* all others */ | ||
215 | |||
216 | #define IBM_HKEY_HID "IBM0068" | ||
217 | #define IBM_PCI_HID "PNP0A03" | ||
116 | 218 | ||
117 | struct ibm_struct { | 219 | struct ibm_struct { |
118 | char *name; | 220 | char *name; |
221 | char param[32]; | ||
119 | 222 | ||
120 | char *hid; | 223 | char *hid; |
121 | struct acpi_driver *driver; | 224 | struct acpi_driver *driver; |
122 | 225 | ||
123 | int (*init) (struct ibm_struct *); | 226 | int (*init) (void); |
124 | int (*read) (struct ibm_struct *, char *); | 227 | int (*read) (char *); |
125 | int (*write) (struct ibm_struct *, char *); | 228 | int (*write) (char *); |
126 | void (*exit) (struct ibm_struct *); | 229 | void (*exit) (void); |
127 | 230 | ||
128 | void (*notify) (struct ibm_struct *, u32); | 231 | void (*notify) (struct ibm_struct *, u32); |
129 | acpi_handle *handle; | 232 | acpi_handle *handle; |
@@ -135,17 +238,6 @@ struct ibm_struct { | |||
135 | int init_called; | 238 | int init_called; |
136 | int notify_installed; | 239 | int notify_installed; |
137 | 240 | ||
138 | int supported; | ||
139 | union { | ||
140 | struct { | ||
141 | int status; | ||
142 | int mask; | ||
143 | } hotkey; | ||
144 | struct { | ||
145 | int autoswitch; | ||
146 | } video; | ||
147 | } state; | ||
148 | |||
149 | int experimental; | 241 | int experimental; |
150 | }; | 242 | }; |
151 | 243 | ||
@@ -161,7 +253,7 @@ static int acpi_evalf(acpi_handle handle, | |||
161 | char *fmt0 = fmt; | 253 | char *fmt0 = fmt; |
162 | struct acpi_object_list params; | 254 | struct acpi_object_list params; |
163 | union acpi_object in_objs[IBM_MAX_ACPI_ARGS]; | 255 | union acpi_object in_objs[IBM_MAX_ACPI_ARGS]; |
164 | struct acpi_buffer result; | 256 | struct acpi_buffer result, *resultp; |
165 | union acpi_object out_obj; | 257 | union acpi_object out_obj; |
166 | acpi_status status; | 258 | acpi_status status; |
167 | va_list ap; | 259 | va_list ap; |
@@ -202,10 +294,14 @@ static int acpi_evalf(acpi_handle handle, | |||
202 | } | 294 | } |
203 | va_end(ap); | 295 | va_end(ap); |
204 | 296 | ||
205 | result.length = sizeof(out_obj); | 297 | if (res_type != 'v') { |
206 | result.pointer = &out_obj; | 298 | result.length = sizeof(out_obj); |
299 | result.pointer = &out_obj; | ||
300 | resultp = &result; | ||
301 | } else | ||
302 | resultp = NULL; | ||
207 | 303 | ||
208 | status = acpi_evaluate_object(handle, method, ¶ms, &result); | 304 | status = acpi_evaluate_object(handle, method, ¶ms, resultp); |
209 | 305 | ||
210 | switch (res_type) { | 306 | switch (res_type) { |
211 | case 'd': /* int */ | 307 | case 'd': /* int */ |
@@ -256,7 +352,7 @@ static char *next_cmd(char **cmds) | |||
256 | return start; | 352 | return start; |
257 | } | 353 | } |
258 | 354 | ||
259 | static int driver_init(struct ibm_struct *ibm) | 355 | static int driver_init(void) |
260 | { | 356 | { |
261 | printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); | 357 | printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); |
262 | printk(IBM_INFO "%s\n", IBM_URL); | 358 | printk(IBM_INFO "%s\n", IBM_URL); |
@@ -264,7 +360,7 @@ static int driver_init(struct ibm_struct *ibm) | |||
264 | return 0; | 360 | return 0; |
265 | } | 361 | } |
266 | 362 | ||
267 | static int driver_read(struct ibm_struct *ibm, char *p) | 363 | static int driver_read(char *p) |
268 | { | 364 | { |
269 | int len = 0; | 365 | int len = 0; |
270 | 366 | ||
@@ -274,66 +370,74 @@ static int driver_read(struct ibm_struct *ibm, char *p) | |||
274 | return len; | 370 | return len; |
275 | } | 371 | } |
276 | 372 | ||
277 | static int hotkey_get(struct ibm_struct *ibm, int *status, int *mask) | 373 | static int hotkey_supported; |
374 | static int hotkey_mask_supported; | ||
375 | static int hotkey_orig_status; | ||
376 | static int hotkey_orig_mask; | ||
377 | |||
378 | static int hotkey_get(int *status, int *mask) | ||
278 | { | 379 | { |
279 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) | 380 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) |
280 | return -EIO; | 381 | return 0; |
281 | if (ibm->supported) { | 382 | |
282 | if (!acpi_evalf(hkey_handle, mask, "DHKN", "qd")) | 383 | if (hotkey_mask_supported) |
283 | return -EIO; | 384 | if (!acpi_evalf(hkey_handle, mask, "DHKN", "d")) |
284 | } else { | 385 | return 0; |
285 | *mask = ibm->state.hotkey.mask; | 386 | |
286 | } | 387 | return 1; |
287 | return 0; | ||
288 | } | 388 | } |
289 | 389 | ||
290 | static int hotkey_set(struct ibm_struct *ibm, int status, int mask) | 390 | static int hotkey_set(int status, int mask) |
291 | { | 391 | { |
292 | int i; | 392 | int i; |
293 | 393 | ||
294 | if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) | 394 | if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) |
295 | return -EIO; | ||
296 | |||
297 | if (!ibm->supported) | ||
298 | return 0; | 395 | return 0; |
299 | 396 | ||
300 | for (i = 0; i < 32; i++) { | 397 | if (hotkey_mask_supported) |
301 | int bit = ((1 << i) & mask) != 0; | 398 | for (i = 0; i < 32; i++) { |
302 | if (!acpi_evalf(hkey_handle, NULL, "MHKM", "vdd", i + 1, bit)) | 399 | int bit = ((1 << i) & mask) != 0; |
303 | return -EIO; | 400 | if (!acpi_evalf(hkey_handle, |
304 | } | 401 | NULL, "MHKM", "vdd", i + 1, bit)) |
402 | return 0; | ||
403 | } | ||
305 | 404 | ||
306 | return 0; | 405 | return 1; |
307 | } | 406 | } |
308 | 407 | ||
309 | static int hotkey_init(struct ibm_struct *ibm) | 408 | static int hotkey_init(void) |
310 | { | 409 | { |
311 | int ret; | 410 | /* hotkey not supported on 570 */ |
411 | hotkey_supported = hkey_handle != NULL; | ||
312 | 412 | ||
313 | ibm->supported = 1; | 413 | if (hotkey_supported) { |
314 | ret = hotkey_get(ibm, | 414 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
315 | &ibm->state.hotkey.status, &ibm->state.hotkey.mask); | 415 | A30, R30, R31, T20-22, X20-21, X22-24 */ |
316 | if (ret < 0) { | 416 | hotkey_mask_supported = |
317 | /* mask not supported on A21e, A22p, T20, T21, X20, X22, X24 */ | 417 | acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); |
318 | ibm->supported = 0; | 418 | |
319 | ret = hotkey_get(ibm, | 419 | if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask)) |
320 | &ibm->state.hotkey.status, | 420 | return -ENODEV; |
321 | &ibm->state.hotkey.mask); | ||
322 | } | 421 | } |
323 | 422 | ||
324 | return ret; | 423 | return 0; |
325 | } | 424 | } |
326 | 425 | ||
327 | static int hotkey_read(struct ibm_struct *ibm, char *p) | 426 | static int hotkey_read(char *p) |
328 | { | 427 | { |
329 | int status, mask; | 428 | int status, mask; |
330 | int len = 0; | 429 | int len = 0; |
331 | 430 | ||
332 | if (hotkey_get(ibm, &status, &mask) < 0) | 431 | if (!hotkey_supported) { |
432 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
433 | return len; | ||
434 | } | ||
435 | |||
436 | if (!hotkey_get(&status, &mask)) | ||
333 | return -EIO; | 437 | return -EIO; |
334 | 438 | ||
335 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); | 439 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); |
336 | if (ibm->supported) { | 440 | if (hotkey_mask_supported) { |
337 | len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); | 441 | len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); |
338 | len += sprintf(p + len, | 442 | len += sprintf(p + len, |
339 | "commands:\tenable, disable, reset, <mask>\n"); | 443 | "commands:\tenable, disable, reset, <mask>\n"); |
@@ -345,23 +449,26 @@ static int hotkey_read(struct ibm_struct *ibm, char *p) | |||
345 | return len; | 449 | return len; |
346 | } | 450 | } |
347 | 451 | ||
348 | static int hotkey_write(struct ibm_struct *ibm, char *buf) | 452 | static int hotkey_write(char *buf) |
349 | { | 453 | { |
350 | int status, mask; | 454 | int status, mask; |
351 | char *cmd; | 455 | char *cmd; |
352 | int do_cmd = 0; | 456 | int do_cmd = 0; |
353 | 457 | ||
354 | if (hotkey_get(ibm, &status, &mask) < 0) | 458 | if (!hotkey_supported) |
355 | return -ENODEV; | 459 | return -ENODEV; |
356 | 460 | ||
461 | if (!hotkey_get(&status, &mask)) | ||
462 | return -EIO; | ||
463 | |||
357 | while ((cmd = next_cmd(&buf))) { | 464 | while ((cmd = next_cmd(&buf))) { |
358 | if (strlencmp(cmd, "enable") == 0) { | 465 | if (strlencmp(cmd, "enable") == 0) { |
359 | status = 1; | 466 | status = 1; |
360 | } else if (strlencmp(cmd, "disable") == 0) { | 467 | } else if (strlencmp(cmd, "disable") == 0) { |
361 | status = 0; | 468 | status = 0; |
362 | } else if (strlencmp(cmd, "reset") == 0) { | 469 | } else if (strlencmp(cmd, "reset") == 0) { |
363 | status = ibm->state.hotkey.status; | 470 | status = hotkey_orig_status; |
364 | mask = ibm->state.hotkey.mask; | 471 | mask = hotkey_orig_mask; |
365 | } else if (sscanf(cmd, "0x%x", &mask) == 1) { | 472 | } else if (sscanf(cmd, "0x%x", &mask) == 1) { |
366 | /* mask set */ | 473 | /* mask set */ |
367 | } else if (sscanf(cmd, "%x", &mask) == 1) { | 474 | } else if (sscanf(cmd, "%x", &mask) == 1) { |
@@ -371,15 +478,16 @@ static int hotkey_write(struct ibm_struct *ibm, char *buf) | |||
371 | do_cmd = 1; | 478 | do_cmd = 1; |
372 | } | 479 | } |
373 | 480 | ||
374 | if (do_cmd && hotkey_set(ibm, status, mask) < 0) | 481 | if (do_cmd && !hotkey_set(status, mask)) |
375 | return -EIO; | 482 | return -EIO; |
376 | 483 | ||
377 | return 0; | 484 | return 0; |
378 | } | 485 | } |
379 | 486 | ||
380 | static void hotkey_exit(struct ibm_struct *ibm) | 487 | static void hotkey_exit(void) |
381 | { | 488 | { |
382 | hotkey_set(ibm, ibm->state.hotkey.status, ibm->state.hotkey.mask); | 489 | if (hotkey_supported) |
490 | hotkey_set(hotkey_orig_status, hotkey_orig_mask); | ||
383 | } | 491 | } |
384 | 492 | ||
385 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 493 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
@@ -394,30 +502,35 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
394 | } | 502 | } |
395 | } | 503 | } |
396 | 504 | ||
397 | static int bluetooth_init(struct ibm_struct *ibm) | 505 | static int bluetooth_supported; |
506 | |||
507 | static int bluetooth_init(void) | ||
398 | { | 508 | { |
399 | /* bluetooth not supported on A21e, G40, T20, T21, X20 */ | 509 | /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
400 | ibm->supported = acpi_evalf(hkey_handle, NULL, "GBDC", "qv"); | 510 | G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ |
511 | bluetooth_supported = hkey_handle && | ||
512 | acpi_evalf(hkey_handle, NULL, "GBDC", "qv"); | ||
401 | 513 | ||
402 | return 0; | 514 | return 0; |
403 | } | 515 | } |
404 | 516 | ||
405 | static int bluetooth_status(struct ibm_struct *ibm) | 517 | static int bluetooth_status(void) |
406 | { | 518 | { |
407 | int status; | 519 | int status; |
408 | 520 | ||
409 | if (!ibm->supported || !acpi_evalf(hkey_handle, &status, "GBDC", "d")) | 521 | if (!bluetooth_supported || |
522 | !acpi_evalf(hkey_handle, &status, "GBDC", "d")) | ||
410 | status = 0; | 523 | status = 0; |
411 | 524 | ||
412 | return status; | 525 | return status; |
413 | } | 526 | } |
414 | 527 | ||
415 | static int bluetooth_read(struct ibm_struct *ibm, char *p) | 528 | static int bluetooth_read(char *p) |
416 | { | 529 | { |
417 | int len = 0; | 530 | int len = 0; |
418 | int status = bluetooth_status(ibm); | 531 | int status = bluetooth_status(); |
419 | 532 | ||
420 | if (!ibm->supported) | 533 | if (!bluetooth_supported) |
421 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 534 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
422 | else if (!(status & 1)) | 535 | else if (!(status & 1)) |
423 | len += sprintf(p + len, "status:\t\tnot installed\n"); | 536 | len += sprintf(p + len, "status:\t\tnot installed\n"); |
@@ -429,14 +542,14 @@ static int bluetooth_read(struct ibm_struct *ibm, char *p) | |||
429 | return len; | 542 | return len; |
430 | } | 543 | } |
431 | 544 | ||
432 | static int bluetooth_write(struct ibm_struct *ibm, char *buf) | 545 | static int bluetooth_write(char *buf) |
433 | { | 546 | { |
434 | int status = bluetooth_status(ibm); | 547 | int status = bluetooth_status(); |
435 | char *cmd; | 548 | char *cmd; |
436 | int do_cmd = 0; | 549 | int do_cmd = 0; |
437 | 550 | ||
438 | if (!ibm->supported) | 551 | if (!bluetooth_supported) |
439 | return -EINVAL; | 552 | return -ENODEV; |
440 | 553 | ||
441 | while ((cmd = next_cmd(&buf))) { | 554 | while ((cmd = next_cmd(&buf))) { |
442 | if (strlencmp(cmd, "enable") == 0) { | 555 | if (strlencmp(cmd, "enable") == 0) { |
@@ -454,58 +567,161 @@ static int bluetooth_write(struct ibm_struct *ibm, char *buf) | |||
454 | return 0; | 567 | return 0; |
455 | } | 568 | } |
456 | 569 | ||
457 | static int video_init(struct ibm_struct *ibm) | 570 | static int video_supported; |
571 | static int video_orig_autosw; | ||
572 | |||
573 | #define VIDEO_570 1 | ||
574 | #define VIDEO_770 2 | ||
575 | #define VIDEO_NEW 3 | ||
576 | |||
577 | static int video_init(void) | ||
458 | { | 578 | { |
459 | if (!acpi_evalf(vid_handle, &ibm->state.video.autoswitch, "^VDEE", "d")) | 579 | int ivga; |
460 | return -ENODEV; | 580 | |
581 | if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) | ||
582 | /* G41, assume IVGA doesn't change */ | ||
583 | vid_handle = vid2_handle; | ||
584 | |||
585 | if (!vid_handle) | ||
586 | /* video switching not supported on R30, R31 */ | ||
587 | video_supported = 0; | ||
588 | else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) | ||
589 | /* 570 */ | ||
590 | video_supported = VIDEO_570; | ||
591 | else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) | ||
592 | /* 600e/x, 770e, 770x */ | ||
593 | video_supported = VIDEO_770; | ||
594 | else | ||
595 | /* all others */ | ||
596 | video_supported = VIDEO_NEW; | ||
461 | 597 | ||
462 | return 0; | 598 | return 0; |
463 | } | 599 | } |
464 | 600 | ||
465 | static int video_status(struct ibm_struct *ibm) | 601 | static int video_status(void) |
466 | { | 602 | { |
467 | int status = 0; | 603 | int status = 0; |
468 | int i; | 604 | int i; |
469 | 605 | ||
470 | acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1); | 606 | if (video_supported == VIDEO_570) { |
471 | if (acpi_evalf(NULL, &i, "\\VCDC", "d")) | 607 | if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87)) |
472 | status |= 0x02 * i; | 608 | status = i & 3; |
609 | } else if (video_supported == VIDEO_770) { | ||
610 | if (acpi_evalf(NULL, &i, "\\VCDL", "d")) | ||
611 | status |= 0x01 * i; | ||
612 | if (acpi_evalf(NULL, &i, "\\VCDC", "d")) | ||
613 | status |= 0x02 * i; | ||
614 | } else if (video_supported == VIDEO_NEW) { | ||
615 | acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1); | ||
616 | if (acpi_evalf(NULL, &i, "\\VCDC", "d")) | ||
617 | status |= 0x02 * i; | ||
618 | |||
619 | acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0); | ||
620 | if (acpi_evalf(NULL, &i, "\\VCDL", "d")) | ||
621 | status |= 0x01 * i; | ||
622 | if (acpi_evalf(NULL, &i, "\\VCDD", "d")) | ||
623 | status |= 0x08 * i; | ||
624 | } | ||
473 | 625 | ||
474 | acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0); | 626 | return status; |
475 | if (acpi_evalf(NULL, &i, "\\VCDL", "d")) | 627 | } |
476 | status |= 0x01 * i; | ||
477 | if (acpi_evalf(NULL, &i, "\\VCDD", "d")) | ||
478 | status |= 0x08 * i; | ||
479 | 628 | ||
480 | if (acpi_evalf(vid_handle, &i, "^VDEE", "d")) | 629 | static int video_autosw(void) |
481 | status |= 0x10 * (i & 1); | 630 | { |
631 | int autosw = 0; | ||
482 | 632 | ||
483 | return status; | 633 | if (video_supported == VIDEO_570) |
634 | acpi_evalf(vid_handle, &autosw, "SWIT", "d"); | ||
635 | else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW) | ||
636 | acpi_evalf(vid_handle, &autosw, "^VDEE", "d"); | ||
637 | |||
638 | return autosw & 1; | ||
484 | } | 639 | } |
485 | 640 | ||
486 | static int video_read(struct ibm_struct *ibm, char *p) | 641 | static int video_read(char *p) |
487 | { | 642 | { |
488 | int status = video_status(ibm); | 643 | int status = video_status(); |
644 | int autosw = video_autosw(); | ||
489 | int len = 0; | 645 | int len = 0; |
490 | 646 | ||
647 | if (!video_supported) { | ||
648 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
649 | return len; | ||
650 | } | ||
651 | |||
652 | len += sprintf(p + len, "status:\t\tsupported\n"); | ||
491 | len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); | 653 | len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); |
492 | len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); | 654 | len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); |
493 | len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); | 655 | if (video_supported == VIDEO_NEW) |
494 | len += sprintf(p + len, "auto:\t\t%s\n", enabled(status, 4)); | 656 | len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); |
495 | len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable, " | 657 | len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); |
496 | "crt_enable, crt_disable\n"); | 658 | len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); |
497 | len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable, " | 659 | len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); |
498 | "auto_enable, auto_disable\n"); | 660 | if (video_supported == VIDEO_NEW) |
661 | len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); | ||
662 | len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); | ||
499 | len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); | 663 | len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); |
500 | 664 | ||
501 | return len; | 665 | return len; |
502 | } | 666 | } |
503 | 667 | ||
504 | static int video_write(struct ibm_struct *ibm, char *buf) | 668 | static int video_switch(void) |
669 | { | ||
670 | int autosw = video_autosw(); | ||
671 | int ret; | ||
672 | |||
673 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) | ||
674 | return -EIO; | ||
675 | ret = video_supported == VIDEO_570 ? | ||
676 | acpi_evalf(ec_handle, NULL, "_Q16", "v") : | ||
677 | acpi_evalf(vid_handle, NULL, "VSWT", "v"); | ||
678 | acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); | ||
679 | |||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | static int video_expand(void) | ||
684 | { | ||
685 | if (video_supported == VIDEO_570) | ||
686 | return acpi_evalf(ec_handle, NULL, "_Q17", "v"); | ||
687 | else if (video_supported == VIDEO_770) | ||
688 | return acpi_evalf(vid_handle, NULL, "VEXP", "v"); | ||
689 | else | ||
690 | return acpi_evalf(NULL, NULL, "\\VEXP", "v"); | ||
691 | } | ||
692 | |||
693 | static int video_switch2(int status) | ||
694 | { | ||
695 | int ret; | ||
696 | |||
697 | if (video_supported == VIDEO_570) { | ||
698 | ret = acpi_evalf(NULL, NULL, | ||
699 | "\\_SB.PHS2", "vdd", 0x8b, status | 0x80); | ||
700 | } else if (video_supported == VIDEO_770) { | ||
701 | int autosw = video_autosw(); | ||
702 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) | ||
703 | return -EIO; | ||
704 | |||
705 | ret = acpi_evalf(vid_handle, NULL, | ||
706 | "ASWT", "vdd", status * 0x100, 0); | ||
707 | |||
708 | acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); | ||
709 | } else { | ||
710 | ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && | ||
711 | acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); | ||
712 | } | ||
713 | |||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | static int video_write(char *buf) | ||
505 | { | 718 | { |
506 | char *cmd; | 719 | char *cmd; |
507 | int enable, disable, status; | 720 | int enable, disable, status; |
508 | 721 | ||
722 | if (!video_supported) | ||
723 | return -ENODEV; | ||
724 | |||
509 | enable = disable = 0; | 725 | enable = disable = 0; |
510 | 726 | ||
511 | while ((cmd = next_cmd(&buf))) { | 727 | while ((cmd = next_cmd(&buf))) { |
@@ -517,9 +733,11 @@ static int video_write(struct ibm_struct *ibm, char *buf) | |||
517 | enable |= 0x02; | 733 | enable |= 0x02; |
518 | } else if (strlencmp(cmd, "crt_disable") == 0) { | 734 | } else if (strlencmp(cmd, "crt_disable") == 0) { |
519 | disable |= 0x02; | 735 | disable |= 0x02; |
520 | } else if (strlencmp(cmd, "dvi_enable") == 0) { | 736 | } else if (video_supported == VIDEO_NEW && |
737 | strlencmp(cmd, "dvi_enable") == 0) { | ||
521 | enable |= 0x08; | 738 | enable |= 0x08; |
522 | } else if (strlencmp(cmd, "dvi_disable") == 0) { | 739 | } else if (video_supported == VIDEO_NEW && |
740 | strlencmp(cmd, "dvi_disable") == 0) { | ||
523 | disable |= 0x08; | 741 | disable |= 0x08; |
524 | } else if (strlencmp(cmd, "auto_enable") == 0) { | 742 | } else if (strlencmp(cmd, "auto_enable") == 0) { |
525 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) | 743 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) |
@@ -528,70 +746,75 @@ static int video_write(struct ibm_struct *ibm, char *buf) | |||
528 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0)) | 746 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0)) |
529 | return -EIO; | 747 | return -EIO; |
530 | } else if (strlencmp(cmd, "video_switch") == 0) { | 748 | } else if (strlencmp(cmd, "video_switch") == 0) { |
531 | int autoswitch; | 749 | if (!video_switch()) |
532 | if (!acpi_evalf(vid_handle, &autoswitch, "^VDEE", "d")) | ||
533 | return -EIO; | ||
534 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) | ||
535 | return -EIO; | ||
536 | if (!acpi_evalf(vid_handle, NULL, "VSWT", "v")) | ||
537 | return -EIO; | ||
538 | if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", | ||
539 | autoswitch)) | ||
540 | return -EIO; | 750 | return -EIO; |
541 | } else if (strlencmp(cmd, "expand_toggle") == 0) { | 751 | } else if (strlencmp(cmd, "expand_toggle") == 0) { |
542 | if (!acpi_evalf(NULL, NULL, "\\VEXP", "v")) | 752 | if (!video_expand()) |
543 | return -EIO; | 753 | return -EIO; |
544 | } else | 754 | } else |
545 | return -EINVAL; | 755 | return -EINVAL; |
546 | } | 756 | } |
547 | 757 | ||
548 | if (enable || disable) { | 758 | if (enable || disable) { |
549 | status = (video_status(ibm) & 0x0f & ~disable) | enable; | 759 | status = (video_status() & 0x0f & ~disable) | enable; |
550 | if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80)) | 760 | if (!video_switch2(status)) |
551 | return -EIO; | ||
552 | if (!acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1)) | ||
553 | return -EIO; | 761 | return -EIO; |
554 | } | 762 | } |
555 | 763 | ||
556 | return 0; | 764 | return 0; |
557 | } | 765 | } |
558 | 766 | ||
559 | static void video_exit(struct ibm_struct *ibm) | 767 | static void video_exit(void) |
560 | { | 768 | { |
561 | acpi_evalf(vid_handle, NULL, "_DOS", "vd", ibm->state.video.autoswitch); | 769 | acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw); |
562 | } | 770 | } |
563 | 771 | ||
564 | static int light_init(struct ibm_struct *ibm) | 772 | static int light_supported; |
773 | static int light_status_supported; | ||
774 | |||
775 | static int light_init(void) | ||
565 | { | 776 | { |
566 | /* kblt not supported on G40, R32, X20 */ | 777 | /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ |
567 | ibm->supported = acpi_evalf(ec_handle, NULL, "KBLT", "qv"); | 778 | light_supported = (cmos_handle || lght_handle) && !ledb_handle; |
779 | |||
780 | if (light_supported) | ||
781 | /* light status not supported on | ||
782 | 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */ | ||
783 | light_status_supported = acpi_evalf(ec_handle, NULL, | ||
784 | "KBLT", "qv"); | ||
568 | 785 | ||
569 | return 0; | 786 | return 0; |
570 | } | 787 | } |
571 | 788 | ||
572 | static int light_read(struct ibm_struct *ibm, char *p) | 789 | static int light_read(char *p) |
573 | { | 790 | { |
574 | int len = 0; | 791 | int len = 0; |
575 | int status = 0; | 792 | int status = 0; |
576 | 793 | ||
577 | if (ibm->supported) { | 794 | if (!light_supported) { |
795 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
796 | } else if (!light_status_supported) { | ||
797 | len += sprintf(p + len, "status:\t\tunknown\n"); | ||
798 | len += sprintf(p + len, "commands:\ton, off\n"); | ||
799 | } else { | ||
578 | if (!acpi_evalf(ec_handle, &status, "KBLT", "d")) | 800 | if (!acpi_evalf(ec_handle, &status, "KBLT", "d")) |
579 | return -EIO; | 801 | return -EIO; |
580 | len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); | 802 | len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); |
581 | } else | 803 | len += sprintf(p + len, "commands:\ton, off\n"); |
582 | len += sprintf(p + len, "status:\t\tunknown\n"); | 804 | } |
583 | |||
584 | len += sprintf(p + len, "commands:\ton, off\n"); | ||
585 | 805 | ||
586 | return len; | 806 | return len; |
587 | } | 807 | } |
588 | 808 | ||
589 | static int light_write(struct ibm_struct *ibm, char *buf) | 809 | static int light_write(char *buf) |
590 | { | 810 | { |
591 | int cmos_cmd, lght_cmd; | 811 | int cmos_cmd, lght_cmd; |
592 | char *cmd; | 812 | char *cmd; |
593 | int success; | 813 | int success; |
594 | 814 | ||
815 | if (!light_supported) | ||
816 | return -ENODEV; | ||
817 | |||
595 | while ((cmd = next_cmd(&buf))) { | 818 | while ((cmd = next_cmd(&buf))) { |
596 | if (strlencmp(cmd, "on") == 0) { | 819 | if (strlencmp(cmd, "on") == 0) { |
597 | cmos_cmd = 0x0c; | 820 | cmos_cmd = 0x0c; |
@@ -624,7 +847,7 @@ static int _sta(acpi_handle handle) | |||
624 | 847 | ||
625 | #define dock_docked() (_sta(dock_handle) & 1) | 848 | #define dock_docked() (_sta(dock_handle) & 1) |
626 | 849 | ||
627 | static int dock_read(struct ibm_struct *ibm, char *p) | 850 | static int dock_read(char *p) |
628 | { | 851 | { |
629 | int len = 0; | 852 | int len = 0; |
630 | int docked = dock_docked(); | 853 | int docked = dock_docked(); |
@@ -641,18 +864,17 @@ static int dock_read(struct ibm_struct *ibm, char *p) | |||
641 | return len; | 864 | return len; |
642 | } | 865 | } |
643 | 866 | ||
644 | static int dock_write(struct ibm_struct *ibm, char *buf) | 867 | static int dock_write(char *buf) |
645 | { | 868 | { |
646 | char *cmd; | 869 | char *cmd; |
647 | 870 | ||
648 | if (!dock_docked()) | 871 | if (!dock_docked()) |
649 | return -EINVAL; | 872 | return -ENODEV; |
650 | 873 | ||
651 | while ((cmd = next_cmd(&buf))) { | 874 | while ((cmd = next_cmd(&buf))) { |
652 | if (strlencmp(cmd, "undock") == 0) { | 875 | if (strlencmp(cmd, "undock") == 0) { |
653 | if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0)) | 876 | if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) || |
654 | return -EIO; | 877 | !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1)) |
655 | if (!acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1)) | ||
656 | return -EIO; | 878 | return -EIO; |
657 | } else if (strlencmp(cmd, "dock") == 0) { | 879 | } else if (strlencmp(cmd, "dock") == 0) { |
658 | if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1)) | 880 | if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1)) |
@@ -667,8 +889,13 @@ static int dock_write(struct ibm_struct *ibm, char *buf) | |||
667 | static void dock_notify(struct ibm_struct *ibm, u32 event) | 889 | static void dock_notify(struct ibm_struct *ibm, u32 event) |
668 | { | 890 | { |
669 | int docked = dock_docked(); | 891 | int docked = dock_docked(); |
892 | int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID); | ||
670 | 893 | ||
671 | if (event == 3 && docked) | 894 | if (event == 1 && !pci) /* 570 */ |
895 | acpi_bus_generate_event(ibm->device, event, 1); /* button */ | ||
896 | else if (event == 1 && pci) /* 570 */ | ||
897 | acpi_bus_generate_event(ibm->device, event, 3); /* dock */ | ||
898 | else if (event == 3 && docked) | ||
672 | acpi_bus_generate_event(ibm->device, event, 1); /* button */ | 899 | acpi_bus_generate_event(ibm->device, event, 1); /* button */ |
673 | else if (event == 3 && !docked) | 900 | else if (event == 3 && !docked) |
674 | acpi_bus_generate_event(ibm->device, event, 2); /* undock */ | 901 | acpi_bus_generate_event(ibm->device, event, 2); /* undock */ |
@@ -681,42 +908,69 @@ static void dock_notify(struct ibm_struct *ibm, u32 event) | |||
681 | } | 908 | } |
682 | } | 909 | } |
683 | 910 | ||
684 | #define bay_occupied() (_sta(bay_handle) & 1) | 911 | static int bay_status_supported; |
912 | static int bay_status2_supported; | ||
913 | static int bay_eject_supported; | ||
914 | static int bay_eject2_supported; | ||
685 | 915 | ||
686 | static int bay_init(struct ibm_struct *ibm) | 916 | static int bay_init(void) |
687 | { | 917 | { |
688 | /* bay not supported on A21e, A22p, A31, A31p, G40, R32, R40e */ | 918 | bay_status_supported = bay_handle && |
689 | ibm->supported = bay_handle && bayej_handle && | ||
690 | acpi_evalf(bay_handle, NULL, "_STA", "qv"); | 919 | acpi_evalf(bay_handle, NULL, "_STA", "qv"); |
920 | bay_status2_supported = bay2_handle && | ||
921 | acpi_evalf(bay2_handle, NULL, "_STA", "qv"); | ||
922 | |||
923 | bay_eject_supported = bay_handle && bay_ej_handle && | ||
924 | (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental); | ||
925 | bay_eject2_supported = bay2_handle && bay2_ej_handle && | ||
926 | (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); | ||
691 | 927 | ||
692 | return 0; | 928 | return 0; |
693 | } | 929 | } |
694 | 930 | ||
695 | static int bay_read(struct ibm_struct *ibm, char *p) | 931 | #define bay_occupied(b) (_sta(b##_handle) & 1) |
932 | |||
933 | static int bay_read(char *p) | ||
696 | { | 934 | { |
697 | int len = 0; | 935 | int len = 0; |
698 | int occupied = bay_occupied(); | 936 | int occupied = bay_occupied(bay); |
699 | 937 | int occupied2 = bay_occupied(bay2); | |
700 | if (!ibm->supported) | 938 | int eject, eject2; |
701 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 939 | |
702 | else if (!occupied) | 940 | len += sprintf(p + len, "status:\t\t%s\n", bay_status_supported ? |
703 | len += sprintf(p + len, "status:\t\tunoccupied\n"); | 941 | (occupied ? "occupied" : "unoccupied") : |
704 | else { | 942 | "not supported"); |
705 | len += sprintf(p + len, "status:\t\toccupied\n"); | 943 | if (bay_status2_supported) |
944 | len += sprintf(p + len, "status2:\t%s\n", occupied2 ? | ||
945 | "occupied" : "unoccupied"); | ||
946 | |||
947 | eject = bay_eject_supported && occupied; | ||
948 | eject2 = bay_eject2_supported && occupied2; | ||
949 | |||
950 | if (eject && eject2) | ||
951 | len += sprintf(p + len, "commands:\teject, eject2\n"); | ||
952 | else if (eject) | ||
706 | len += sprintf(p + len, "commands:\teject\n"); | 953 | len += sprintf(p + len, "commands:\teject\n"); |
707 | } | 954 | else if (eject2) |
955 | len += sprintf(p + len, "commands:\teject2\n"); | ||
708 | 956 | ||
709 | return len; | 957 | return len; |
710 | } | 958 | } |
711 | 959 | ||
712 | static int bay_write(struct ibm_struct *ibm, char *buf) | 960 | static int bay_write(char *buf) |
713 | { | 961 | { |
714 | char *cmd; | 962 | char *cmd; |
715 | 963 | ||
964 | if (!bay_eject_supported && !bay_eject2_supported) | ||
965 | return -ENODEV; | ||
966 | |||
716 | while ((cmd = next_cmd(&buf))) { | 967 | while ((cmd = next_cmd(&buf))) { |
717 | if (strlencmp(cmd, "eject") == 0) { | 968 | if (bay_eject_supported && strlencmp(cmd, "eject") == 0) { |
718 | if (!ibm->supported || | 969 | if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1)) |
719 | !acpi_evalf(bay_handle, NULL, "_EJ0", "vd", 1)) | 970 | return -EIO; |
971 | } else if (bay_eject2_supported && | ||
972 | strlencmp(cmd, "eject2") == 0) { | ||
973 | if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1)) | ||
720 | return -EIO; | 974 | return -EIO; |
721 | } else | 975 | } else |
722 | return -EINVAL; | 976 | return -EINVAL; |
@@ -730,22 +984,31 @@ static void bay_notify(struct ibm_struct *ibm, u32 event) | |||
730 | acpi_bus_generate_event(ibm->device, event, 0); | 984 | acpi_bus_generate_event(ibm->device, event, 0); |
731 | } | 985 | } |
732 | 986 | ||
733 | static int cmos_read(struct ibm_struct *ibm, char *p) | 987 | static int cmos_read(char *p) |
734 | { | 988 | { |
735 | int len = 0; | 989 | int len = 0; |
736 | 990 | ||
737 | /* cmos not supported on A21e, A22p, T20, T21, X20 */ | 991 | /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
992 | R30, R31, T20-22, X20-21 */ | ||
738 | if (!cmos_handle) | 993 | if (!cmos_handle) |
739 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 994 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
740 | else { | 995 | else { |
741 | len += sprintf(p + len, "status:\t\tsupported\n"); | 996 | len += sprintf(p + len, "status:\t\tsupported\n"); |
742 | len += sprintf(p + len, "commands:\t<int>\n"); | 997 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n"); |
743 | } | 998 | } |
744 | 999 | ||
745 | return len; | 1000 | return len; |
746 | } | 1001 | } |
747 | 1002 | ||
748 | static int cmos_write(struct ibm_struct *ibm, char *buf) | 1003 | static int cmos_eval(int cmos_cmd) |
1004 | { | ||
1005 | if (cmos_handle) | ||
1006 | return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd); | ||
1007 | else | ||
1008 | return 1; | ||
1009 | } | ||
1010 | |||
1011 | static int cmos_write(char *buf) | ||
749 | { | 1012 | { |
750 | char *cmd; | 1013 | char *cmd; |
751 | int cmos_cmd; | 1014 | int cmos_cmd; |
@@ -754,64 +1017,296 @@ static int cmos_write(struct ibm_struct *ibm, char *buf) | |||
754 | return -EINVAL; | 1017 | return -EINVAL; |
755 | 1018 | ||
756 | while ((cmd = next_cmd(&buf))) { | 1019 | while ((cmd = next_cmd(&buf))) { |
757 | if (sscanf(cmd, "%u", &cmos_cmd) == 1) { | 1020 | if (sscanf(cmd, "%u", &cmos_cmd) == 1 && |
1021 | cmos_cmd >= 0 && cmos_cmd <= 21) { | ||
758 | /* cmos_cmd set */ | 1022 | /* cmos_cmd set */ |
759 | } else | 1023 | } else |
760 | return -EINVAL; | 1024 | return -EINVAL; |
761 | 1025 | ||
762 | if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd)) | 1026 | if (!cmos_eval(cmos_cmd)) |
763 | return -EIO; | 1027 | return -EIO; |
764 | } | 1028 | } |
765 | 1029 | ||
766 | return 0; | 1030 | return 0; |
767 | } | 1031 | } |
768 | 1032 | ||
769 | static int led_read(struct ibm_struct *ibm, char *p) | 1033 | static int led_supported; |
1034 | |||
1035 | #define LED_570 1 | ||
1036 | #define LED_OLD 2 | ||
1037 | #define LED_NEW 3 | ||
1038 | |||
1039 | static int led_init(void) | ||
1040 | { | ||
1041 | if (!led_handle) | ||
1042 | /* led not supported on R30, R31 */ | ||
1043 | led_supported = 0; | ||
1044 | else if (strlencmp(led_path, "SLED") == 0) | ||
1045 | /* 570 */ | ||
1046 | led_supported = LED_570; | ||
1047 | else if (strlencmp(led_path, "SYSL") == 0) | ||
1048 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ | ||
1049 | led_supported = LED_OLD; | ||
1050 | else | ||
1051 | /* all others */ | ||
1052 | led_supported = LED_NEW; | ||
1053 | |||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | #define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking")) | ||
1058 | |||
1059 | static int led_read(char *p) | ||
770 | { | 1060 | { |
771 | int len = 0; | 1061 | int len = 0; |
772 | 1062 | ||
1063 | if (!led_supported) { | ||
1064 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
1065 | return len; | ||
1066 | } | ||
1067 | len += sprintf(p + len, "status:\t\tsupported\n"); | ||
1068 | |||
1069 | if (led_supported == LED_570) { | ||
1070 | /* 570 */ | ||
1071 | int i, status; | ||
1072 | for (i = 0; i < 8; i++) { | ||
1073 | if (!acpi_evalf(ec_handle, | ||
1074 | &status, "GLED", "dd", 1 << i)) | ||
1075 | return -EIO; | ||
1076 | len += sprintf(p + len, "%d:\t\t%s\n", | ||
1077 | i, led_status(status)); | ||
1078 | } | ||
1079 | } | ||
1080 | |||
773 | len += sprintf(p + len, "commands:\t" | 1081 | len += sprintf(p + len, "commands:\t" |
774 | "<int> on, <int> off, <int> blink\n"); | 1082 | "<led> on, <led> off, <led> blink (<led> is 0-7)\n"); |
775 | 1083 | ||
776 | return len; | 1084 | return len; |
777 | } | 1085 | } |
778 | 1086 | ||
779 | static int led_write(struct ibm_struct *ibm, char *buf) | 1087 | /* off, on, blink */ |
1088 | static const int led_sled_arg1[] = { 0, 1, 3 }; | ||
1089 | static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ | ||
1090 | static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ | ||
1091 | static const int led_led_arg1[] = { 0, 0x80, 0xc0 }; | ||
1092 | |||
1093 | #define EC_HLCL 0x0c | ||
1094 | #define EC_HLBL 0x0d | ||
1095 | #define EC_HLMS 0x0e | ||
1096 | |||
1097 | static int led_write(char *buf) | ||
780 | { | 1098 | { |
781 | char *cmd; | 1099 | char *cmd; |
782 | unsigned int led; | 1100 | int led, ind, ret; |
783 | int led_cmd, sysl_cmd, bled_a, bled_b; | 1101 | |
1102 | if (!led_supported) | ||
1103 | return -ENODEV; | ||
784 | 1104 | ||
785 | while ((cmd = next_cmd(&buf))) { | 1105 | while ((cmd = next_cmd(&buf))) { |
786 | if (sscanf(cmd, "%u", &led) != 1) | 1106 | if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7) |
787 | return -EINVAL; | 1107 | return -EINVAL; |
788 | 1108 | ||
789 | if (strstr(cmd, "blink")) { | 1109 | if (strstr(cmd, "off")) { |
790 | led_cmd = 0xc0; | 1110 | ind = 0; |
791 | sysl_cmd = 2; | ||
792 | bled_a = 2; | ||
793 | bled_b = 1; | ||
794 | } else if (strstr(cmd, "on")) { | 1111 | } else if (strstr(cmd, "on")) { |
795 | led_cmd = 0x80; | 1112 | ind = 1; |
796 | sysl_cmd = 1; | 1113 | } else if (strstr(cmd, "blink")) { |
797 | bled_a = 2; | 1114 | ind = 2; |
798 | bled_b = 0; | ||
799 | } else if (strstr(cmd, "off")) { | ||
800 | led_cmd = sysl_cmd = bled_a = bled_b = 0; | ||
801 | } else | 1115 | } else |
802 | return -EINVAL; | 1116 | return -EINVAL; |
803 | 1117 | ||
804 | if (led_handle) { | 1118 | if (led_supported == LED_570) { |
1119 | /* 570 */ | ||
1120 | led = 1 << led; | ||
805 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", | 1121 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", |
806 | led, led_cmd)) | 1122 | led, led_sled_arg1[ind])) |
807 | return -EIO; | 1123 | return -EIO; |
808 | } else if (led < 2) { | 1124 | } else if (led_supported == LED_OLD) { |
809 | if (acpi_evalf(sysl_handle, NULL, NULL, "vdd", | 1125 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ |
810 | led, sysl_cmd)) | 1126 | led = 1 << led; |
1127 | ret = ec_write(EC_HLMS, led); | ||
1128 | if (ret >= 0) | ||
1129 | ret = | ||
1130 | ec_write(EC_HLBL, led * led_exp_hlbl[ind]); | ||
1131 | if (ret >= 0) | ||
1132 | ret = | ||
1133 | ec_write(EC_HLCL, led * led_exp_hlcl[ind]); | ||
1134 | if (ret < 0) | ||
1135 | return ret; | ||
1136 | } else { | ||
1137 | /* all others */ | ||
1138 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", | ||
1139 | led, led_led_arg1[ind])) | ||
811 | return -EIO; | 1140 | return -EIO; |
812 | } else if (led == 2 && bled_handle) { | 1141 | } |
813 | if (acpi_evalf(bled_handle, NULL, NULL, "vdd", | 1142 | } |
814 | bled_a, bled_b)) | 1143 | |
1144 | return 0; | ||
1145 | } | ||
1146 | |||
1147 | static int beep_read(char *p) | ||
1148 | { | ||
1149 | int len = 0; | ||
1150 | |||
1151 | if (!beep_handle) | ||
1152 | len += sprintf(p + len, "status:\t\tnot supported\n"); | ||
1153 | else { | ||
1154 | len += sprintf(p + len, "status:\t\tsupported\n"); | ||
1155 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n"); | ||
1156 | } | ||
1157 | |||
1158 | return len; | ||
1159 | } | ||
1160 | |||
1161 | static int beep_write(char *buf) | ||
1162 | { | ||
1163 | char *cmd; | ||
1164 | int beep_cmd; | ||
1165 | |||
1166 | if (!beep_handle) | ||
1167 | return -ENODEV; | ||
1168 | |||
1169 | while ((cmd = next_cmd(&buf))) { | ||
1170 | if (sscanf(cmd, "%u", &beep_cmd) == 1 && | ||
1171 | beep_cmd >= 0 && beep_cmd <= 17) { | ||
1172 | /* beep_cmd set */ | ||
1173 | } else | ||
1174 | return -EINVAL; | ||
1175 | if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0)) | ||
1176 | return -EIO; | ||
1177 | } | ||
1178 | |||
1179 | return 0; | ||
1180 | } | ||
1181 | |||
1182 | static int acpi_ec_read(int i, u8 * p) | ||
1183 | { | ||
1184 | int v; | ||
1185 | |||
1186 | if (ecrd_handle) { | ||
1187 | if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i)) | ||
1188 | return 0; | ||
1189 | *p = v; | ||
1190 | } else { | ||
1191 | if (ec_read(i, p) < 0) | ||
1192 | return 0; | ||
1193 | } | ||
1194 | |||
1195 | return 1; | ||
1196 | } | ||
1197 | |||
1198 | static int acpi_ec_write(int i, u8 v) | ||
1199 | { | ||
1200 | if (ecwr_handle) { | ||
1201 | if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v)) | ||
1202 | return 0; | ||
1203 | } else { | ||
1204 | if (ec_write(i, v) < 0) | ||
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1208 | return 1; | ||
1209 | } | ||
1210 | |||
1211 | static int thermal_tmp_supported; | ||
1212 | static int thermal_updt_supported; | ||
1213 | |||
1214 | static int thermal_init(void) | ||
1215 | { | ||
1216 | /* temperatures not supported on 570, G4x, R30, R31, R32 */ | ||
1217 | thermal_tmp_supported = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); | ||
1218 | |||
1219 | /* 600e/x, 770e, 770x */ | ||
1220 | thermal_updt_supported = acpi_evalf(ec_handle, NULL, "UPDT", "qv"); | ||
1221 | |||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | static int thermal_read(char *p) | ||
1226 | { | ||
1227 | int len = 0; | ||
1228 | |||
1229 | if (!thermal_tmp_supported) | ||
1230 | len += sprintf(p + len, "temperatures:\tnot supported\n"); | ||
1231 | else { | ||
1232 | int i, t; | ||
1233 | char tmpi[] = "TMPi"; | ||
1234 | s8 tmp[8]; | ||
1235 | |||
1236 | if (thermal_updt_supported) | ||
1237 | if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) | ||
1238 | return -EIO; | ||
1239 | |||
1240 | for (i = 0; i < 8; i++) { | ||
1241 | tmpi[3] = '0' + i; | ||
1242 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) | ||
1243 | return -EIO; | ||
1244 | if (thermal_updt_supported) | ||
1245 | tmp[i] = (t - 2732 + 5) / 10; | ||
1246 | else | ||
1247 | tmp[i] = t; | ||
1248 | } | ||
1249 | |||
1250 | len += sprintf(p + len, | ||
1251 | "temperatures:\t%d %d %d %d %d %d %d %d\n", | ||
1252 | tmp[0], tmp[1], tmp[2], tmp[3], | ||
1253 | tmp[4], tmp[5], tmp[6], tmp[7]); | ||
1254 | } | ||
1255 | |||
1256 | return len; | ||
1257 | } | ||
1258 | |||
1259 | static u8 ecdump_regs[256]; | ||
1260 | |||
1261 | static int ecdump_read(char *p) | ||
1262 | { | ||
1263 | int len = 0; | ||
1264 | int i, j; | ||
1265 | u8 v; | ||
1266 | |||
1267 | len += sprintf(p + len, "EC " | ||
1268 | " +00 +01 +02 +03 +04 +05 +06 +07" | ||
1269 | " +08 +09 +0a +0b +0c +0d +0e +0f\n"); | ||
1270 | for (i = 0; i < 256; i += 16) { | ||
1271 | len += sprintf(p + len, "EC 0x%02x:", i); | ||
1272 | for (j = 0; j < 16; j++) { | ||
1273 | if (!acpi_ec_read(i + j, &v)) | ||
1274 | break; | ||
1275 | if (v != ecdump_regs[i + j]) | ||
1276 | len += sprintf(p + len, " *%02x", v); | ||
1277 | else | ||
1278 | len += sprintf(p + len, " %02x", v); | ||
1279 | ecdump_regs[i + j] = v; | ||
1280 | } | ||
1281 | len += sprintf(p + len, "\n"); | ||
1282 | if (j != 16) | ||
1283 | break; | ||
1284 | } | ||
1285 | |||
1286 | /* These are way too dangerous to advertise openly... */ | ||
1287 | #if 0 | ||
1288 | len += sprintf(p + len, "commands:\t0x<offset> 0x<value>" | ||
1289 | " (<offset> is 00-ff, <value> is 00-ff)\n"); | ||
1290 | len += sprintf(p + len, "commands:\t0x<offset> <value> " | ||
1291 | " (<offset> is 00-ff, <value> is 0-255)\n"); | ||
1292 | #endif | ||
1293 | return len; | ||
1294 | } | ||
1295 | |||
1296 | static int ecdump_write(char *buf) | ||
1297 | { | ||
1298 | char *cmd; | ||
1299 | int i, v; | ||
1300 | |||
1301 | while ((cmd = next_cmd(&buf))) { | ||
1302 | if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) { | ||
1303 | /* i and v set */ | ||
1304 | } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) { | ||
1305 | /* i and v set */ | ||
1306 | } else | ||
1307 | return -EINVAL; | ||
1308 | if (i >= 0 && i < 256 && v >= 0 && v < 256) { | ||
1309 | if (!acpi_ec_write(i, v)) | ||
815 | return -EIO; | 1310 | return -EIO; |
816 | } else | 1311 | } else |
817 | return -EINVAL; | 1312 | return -EINVAL; |
@@ -820,28 +1315,224 @@ static int led_write(struct ibm_struct *ibm, char *buf) | |||
820 | return 0; | 1315 | return 0; |
821 | } | 1316 | } |
822 | 1317 | ||
823 | static int beep_read(struct ibm_struct *ibm, char *p) | 1318 | static int brightness_offset = 0x31; |
1319 | |||
1320 | static int brightness_read(char *p) | ||
824 | { | 1321 | { |
825 | int len = 0; | 1322 | int len = 0; |
1323 | u8 level; | ||
826 | 1324 | ||
827 | len += sprintf(p + len, "commands:\t<int>\n"); | 1325 | if (!acpi_ec_read(brightness_offset, &level)) { |
1326 | len += sprintf(p + len, "level:\t\tunreadable\n"); | ||
1327 | } else { | ||
1328 | len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); | ||
1329 | len += sprintf(p + len, "commands:\tup, down\n"); | ||
1330 | len += sprintf(p + len, "commands:\tlevel <level>" | ||
1331 | " (<level> is 0-7)\n"); | ||
1332 | } | ||
828 | 1333 | ||
829 | return len; | 1334 | return len; |
830 | } | 1335 | } |
831 | 1336 | ||
832 | static int beep_write(struct ibm_struct *ibm, char *buf) | 1337 | #define BRIGHTNESS_UP 4 |
1338 | #define BRIGHTNESS_DOWN 5 | ||
1339 | |||
1340 | static int brightness_write(char *buf) | ||
833 | { | 1341 | { |
1342 | int cmos_cmd, inc, i; | ||
1343 | u8 level; | ||
1344 | int new_level; | ||
834 | char *cmd; | 1345 | char *cmd; |
835 | int beep_cmd; | ||
836 | 1346 | ||
837 | while ((cmd = next_cmd(&buf))) { | 1347 | while ((cmd = next_cmd(&buf))) { |
838 | if (sscanf(cmd, "%u", &beep_cmd) == 1) { | 1348 | if (!acpi_ec_read(brightness_offset, &level)) |
839 | /* beep_cmd set */ | 1349 | return -EIO; |
1350 | level &= 7; | ||
1351 | |||
1352 | if (strlencmp(cmd, "up") == 0) { | ||
1353 | new_level = level == 7 ? 7 : level + 1; | ||
1354 | } else if (strlencmp(cmd, "down") == 0) { | ||
1355 | new_level = level == 0 ? 0 : level - 1; | ||
1356 | } else if (sscanf(cmd, "level %d", &new_level) == 1 && | ||
1357 | new_level >= 0 && new_level <= 7) { | ||
1358 | /* new_level set */ | ||
1359 | } else | ||
1360 | return -EINVAL; | ||
1361 | |||
1362 | cmos_cmd = new_level > level ? BRIGHTNESS_UP : BRIGHTNESS_DOWN; | ||
1363 | inc = new_level > level ? 1 : -1; | ||
1364 | for (i = level; i != new_level; i += inc) { | ||
1365 | if (!cmos_eval(cmos_cmd)) | ||
1366 | return -EIO; | ||
1367 | if (!acpi_ec_write(brightness_offset, i + inc)) | ||
1368 | return -EIO; | ||
1369 | } | ||
1370 | } | ||
1371 | |||
1372 | return 0; | ||
1373 | } | ||
1374 | |||
1375 | static int volume_offset = 0x30; | ||
1376 | |||
1377 | static int volume_read(char *p) | ||
1378 | { | ||
1379 | int len = 0; | ||
1380 | u8 level; | ||
1381 | |||
1382 | if (!acpi_ec_read(volume_offset, &level)) { | ||
1383 | len += sprintf(p + len, "level:\t\tunreadable\n"); | ||
1384 | } else { | ||
1385 | len += sprintf(p + len, "level:\t\t%d\n", level & 0xf); | ||
1386 | len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6)); | ||
1387 | len += sprintf(p + len, "commands:\tup, down, mute\n"); | ||
1388 | len += sprintf(p + len, "commands:\tlevel <level>" | ||
1389 | " (<level> is 0-15)\n"); | ||
1390 | } | ||
1391 | |||
1392 | return len; | ||
1393 | } | ||
1394 | |||
1395 | #define VOLUME_DOWN 0 | ||
1396 | #define VOLUME_UP 1 | ||
1397 | #define VOLUME_MUTE 2 | ||
1398 | |||
1399 | static int volume_write(char *buf) | ||
1400 | { | ||
1401 | int cmos_cmd, inc, i; | ||
1402 | u8 level, mute; | ||
1403 | int new_level, new_mute; | ||
1404 | char *cmd; | ||
1405 | |||
1406 | while ((cmd = next_cmd(&buf))) { | ||
1407 | if (!acpi_ec_read(volume_offset, &level)) | ||
1408 | return -EIO; | ||
1409 | new_mute = mute = level & 0x40; | ||
1410 | new_level = level = level & 0xf; | ||
1411 | |||
1412 | if (strlencmp(cmd, "up") == 0) { | ||
1413 | if (mute) | ||
1414 | new_mute = 0; | ||
1415 | else | ||
1416 | new_level = level == 15 ? 15 : level + 1; | ||
1417 | } else if (strlencmp(cmd, "down") == 0) { | ||
1418 | if (mute) | ||
1419 | new_mute = 0; | ||
1420 | else | ||
1421 | new_level = level == 0 ? 0 : level - 1; | ||
1422 | } else if (sscanf(cmd, "level %d", &new_level) == 1 && | ||
1423 | new_level >= 0 && new_level <= 15) { | ||
1424 | /* new_level set */ | ||
1425 | } else if (strlencmp(cmd, "mute") == 0) { | ||
1426 | new_mute = 0x40; | ||
840 | } else | 1427 | } else |
841 | return -EINVAL; | 1428 | return -EINVAL; |
842 | 1429 | ||
843 | if (!acpi_evalf(beep_handle, NULL, NULL, "vd", beep_cmd)) | 1430 | if (new_level != level) { /* mute doesn't change */ |
1431 | cmos_cmd = new_level > level ? VOLUME_UP : VOLUME_DOWN; | ||
1432 | inc = new_level > level ? 1 : -1; | ||
1433 | |||
1434 | if (mute && (!cmos_eval(cmos_cmd) || | ||
1435 | !acpi_ec_write(volume_offset, level))) | ||
1436 | return -EIO; | ||
1437 | |||
1438 | for (i = level; i != new_level; i += inc) | ||
1439 | if (!cmos_eval(cmos_cmd) || | ||
1440 | !acpi_ec_write(volume_offset, i + inc)) | ||
1441 | return -EIO; | ||
1442 | |||
1443 | if (mute && (!cmos_eval(VOLUME_MUTE) || | ||
1444 | !acpi_ec_write(volume_offset, | ||
1445 | new_level + mute))) | ||
1446 | return -EIO; | ||
1447 | } | ||
1448 | |||
1449 | if (new_mute != mute) { /* level doesn't change */ | ||
1450 | cmos_cmd = new_mute ? VOLUME_MUTE : VOLUME_UP; | ||
1451 | |||
1452 | if (!cmos_eval(cmos_cmd) || | ||
1453 | !acpi_ec_write(volume_offset, level + new_mute)) | ||
1454 | return -EIO; | ||
1455 | } | ||
1456 | } | ||
1457 | |||
1458 | return 0; | ||
1459 | } | ||
1460 | |||
1461 | static int fan_status_offset = 0x2f; | ||
1462 | static int fan_rpm_offset = 0x84; | ||
1463 | |||
1464 | static int fan_read(char *p) | ||
1465 | { | ||
1466 | int len = 0; | ||
1467 | int s; | ||
1468 | u8 lo, hi, status; | ||
1469 | |||
1470 | if (gfan_handle) { | ||
1471 | /* 570, 600e/x, 770e, 770x */ | ||
1472 | if (!acpi_evalf(gfan_handle, &s, NULL, "d")) | ||
844 | return -EIO; | 1473 | return -EIO; |
1474 | |||
1475 | len += sprintf(p + len, "level:\t\t%d\n", s); | ||
1476 | } else { | ||
1477 | /* all except 570, 600e/x, 770e, 770x */ | ||
1478 | if (!acpi_ec_read(fan_status_offset, &status)) | ||
1479 | len += sprintf(p + len, "status:\t\tunreadable\n"); | ||
1480 | else | ||
1481 | len += sprintf(p + len, "status:\t\t%s\n", | ||
1482 | enabled(status, 7)); | ||
1483 | |||
1484 | if (!acpi_ec_read(fan_rpm_offset, &lo) || | ||
1485 | !acpi_ec_read(fan_rpm_offset + 1, &hi)) | ||
1486 | len += sprintf(p + len, "speed:\t\tunreadable\n"); | ||
1487 | else | ||
1488 | len += sprintf(p + len, "speed:\t\t%d\n", | ||
1489 | (hi << 8) + lo); | ||
1490 | } | ||
1491 | |||
1492 | if (sfan_handle) | ||
1493 | /* 570, 770x-JL */ | ||
1494 | len += sprintf(p + len, "commands:\tlevel <level>" | ||
1495 | " (<level> is 0-7)\n"); | ||
1496 | if (!gfan_handle) | ||
1497 | /* all except 570, 600e/x, 770e, 770x */ | ||
1498 | len += sprintf(p + len, "commands:\tenable, disable\n"); | ||
1499 | if (fans_handle) | ||
1500 | /* X31, X40 */ | ||
1501 | len += sprintf(p + len, "commands:\tspeed <speed>" | ||
1502 | " (<speed> is 0-65535)\n"); | ||
1503 | |||
1504 | return len; | ||
1505 | } | ||
1506 | |||
1507 | static int fan_write(char *buf) | ||
1508 | { | ||
1509 | char *cmd; | ||
1510 | int level, speed; | ||
1511 | |||
1512 | while ((cmd = next_cmd(&buf))) { | ||
1513 | if (sfan_handle && | ||
1514 | sscanf(cmd, "level %d", &level) == 1 && | ||
1515 | level >= 0 && level <= 7) { | ||
1516 | /* 570, 770x-JL */ | ||
1517 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) | ||
1518 | return -EIO; | ||
1519 | } else if (!gfan_handle && strlencmp(cmd, "enable") == 0) { | ||
1520 | /* all except 570, 600e/x, 770e, 770x */ | ||
1521 | if (!acpi_ec_write(fan_status_offset, 0x80)) | ||
1522 | return -EIO; | ||
1523 | } else if (!gfan_handle && strlencmp(cmd, "disable") == 0) { | ||
1524 | /* all except 570, 600e/x, 770e, 770x */ | ||
1525 | if (!acpi_ec_write(fan_status_offset, 0x00)) | ||
1526 | return -EIO; | ||
1527 | } else if (fans_handle && | ||
1528 | sscanf(cmd, "speed %d", &speed) == 1 && | ||
1529 | speed >= 0 && speed <= 65535) { | ||
1530 | /* X31, X40 */ | ||
1531 | if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", | ||
1532 | speed, speed, speed)) | ||
1533 | return -EIO; | ||
1534 | } else | ||
1535 | return -EINVAL; | ||
845 | } | 1536 | } |
846 | 1537 | ||
847 | return 0; | 1538 | return 0; |
@@ -855,7 +1546,7 @@ static struct ibm_struct ibms[] = { | |||
855 | }, | 1546 | }, |
856 | { | 1547 | { |
857 | .name = "hotkey", | 1548 | .name = "hotkey", |
858 | .hid = "IBM0068", | 1549 | .hid = IBM_HKEY_HID, |
859 | .init = hotkey_init, | 1550 | .init = hotkey_init, |
860 | .read = hotkey_read, | 1551 | .read = hotkey_read, |
861 | .write = hotkey_write, | 1552 | .write = hotkey_write, |
@@ -892,6 +1583,13 @@ static struct ibm_struct ibms[] = { | |||
892 | .type = ACPI_SYSTEM_NOTIFY, | 1583 | .type = ACPI_SYSTEM_NOTIFY, |
893 | }, | 1584 | }, |
894 | { | 1585 | { |
1586 | .name = "dock", | ||
1587 | .hid = IBM_PCI_HID, | ||
1588 | .notify = dock_notify, | ||
1589 | .handle = &pci_handle, | ||
1590 | .type = ACPI_SYSTEM_NOTIFY, | ||
1591 | }, | ||
1592 | { | ||
895 | .name = "bay", | 1593 | .name = "bay", |
896 | .init = bay_init, | 1594 | .init = bay_init, |
897 | .read = bay_read, | 1595 | .read = bay_read, |
@@ -904,24 +1602,49 @@ static struct ibm_struct ibms[] = { | |||
904 | .name = "cmos", | 1602 | .name = "cmos", |
905 | .read = cmos_read, | 1603 | .read = cmos_read, |
906 | .write = cmos_write, | 1604 | .write = cmos_write, |
907 | .experimental = 1, | ||
908 | }, | 1605 | }, |
909 | { | 1606 | { |
910 | .name = "led", | 1607 | .name = "led", |
1608 | .init = led_init, | ||
911 | .read = led_read, | 1609 | .read = led_read, |
912 | .write = led_write, | 1610 | .write = led_write, |
913 | .experimental = 1, | ||
914 | }, | 1611 | }, |
915 | { | 1612 | { |
916 | .name = "beep", | 1613 | .name = "beep", |
917 | .read = beep_read, | 1614 | .read = beep_read, |
918 | .write = beep_write, | 1615 | .write = beep_write, |
1616 | }, | ||
1617 | { | ||
1618 | .name = "thermal", | ||
1619 | .init = thermal_init, | ||
1620 | .read = thermal_read, | ||
1621 | }, | ||
1622 | { | ||
1623 | .name = "ecdump", | ||
1624 | .read = ecdump_read, | ||
1625 | .write = ecdump_write, | ||
1626 | .experimental = 1, | ||
1627 | }, | ||
1628 | { | ||
1629 | .name = "brightness", | ||
1630 | .read = brightness_read, | ||
1631 | .write = brightness_write, | ||
1632 | .experimental = 1, | ||
1633 | }, | ||
1634 | { | ||
1635 | .name = "volume", | ||
1636 | .read = volume_read, | ||
1637 | .write = volume_write, | ||
1638 | .experimental = 1, | ||
1639 | }, | ||
1640 | { | ||
1641 | .name = "fan", | ||
1642 | .read = fan_read, | ||
1643 | .write = fan_write, | ||
919 | .experimental = 1, | 1644 | .experimental = 1, |
920 | }, | 1645 | }, |
921 | }; | 1646 | }; |
922 | 1647 | ||
923 | #define NUM_IBMS (sizeof(ibms)/sizeof(ibms[0])) | ||
924 | |||
925 | static int dispatch_read(char *page, char **start, off_t off, int count, | 1648 | static int dispatch_read(char *page, char **start, off_t off, int count, |
926 | int *eof, void *data) | 1649 | int *eof, void *data) |
927 | { | 1650 | { |
@@ -931,7 +1654,7 @@ static int dispatch_read(char *page, char **start, off_t off, int count, | |||
931 | if (!ibm || !ibm->read) | 1654 | if (!ibm || !ibm->read) |
932 | return -EINVAL; | 1655 | return -EINVAL; |
933 | 1656 | ||
934 | len = ibm->read(ibm, page); | 1657 | len = ibm->read(page); |
935 | if (len < 0) | 1658 | if (len < 0) |
936 | return len; | 1659 | return len; |
937 | 1660 | ||
@@ -968,7 +1691,7 @@ static int dispatch_write(struct file *file, const char __user * userbuf, | |||
968 | 1691 | ||
969 | kernbuf[count] = 0; | 1692 | kernbuf[count] = 0; |
970 | strcat(kernbuf, ","); | 1693 | strcat(kernbuf, ","); |
971 | ret = ibm->write(ibm, kernbuf); | 1694 | ret = ibm->write(kernbuf); |
972 | if (ret == 0) | 1695 | if (ret == 0) |
973 | ret = count; | 1696 | ret = count; |
974 | 1697 | ||
@@ -987,7 +1710,7 @@ static void dispatch_notify(acpi_handle handle, u32 event, void *data) | |||
987 | ibm->notify(ibm, event); | 1710 | ibm->notify(ibm, event); |
988 | } | 1711 | } |
989 | 1712 | ||
990 | static int setup_notify(struct ibm_struct *ibm) | 1713 | static int __init setup_notify(struct ibm_struct *ibm) |
991 | { | 1714 | { |
992 | acpi_status status; | 1715 | acpi_status status; |
993 | int ret; | 1716 | int ret; |
@@ -1012,17 +1735,15 @@ static int setup_notify(struct ibm_struct *ibm) | |||
1012 | return -ENODEV; | 1735 | return -ENODEV; |
1013 | } | 1736 | } |
1014 | 1737 | ||
1015 | ibm->notify_installed = 1; | ||
1016 | |||
1017 | return 0; | 1738 | return 0; |
1018 | } | 1739 | } |
1019 | 1740 | ||
1020 | static int ibmacpi_device_add(struct acpi_device *device) | 1741 | static int __init ibm_device_add(struct acpi_device *device) |
1021 | { | 1742 | { |
1022 | return 0; | 1743 | return 0; |
1023 | } | 1744 | } |
1024 | 1745 | ||
1025 | static int register_driver(struct ibm_struct *ibm) | 1746 | static int __init register_driver(struct ibm_struct *ibm) |
1026 | { | 1747 | { |
1027 | int ret; | 1748 | int ret; |
1028 | 1749 | ||
@@ -1035,7 +1756,7 @@ static int register_driver(struct ibm_struct *ibm) | |||
1035 | memset(ibm->driver, 0, sizeof(struct acpi_driver)); | 1756 | memset(ibm->driver, 0, sizeof(struct acpi_driver)); |
1036 | sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name); | 1757 | sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name); |
1037 | ibm->driver->ids = ibm->hid; | 1758 | ibm->driver->ids = ibm->hid; |
1038 | ibm->driver->ops.add = &ibmacpi_device_add; | 1759 | ibm->driver->ops.add = &ibm_device_add; |
1039 | 1760 | ||
1040 | ret = acpi_bus_register_driver(ibm->driver); | 1761 | ret = acpi_bus_register_driver(ibm->driver); |
1041 | if (ret < 0) { | 1762 | if (ret < 0) { |
@@ -1047,7 +1768,7 @@ static int register_driver(struct ibm_struct *ibm) | |||
1047 | return ret; | 1768 | return ret; |
1048 | } | 1769 | } |
1049 | 1770 | ||
1050 | static int ibm_init(struct ibm_struct *ibm) | 1771 | static int __init ibm_init(struct ibm_struct *ibm) |
1051 | { | 1772 | { |
1052 | int ret; | 1773 | int ret; |
1053 | struct proc_dir_entry *entry; | 1774 | struct proc_dir_entry *entry; |
@@ -1063,31 +1784,34 @@ static int ibm_init(struct ibm_struct *ibm) | |||
1063 | } | 1784 | } |
1064 | 1785 | ||
1065 | if (ibm->init) { | 1786 | if (ibm->init) { |
1066 | ret = ibm->init(ibm); | 1787 | ret = ibm->init(); |
1067 | if (ret != 0) | 1788 | if (ret != 0) |
1068 | return ret; | 1789 | return ret; |
1069 | ibm->init_called = 1; | 1790 | ibm->init_called = 1; |
1070 | } | 1791 | } |
1071 | 1792 | ||
1072 | entry = create_proc_entry(ibm->name, S_IFREG | S_IRUGO | S_IWUSR, | 1793 | if (ibm->read) { |
1073 | proc_dir); | 1794 | entry = create_proc_entry(ibm->name, |
1074 | if (!entry) { | 1795 | S_IFREG | S_IRUGO | S_IWUSR, |
1075 | printk(IBM_ERR "unable to create proc entry %s\n", ibm->name); | 1796 | proc_dir); |
1076 | return -ENODEV; | 1797 | if (!entry) { |
1077 | } | 1798 | printk(IBM_ERR "unable to create proc entry %s\n", |
1078 | entry->owner = THIS_MODULE; | 1799 | ibm->name); |
1079 | ibm->proc_created = 1; | 1800 | return -ENODEV; |
1080 | 1801 | } | |
1081 | entry->data = ibm; | 1802 | entry->owner = THIS_MODULE; |
1082 | if (ibm->read) | 1803 | entry->data = ibm; |
1083 | entry->read_proc = &dispatch_read; | 1804 | entry->read_proc = &dispatch_read; |
1084 | if (ibm->write) | 1805 | if (ibm->write) |
1085 | entry->write_proc = &dispatch_write; | 1806 | entry->write_proc = &dispatch_write; |
1807 | ibm->proc_created = 1; | ||
1808 | } | ||
1086 | 1809 | ||
1087 | if (ibm->notify) { | 1810 | if (ibm->notify) { |
1088 | ret = setup_notify(ibm); | 1811 | ret = setup_notify(ibm); |
1089 | if (ret < 0) | 1812 | if (ret < 0) |
1090 | return ret; | 1813 | return ret; |
1814 | ibm->notify_installed = 1; | ||
1091 | } | 1815 | } |
1092 | 1816 | ||
1093 | return 0; | 1817 | return 0; |
@@ -1103,7 +1827,7 @@ static void ibm_exit(struct ibm_struct *ibm) | |||
1103 | remove_proc_entry(ibm->name, proc_dir); | 1827 | remove_proc_entry(ibm->name, proc_dir); |
1104 | 1828 | ||
1105 | if (ibm->init_called && ibm->exit) | 1829 | if (ibm->init_called && ibm->exit) |
1106 | ibm->exit(ibm); | 1830 | ibm->exit(); |
1107 | 1831 | ||
1108 | if (ibm->driver_registered) { | 1832 | if (ibm->driver_registered) { |
1109 | acpi_bus_unregister_driver(ibm->driver); | 1833 | acpi_bus_unregister_driver(ibm->driver); |
@@ -1111,59 +1835,66 @@ static void ibm_exit(struct ibm_struct *ibm) | |||
1111 | } | 1835 | } |
1112 | } | 1836 | } |
1113 | 1837 | ||
1114 | static int ibm_handle_init(char *name, | 1838 | static void __init ibm_handle_init(char *name, |
1115 | acpi_handle * handle, acpi_handle parent, | 1839 | acpi_handle * handle, acpi_handle parent, |
1116 | char **paths, int num_paths, int required) | 1840 | char **paths, int num_paths, char **path) |
1117 | { | 1841 | { |
1118 | int i; | 1842 | int i; |
1119 | acpi_status status; | 1843 | acpi_status status; |
1120 | 1844 | ||
1121 | for (i = 0; i < num_paths; i++) { | 1845 | for (i = 0; i < num_paths; i++) { |
1122 | status = acpi_get_handle(parent, paths[i], handle); | 1846 | status = acpi_get_handle(parent, paths[i], handle); |
1123 | if (ACPI_SUCCESS(status)) | 1847 | if (ACPI_SUCCESS(status)) { |
1124 | return 0; | 1848 | *path = paths[i]; |
1849 | return; | ||
1850 | } | ||
1125 | } | 1851 | } |
1126 | 1852 | ||
1127 | *handle = NULL; | 1853 | *handle = NULL; |
1128 | |||
1129 | if (required) { | ||
1130 | printk(IBM_ERR "%s object not found\n", name); | ||
1131 | return -1; | ||
1132 | } | ||
1133 | |||
1134 | return 0; | ||
1135 | } | 1854 | } |
1136 | 1855 | ||
1137 | #define IBM_HANDLE_INIT(object, required) \ | 1856 | #define IBM_HANDLE_INIT(object) \ |
1138 | ibm_handle_init(#object, &object##_handle, *object##_parent, \ | 1857 | ibm_handle_init(#object, &object##_handle, *object##_parent, \ |
1139 | object##_paths, sizeof(object##_paths)/sizeof(char*), required) | 1858 | object##_paths, ARRAY_SIZE(object##_paths), &object##_path) |
1140 | 1859 | ||
1141 | static int set_ibm_param(const char *val, struct kernel_param *kp) | 1860 | static int set_ibm_param(const char *val, struct kernel_param *kp) |
1142 | { | 1861 | { |
1143 | unsigned int i; | 1862 | unsigned int i; |
1144 | char arg_with_comma[32]; | ||
1145 | |||
1146 | if (strlen(val) > 30) | ||
1147 | return -ENOSPC; | ||
1148 | 1863 | ||
1149 | strcpy(arg_with_comma, val); | 1864 | for (i = 0; i < ARRAY_SIZE(ibms); i++) |
1150 | strcat(arg_with_comma, ","); | 1865 | if (strcmp(ibms[i].name, kp->name) == 0 && ibms[i].write) { |
1866 | if (strlen(val) > sizeof(ibms[i].param) - 2) | ||
1867 | return -ENOSPC; | ||
1868 | strcpy(ibms[i].param, val); | ||
1869 | strcat(ibms[i].param, ","); | ||
1870 | return 0; | ||
1871 | } | ||
1151 | 1872 | ||
1152 | for (i = 0; i < NUM_IBMS; i++) | ||
1153 | if (strcmp(ibms[i].name, kp->name) == 0) | ||
1154 | return ibms[i].write(&ibms[i], arg_with_comma); | ||
1155 | BUG(); | ||
1156 | return -EINVAL; | 1873 | return -EINVAL; |
1157 | } | 1874 | } |
1158 | 1875 | ||
1159 | #define IBM_PARAM(feature) \ | 1876 | #define IBM_PARAM(feature) \ |
1160 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) | 1877 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) |
1161 | 1878 | ||
1879 | IBM_PARAM(hotkey); | ||
1880 | IBM_PARAM(bluetooth); | ||
1881 | IBM_PARAM(video); | ||
1882 | IBM_PARAM(light); | ||
1883 | IBM_PARAM(dock); | ||
1884 | IBM_PARAM(bay); | ||
1885 | IBM_PARAM(cmos); | ||
1886 | IBM_PARAM(led); | ||
1887 | IBM_PARAM(beep); | ||
1888 | IBM_PARAM(ecdump); | ||
1889 | IBM_PARAM(brightness); | ||
1890 | IBM_PARAM(volume); | ||
1891 | IBM_PARAM(fan); | ||
1892 | |||
1162 | static void acpi_ibm_exit(void) | 1893 | static void acpi_ibm_exit(void) |
1163 | { | 1894 | { |
1164 | int i; | 1895 | int i; |
1165 | 1896 | ||
1166 | for (i = NUM_IBMS - 1; i >= 0; i--) | 1897 | for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--) |
1167 | ibm_exit(&ibms[i]); | 1898 | ibm_exit(&ibms[i]); |
1168 | 1899 | ||
1169 | remove_proc_entry(IBM_DIR, acpi_root_dir); | 1900 | remove_proc_entry(IBM_DIR, acpi_root_dir); |
@@ -1177,28 +1908,39 @@ static int __init acpi_ibm_init(void) | |||
1177 | return -ENODEV; | 1908 | return -ENODEV; |
1178 | 1909 | ||
1179 | if (!acpi_specific_hotkey_enabled) { | 1910 | if (!acpi_specific_hotkey_enabled) { |
1180 | printk(IBM_ERR "Using generic hotkey driver\n"); | 1911 | printk(IBM_ERR "using generic hotkey driver\n"); |
1181 | return -ENODEV; | 1912 | return -ENODEV; |
1182 | } | 1913 | } |
1183 | /* these handles are required */ | ||
1184 | if (IBM_HANDLE_INIT(ec, 1) < 0 || | ||
1185 | IBM_HANDLE_INIT(hkey, 1) < 0 || | ||
1186 | IBM_HANDLE_INIT(vid, 1) < 0 || IBM_HANDLE_INIT(beep, 1) < 0) | ||
1187 | return -ENODEV; | ||
1188 | 1914 | ||
1189 | /* these handles have alternatives */ | 1915 | /* ec is required because many other handles are relative to it */ |
1190 | IBM_HANDLE_INIT(lght, 0); | 1916 | IBM_HANDLE_INIT(ec); |
1191 | if (IBM_HANDLE_INIT(cmos, !lght_handle) < 0) | 1917 | if (!ec_handle) { |
1192 | return -ENODEV; | 1918 | printk(IBM_ERR "ec object not found\n"); |
1193 | IBM_HANDLE_INIT(sysl, 0); | ||
1194 | if (IBM_HANDLE_INIT(led, !sysl_handle) < 0) | ||
1195 | return -ENODEV; | 1919 | return -ENODEV; |
1920 | } | ||
1196 | 1921 | ||
1197 | /* these handles are not required */ | 1922 | /* these handles are not required */ |
1198 | IBM_HANDLE_INIT(dock, 0); | 1923 | IBM_HANDLE_INIT(vid); |
1199 | IBM_HANDLE_INIT(bay, 0); | 1924 | IBM_HANDLE_INIT(vid2); |
1200 | IBM_HANDLE_INIT(bayej, 0); | 1925 | IBM_HANDLE_INIT(ledb); |
1201 | IBM_HANDLE_INIT(bled, 0); | 1926 | IBM_HANDLE_INIT(led); |
1927 | IBM_HANDLE_INIT(hkey); | ||
1928 | IBM_HANDLE_INIT(lght); | ||
1929 | IBM_HANDLE_INIT(cmos); | ||
1930 | IBM_HANDLE_INIT(dock); | ||
1931 | IBM_HANDLE_INIT(pci); | ||
1932 | IBM_HANDLE_INIT(bay); | ||
1933 | if (bay_handle) | ||
1934 | IBM_HANDLE_INIT(bay_ej); | ||
1935 | IBM_HANDLE_INIT(bay2); | ||
1936 | if (bay2_handle) | ||
1937 | IBM_HANDLE_INIT(bay2_ej); | ||
1938 | IBM_HANDLE_INIT(beep); | ||
1939 | IBM_HANDLE_INIT(ecrd); | ||
1940 | IBM_HANDLE_INIT(ecwr); | ||
1941 | IBM_HANDLE_INIT(fans); | ||
1942 | IBM_HANDLE_INIT(gfan); | ||
1943 | IBM_HANDLE_INIT(sfan); | ||
1202 | 1944 | ||
1203 | proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); | 1945 | proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); |
1204 | if (!proc_dir) { | 1946 | if (!proc_dir) { |
@@ -1207,8 +1949,10 @@ static int __init acpi_ibm_init(void) | |||
1207 | } | 1949 | } |
1208 | proc_dir->owner = THIS_MODULE; | 1950 | proc_dir->owner = THIS_MODULE; |
1209 | 1951 | ||
1210 | for (i = 0; i < NUM_IBMS; i++) { | 1952 | for (i = 0; i < ARRAY_SIZE(ibms); i++) { |
1211 | ret = ibm_init(&ibms[i]); | 1953 | ret = ibm_init(&ibms[i]); |
1954 | if (ret >= 0 && *ibms[i].param) | ||
1955 | ret = ibms[i].write(ibms[i].param); | ||
1212 | if (ret < 0) { | 1956 | if (ret < 0) { |
1213 | acpi_ibm_exit(); | 1957 | acpi_ibm_exit(); |
1214 | return ret; | 1958 | return ret; |
@@ -1220,17 +1964,3 @@ static int __init acpi_ibm_init(void) | |||
1220 | 1964 | ||
1221 | module_init(acpi_ibm_init); | 1965 | module_init(acpi_ibm_init); |
1222 | module_exit(acpi_ibm_exit); | 1966 | module_exit(acpi_ibm_exit); |
1223 | |||
1224 | MODULE_AUTHOR("Borislav Deianov"); | ||
1225 | MODULE_DESCRIPTION(IBM_DESC); | ||
1226 | MODULE_LICENSE("GPL"); | ||
1227 | |||
1228 | IBM_PARAM(hotkey); | ||
1229 | IBM_PARAM(bluetooth); | ||
1230 | IBM_PARAM(video); | ||
1231 | IBM_PARAM(light); | ||
1232 | IBM_PARAM(dock); | ||
1233 | IBM_PARAM(bay); | ||
1234 | IBM_PARAM(cmos); | ||
1235 | IBM_PARAM(led); | ||
1236 | IBM_PARAM(beep); | ||