aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2007-03-23 16:33:57 -0400
committerLen Brown <len.brown@intel.com>2007-03-25 23:37:54 -0400
commit56b6aeb05890f219895197f5166637b3d7a6f679 (patch)
tree7c35d878a87192f0cb9b9cce3909d228542de6c1 /drivers/acpi
parent1406cdd1760743106278c1f02a0f445159c8f400 (diff)
ACPI: ibm-acpi: organize code
Shuffle code around to better organize the driver code inside the ibm-acpi.c file. This patch adds no functional changes. It is pure fluff that will make me a bit more productive. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/ibm_acpi.c1398
1 files changed, 757 insertions, 641 deletions
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index e2da95498f32..984ec81bd234 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -87,8 +87,17 @@ MODULE_LICENSE("GPL");
87 87
88#define __unused __attribute__ ((unused)) 88#define __unused __attribute__ ((unused))
89 89
90static int experimental; 90/****************************************************************************
91module_param(experimental, int, 0); 91 ****************************************************************************
92 *
93 * ACPI Helpers and device model
94 *
95 ****************************************************************************
96 ****************************************************************************/
97
98/*************************************************************************
99 * ACPI basic handles
100 */
92 101
93static acpi_handle root_handle = NULL; 102static acpi_handle root_handle = NULL;
94 103
@@ -105,183 +114,31 @@ IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
105 "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ 114 "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */
106 "\\_SB.PCI0.ICH3.EC0", /* R31 */ 115 "\\_SB.PCI0.ICH3.EC0", /* R31 */
107 "\\_SB.PCI0.LPC.EC", /* all others */ 116 "\\_SB.PCI0.LPC.EC", /* all others */
108 ); 117 );
109 118
110IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ 119IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
111 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ 120IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
112 "\\_SB.PCI0.VID0", /* 770e */
113 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
114 "\\_SB.PCI0.AGP.VID", /* all others */
115 ); /* R30, R31 */
116 121
117IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ 122
123/*************************************************************************
124 * Misc ACPI handles
125 */
118 126
119IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ 127IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
120 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ 128 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
121 "\\CMS", /* R40, R40e */ 129 "\\CMS", /* R40, R40e */
122 ); /* all others */ 130 ); /* all others */
123#ifdef CONFIG_ACPI_IBM_DOCK
124IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
125 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
126 "\\_SB.PCI0.PCI1.DOCK", /* all others */
127 "\\_SB.PCI.ISA.SLCE", /* 570 */
128 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
129#endif
130#ifdef CONFIG_ACPI_IBM_BAY
131IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
132 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
133 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
134 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
135 ); /* A21e, R30, R31 */
136
137IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
138 "_EJ0", /* all others */
139 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
140
141IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
142 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
143 ); /* all others */
144
145IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
146 "_EJ0", /* 770x */
147 ); /* all others */
148#endif /* CONFIG_ACPI_IBM_BAY */
149
150/* don't list other alternatives as we install a notify handler on the 570 */
151IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
152 131
153IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ 132IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
154 "^HKEY", /* R30, R31 */ 133 "^HKEY", /* R30, R31 */
155 "HKEY", /* all others */ 134 "HKEY", /* all others */
156 ); /* 570 */ 135 ); /* 570 */
157 136
158IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
159IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
160 137
161IBM_HANDLE(led, ec, "SLED", /* 570 */ 138/*************************************************************************
162 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ 139 * ACPI helpers
163 "LED", /* all others */
164 ); /* R30, R31 */
165
166IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
167IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
168IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
169IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
170
171IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
172 "\\FSPD", /* 600e/x, 770e, 770x */
173 ); /* all others */
174
175IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
176 "JFNS", /* 770x-JL */
177 ); /* all others */
178
179/*
180 * FAN ACCESS MODES
181 *
182 * IBMACPI_FAN_RD_ACPI_GFAN:
183 * ACPI GFAN method: returns fan level
184 *
185 * see IBMACPI_FAN_WR_ACPI_SFAN
186 * EC 0x2f not available if GFAN exists
187 *
188 * IBMACPI_FAN_WR_ACPI_SFAN:
189 * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
190 *
191 * EC 0x2f might be available *for reading*, but never for writing.
192 *
193 * IBMACPI_FAN_WR_TPEC:
194 * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
195 * on almost all ThinkPads
196 *
197 * Fan speed changes of any sort (including those caused by the
198 * disengaged mode) are usually done slowly by the firmware as the
199 * maximum ammount of fan duty cycle change per second seems to be
200 * limited.
201 *
202 * Reading is not available if GFAN exists.
203 * Writing is not available if SFAN exists.
204 *
205 * Bits
206 * 7 automatic mode engaged;
207 * (default operation mode of the ThinkPad)
208 * fan level is ignored in this mode.
209 * 6 disengage mode (takes precedence over bit 7);
210 * not available on all thinkpads. May disable
211 * the tachometer, and speeds up fan to 100% duty-cycle,
212 * which speeds it up far above the standard RPM
213 * levels. It is not impossible that it could cause
214 * hardware damage.
215 * 5-3 unused in some models. Extra bits for fan level
216 * in others, but still useless as all values above
217 * 7 map to the same speed as level 7 in these models.
218 * 2-0 fan level (0..7 usually)
219 * 0x00 = stop
220 * 0x07 = max (set when temperatures critical)
221 * Some ThinkPads may have other levels, see
222 * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
223 *
224 * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
225 * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
226 * does so, its initial value is meaningless (0x07).
227 *
228 * For firmware bugs, refer to:
229 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
230 *
231 * ----
232 *
233 * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
234 * Main fan tachometer reading (in RPM)
235 *
236 * This register is present on all ThinkPads with a new-style EC, and
237 * it is known not to be present on the A21m/e, and T22, as there is
238 * something else in offset 0x84 according to the ACPI DSDT. Other
239 * ThinkPads from this same time period (and earlier) probably lack the
240 * tachometer as well.
241 *
242 * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
243 * was never fixed by IBM to report the EC firmware version string
244 * probably support the tachometer (like the early X models), so
245 * detecting it is quite hard. We need more data to know for sure.
246 *
247 * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
248 * might result.
249 *
250 * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
251 * register is not invalidated in ThinkPads that disable tachometer
252 * readings. Thus, the tachometer readings go stale.
253 *
254 * For firmware bugs, refer to:
255 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
256 *
257 * IBMACPI_FAN_WR_ACPI_FANS:
258 * ThinkPad X31, X40, X41. Not available in the X60.
259 *
260 * FANS ACPI handle: takes three arguments: low speed, medium speed,
261 * high speed. ACPI DSDT seems to map these three speeds to levels
262 * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
263 * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
264 *
265 * The speeds are stored on handles
266 * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
267 *
268 * There are three default speed sets, acessible as handles:
269 * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
270 *
271 * ACPI DSDT switches which set is in use depending on various
272 * factors.
273 *
274 * IBMACPI_FAN_WR_TPEC is also available and should be used to
275 * command the fan. The X31/X40/X41 seems to have 8 fan levels,
276 * but the ACPI tables just mention level 7.
277 */ 140 */
278 141
279static char *ibm_thinkpad_ec_found = NULL;
280
281static struct proc_dir_entry *proc_dir = NULL;
282
283static struct backlight_device *ibm_backlight_device = NULL;
284
285static int acpi_evalf(acpi_handle handle, 142static int acpi_evalf(acpi_handle handle,
286 void *res, char *method, char *fmt, ...) 143 void *res, char *method, char *fmt, ...)
287{ 144{
@@ -371,6 +228,203 @@ static void __unused acpi_print_int(acpi_handle handle, char *method)
371 printk(IBM_ERR "error calling %s\n", method); 228 printk(IBM_ERR "error calling %s\n", method);
372} 229}
373 230
231static int acpi_ec_read(int i, u8 * p)
232{
233 int v;
234
235 if (ecrd_handle) {
236 if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
237 return 0;
238 *p = v;
239 } else {
240 if (ec_read(i, p) < 0)
241 return 0;
242 }
243
244 return 1;
245}
246
247static int acpi_ec_write(int i, u8 v)
248{
249 if (ecwr_handle) {
250 if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
251 return 0;
252 } else {
253 if (ec_write(i, v) < 0)
254 return 0;
255 }
256
257 return 1;
258}
259
260static int _sta(acpi_handle handle)
261{
262 int status;
263
264 if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
265 status = 0;
266
267 return status;
268}
269
270/*************************************************************************
271 * ACPI device model
272 */
273
274static void __init ibm_handle_init(char *name,
275 acpi_handle * handle, acpi_handle parent,
276 char **paths, int num_paths, char **path)
277{
278 int i;
279 acpi_status status;
280
281 for (i = 0; i < num_paths; i++) {
282 status = acpi_get_handle(parent, paths[i], handle);
283 if (ACPI_SUCCESS(status)) {
284 *path = paths[i];
285 return;
286 }
287 }
288
289 *handle = NULL;
290}
291
292static void dispatch_notify(acpi_handle handle, u32 event, void *data)
293{
294 struct ibm_struct *ibm = data;
295
296 if (!ibm || !ibm->notify)
297 return;
298
299 ibm->notify(ibm, event);
300}
301
302static int __init setup_notify(struct ibm_struct *ibm)
303{
304 acpi_status status;
305 int ret;
306
307 if (!*ibm->handle)
308 return 0;
309
310 ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
311 if (ret < 0) {
312 printk(IBM_ERR "%s device not present\n", ibm->name);
313 return -ENODEV;
314 }
315
316 acpi_driver_data(ibm->device) = ibm;
317 sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
318
319 status = acpi_install_notify_handler(*ibm->handle, ibm->type,
320 dispatch_notify, ibm);
321 if (ACPI_FAILURE(status)) {
322 if (status == AE_ALREADY_EXISTS) {
323 printk(IBM_NOTICE "another device driver is already handling %s events\n",
324 ibm->name);
325 } else {
326 printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
327 ibm->name, status);
328 }
329 return -ENODEV;
330 }
331 ibm->notify_installed = 1;
332 return 0;
333}
334
335static int __init ibm_device_add(struct acpi_device *device)
336{
337 return 0;
338}
339
340static int __init register_ibmacpi_subdriver(struct ibm_struct *ibm)
341{
342 int ret;
343
344 ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
345 if (!ibm->driver) {
346 printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
347 return -1;
348 }
349
350 sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
351 ibm->driver->ids = ibm->hid;
352 ibm->driver->ops.add = &ibm_device_add;
353
354 ret = acpi_bus_register_driver(ibm->driver);
355 if (ret < 0) {
356 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
357 ibm->hid, ret);
358 kfree(ibm->driver);
359 }
360
361 return ret;
362}
363
364
365/****************************************************************************
366 ****************************************************************************
367 *
368 * Procfs Helpers
369 *
370 ****************************************************************************
371 ****************************************************************************/
372
373static int dispatch_read(char *page, char **start, off_t off, int count,
374 int *eof, void *data)
375{
376 struct ibm_struct *ibm = data;
377 int len;
378
379 if (!ibm || !ibm->read)
380 return -EINVAL;
381
382 len = ibm->read(page);
383 if (len < 0)
384 return len;
385
386 if (len <= off + count)
387 *eof = 1;
388 *start = page + off;
389 len -= off;
390 if (len > count)
391 len = count;
392 if (len < 0)
393 len = 0;
394
395 return len;
396}
397
398static int dispatch_write(struct file *file, const char __user * userbuf,
399 unsigned long count, void *data)
400{
401 struct ibm_struct *ibm = data;
402 char *kernbuf;
403 int ret;
404
405 if (!ibm || !ibm->write)
406 return -EINVAL;
407
408 kernbuf = kmalloc(count + 2, GFP_KERNEL);
409 if (!kernbuf)
410 return -ENOMEM;
411
412 if (copy_from_user(kernbuf, userbuf, count)) {
413 kfree(kernbuf);
414 return -EFAULT;
415 }
416
417 kernbuf[count] = 0;
418 strcat(kernbuf, ",");
419 ret = ibm->write(kernbuf);
420 if (ret == 0)
421 ret = count;
422
423 kfree(kernbuf);
424
425 return ret;
426}
427
374static char *next_cmd(char **cmds) 428static char *next_cmd(char **cmds)
375{ 429{
376 char *start = *cmds; 430 char *start = *cmds;
@@ -387,6 +441,19 @@ static char *next_cmd(char **cmds)
387 return start; 441 return start;
388} 442}
389 443
444
445/****************************************************************************
446 ****************************************************************************
447 *
448 * Subdrivers
449 *
450 ****************************************************************************
451 ****************************************************************************/
452
453/*************************************************************************
454 * ibm-acpi init subdriver
455 */
456
390static int ibm_acpi_driver_init(void) 457static int ibm_acpi_driver_init(void)
391{ 458{
392 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); 459 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
@@ -409,11 +476,51 @@ static int ibm_acpi_driver_read(char *p)
409 return len; 476 return len;
410} 477}
411 478
479/*************************************************************************
480 * Hotkey subdriver
481 */
482
412static int hotkey_supported; 483static int hotkey_supported;
413static int hotkey_mask_supported; 484static int hotkey_mask_supported;
414static int hotkey_orig_status; 485static int hotkey_orig_status;
415static int hotkey_orig_mask; 486static int hotkey_orig_mask;
416 487
488static int hotkey_init(void)
489{
490 /* hotkey not supported on 570 */
491 hotkey_supported = hkey_handle != NULL;
492
493 if (hotkey_supported) {
494 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
495 A30, R30, R31, T20-22, X20-21, X22-24 */
496 hotkey_mask_supported =
497 acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
498
499 if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
500 return -ENODEV;
501 }
502
503 return 0;
504}
505
506static void hotkey_exit(void)
507{
508 if (hotkey_supported)
509 hotkey_set(hotkey_orig_status, hotkey_orig_mask);
510}
511
512static void hotkey_notify(struct ibm_struct *ibm, u32 event)
513{
514 int hkey;
515
516 if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
517 acpi_bus_generate_event(ibm->device, event, hkey);
518 else {
519 printk(IBM_ERR "unknown hotkey event %d\n", event);
520 acpi_bus_generate_event(ibm->device, event, 0);
521 }
522}
523
417static int hotkey_get(int *status, int *mask) 524static int hotkey_get(int *status, int *mask)
418{ 525{
419 if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) 526 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
@@ -444,24 +551,6 @@ static int hotkey_set(int status, int mask)
444 return 1; 551 return 1;
445} 552}
446 553
447static int hotkey_init(void)
448{
449 /* hotkey not supported on 570 */
450 hotkey_supported = hkey_handle != NULL;
451
452 if (hotkey_supported) {
453 /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
454 A30, R30, R31, T20-22, X20-21, X22-24 */
455 hotkey_mask_supported =
456 acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
457
458 if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
459 return -ENODEV;
460 }
461
462 return 0;
463}
464
465static int hotkey_read(char *p) 554static int hotkey_read(char *p)
466{ 555{
467 int status, mask; 556 int status, mask;
@@ -523,23 +612,9 @@ static int hotkey_write(char *buf)
523 return 0; 612 return 0;
524} 613}
525 614
526static void hotkey_exit(void) 615/*************************************************************************
527{ 616 * Bluetooth subdriver
528 if (hotkey_supported) 617 */
529 hotkey_set(hotkey_orig_status, hotkey_orig_mask);
530}
531
532static void hotkey_notify(struct ibm_struct *ibm, u32 event)
533{
534 int hkey;
535
536 if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
537 acpi_bus_generate_event(ibm->device, event, hkey);
538 else {
539 printk(IBM_ERR "unknown hotkey event %d\n", event);
540 acpi_bus_generate_event(ibm->device, event, 0);
541 }
542}
543 618
544static int bluetooth_supported; 619static int bluetooth_supported;
545 620
@@ -606,6 +681,10 @@ static int bluetooth_write(char *buf)
606 return 0; 681 return 0;
607} 682}
608 683
684/*************************************************************************
685 * Wan subdriver
686 */
687
609static int wan_supported; 688static int wan_supported;
610 689
611static int wan_init(void) 690static int wan_init(void)
@@ -668,9 +747,22 @@ static int wan_write(char *buf)
668 return 0; 747 return 0;
669} 748}
670 749
750/*************************************************************************
751 * Video subdriver
752 */
753
671static enum video_access_mode video_supported; 754static enum video_access_mode video_supported;
672static int video_orig_autosw; 755static int video_orig_autosw;
673 756
757IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
758 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
759 "\\_SB.PCI0.VID0", /* 770e */
760 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
761 "\\_SB.PCI0.AGP.VID", /* all others */
762 ); /* R30, R31 */
763
764IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
765
674static int video_init(void) 766static int video_init(void)
675{ 767{
676 int ivga; 768 int ivga;
@@ -695,6 +787,11 @@ static int video_init(void)
695 return 0; 787 return 0;
696} 788}
697 789
790static void video_exit(void)
791{
792 acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
793}
794
698static int video_status(void) 795static int video_status(void)
699{ 796{
700 int status = 0; 797 int status = 0;
@@ -736,33 +833,6 @@ static int video_autosw(void)
736 return autosw & 1; 833 return autosw & 1;
737} 834}
738 835
739static int video_read(char *p)
740{
741 int status = video_status();
742 int autosw = video_autosw();
743 int len = 0;
744
745 if (!video_supported) {
746 len += sprintf(p + len, "status:\t\tnot supported\n");
747 return len;
748 }
749
750 len += sprintf(p + len, "status:\t\tsupported\n");
751 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
752 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
753 if (video_supported == IBMACPI_VIDEO_NEW)
754 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
755 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
756 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
757 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
758 if (video_supported == IBMACPI_VIDEO_NEW)
759 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
760 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
761 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
762
763 return len;
764}
765
766static int video_switch(void) 836static int video_switch(void)
767{ 837{
768 int autosw = video_autosw(); 838 int autosw = video_autosw();
@@ -812,6 +882,33 @@ static int video_switch2(int status)
812 return ret; 882 return ret;
813} 883}
814 884
885static int video_read(char *p)
886{
887 int status = video_status();
888 int autosw = video_autosw();
889 int len = 0;
890
891 if (!video_supported) {
892 len += sprintf(p + len, "status:\t\tnot supported\n");
893 return len;
894 }
895
896 len += sprintf(p + len, "status:\t\tsupported\n");
897 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
898 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
899 if (video_supported == IBMACPI_VIDEO_NEW)
900 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
901 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
902 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
903 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
904 if (video_supported == IBMACPI_VIDEO_NEW)
905 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
906 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
907 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
908
909 return len;
910}
911
815static int video_write(char *buf) 912static int video_write(char *buf)
816{ 913{
817 char *cmd; 914 char *cmd;
@@ -862,14 +959,16 @@ static int video_write(char *buf)
862 return 0; 959 return 0;
863} 960}
864 961
865static void video_exit(void) 962/*************************************************************************
866{ 963 * Light (thinklight) subdriver
867 acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw); 964 */
868}
869 965
870static int light_supported; 966static int light_supported;
871static int light_status_supported; 967static int light_status_supported;
872 968
969IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
970IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
971
873static int light_init(void) 972static int light_init(void)
874{ 973{
875 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ 974 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
@@ -933,21 +1032,45 @@ static int light_write(char *buf)
933 return 0; 1032 return 0;
934} 1033}
935 1034
936#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY) 1035/*************************************************************************
937static int _sta(acpi_handle handle) 1036 * Dock subdriver
938{ 1037 */
939 int status;
940
941 if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
942 status = 0;
943 1038
944 return status; 1039/* don't list other alternatives as we install a notify handler on the 570 */
945} 1040IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
946#endif
947 1041
948#ifdef CONFIG_ACPI_IBM_DOCK 1042#ifdef CONFIG_ACPI_IBM_DOCK
1043
1044IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
1045 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
1046 "\\_SB.PCI0.PCI1.DOCK", /* all others */
1047 "\\_SB.PCI.ISA.SLCE", /* 570 */
1048 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
1049
949#define dock_docked() (_sta(dock_handle) & 1) 1050#define dock_docked() (_sta(dock_handle) & 1)
950 1051
1052static void dock_notify(struct ibm_struct *ibm, u32 event)
1053{
1054 int docked = dock_docked();
1055 int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
1056
1057 if (event == 1 && !pci) /* 570 */
1058 acpi_bus_generate_event(ibm->device, event, 1); /* button */
1059 else if (event == 1 && pci) /* 570 */
1060 acpi_bus_generate_event(ibm->device, event, 3); /* dock */
1061 else if (event == 3 && docked)
1062 acpi_bus_generate_event(ibm->device, event, 1); /* button */
1063 else if (event == 3 && !docked)
1064 acpi_bus_generate_event(ibm->device, event, 2); /* undock */
1065 else if (event == 0 && docked)
1066 acpi_bus_generate_event(ibm->device, event, 3); /* dock */
1067 else {
1068 printk(IBM_ERR "unknown dock event %d, status %d\n",
1069 event, _sta(dock_handle));
1070 acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
1071 }
1072}
1073
951static int dock_read(char *p) 1074static int dock_read(char *p)
952{ 1075{
953 int len = 0; 1076 int len = 0;
@@ -987,28 +1110,11 @@ static int dock_write(char *buf)
987 return 0; 1110 return 0;
988} 1111}
989 1112
990static void dock_notify(struct ibm_struct *ibm, u32 event) 1113#endif /* CONFIG_ACPI_IBM_DOCK */
991{
992 int docked = dock_docked();
993 int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
994 1114
995 if (event == 1 && !pci) /* 570 */ 1115/*************************************************************************
996 acpi_bus_generate_event(ibm->device, event, 1); /* button */ 1116 * Bay subdriver
997 else if (event == 1 && pci) /* 570 */ 1117 */
998 acpi_bus_generate_event(ibm->device, event, 3); /* dock */
999 else if (event == 3 && docked)
1000 acpi_bus_generate_event(ibm->device, event, 1); /* button */
1001 else if (event == 3 && !docked)
1002 acpi_bus_generate_event(ibm->device, event, 2); /* undock */
1003 else if (event == 0 && docked)
1004 acpi_bus_generate_event(ibm->device, event, 3); /* dock */
1005 else {
1006 printk(IBM_ERR "unknown dock event %d, status %d\n",
1007 event, _sta(dock_handle));
1008 acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
1009 }
1010}
1011#endif
1012 1118
1013#ifdef CONFIG_ACPI_IBM_BAY 1119#ifdef CONFIG_ACPI_IBM_BAY
1014static int bay_status_supported; 1120static int bay_status_supported;
@@ -1016,6 +1122,21 @@ static int bay_status2_supported;
1016static int bay_eject_supported; 1122static int bay_eject_supported;
1017static int bay_eject2_supported; 1123static int bay_eject2_supported;
1018 1124
1125IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
1126 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
1127 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
1128 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
1129 ); /* A21e, R30, R31 */
1130IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
1131 "_EJ0", /* all others */
1132 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
1133IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
1134 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
1135 ); /* all others */
1136IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
1137 "_EJ0", /* 770x */
1138 ); /* all others */
1139
1019static int bay_init(void) 1140static int bay_init(void)
1020{ 1141{
1021 bay_status_supported = bay_handle && 1142 bay_status_supported = bay_handle &&
@@ -1031,6 +1152,11 @@ static int bay_init(void)
1031 return 0; 1152 return 0;
1032} 1153}
1033 1154
1155static void bay_notify(struct ibm_struct *ibm, u32 event)
1156{
1157 acpi_bus_generate_event(ibm->device, event, 0);
1158}
1159
1034#define bay_occupied(b) (_sta(b##_handle) & 1) 1160#define bay_occupied(b) (_sta(b##_handle) & 1)
1035 1161
1036static int bay_read(char *p) 1162static int bay_read(char *p)
@@ -1081,12 +1207,19 @@ static int bay_write(char *buf)
1081 1207
1082 return 0; 1208 return 0;
1083} 1209}
1210#endif /* CONFIG_ACPI_IBM_BAY */
1084 1211
1085static void bay_notify(struct ibm_struct *ibm, u32 event) 1212/*************************************************************************
1213 * CMOS subdriver
1214 */
1215
1216static int cmos_eval(int cmos_cmd)
1086{ 1217{
1087 acpi_bus_generate_event(ibm->device, event, 0); 1218 if (cmos_handle)
1219 return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
1220 else
1221 return 1;
1088} 1222}
1089#endif /* CONFIG_ACPI_IBM_BAY */
1090 1223
1091static int cmos_read(char *p) 1224static int cmos_read(char *p)
1092{ 1225{
@@ -1104,14 +1237,6 @@ static int cmos_read(char *p)
1104 return len; 1237 return len;
1105} 1238}
1106 1239
1107static int cmos_eval(int cmos_cmd)
1108{
1109 if (cmos_handle)
1110 return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
1111 else
1112 return 1;
1113}
1114
1115static int cmos_write(char *buf) 1240static int cmos_write(char *buf)
1116{ 1241{
1117 char *cmd; 1242 char *cmd;
@@ -1134,8 +1259,18 @@ static int cmos_write(char *buf)
1134 return 0; 1259 return 0;
1135} 1260}
1136 1261
1262
1263/*************************************************************************
1264 * LED subdriver
1265 */
1266
1137static enum led_access_mode led_supported; 1267static enum led_access_mode led_supported;
1138 1268
1269IBM_HANDLE(led, ec, "SLED", /* 570 */
1270 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
1271 "LED", /* all others */
1272 ); /* R30, R31 */
1273
1139static int led_init(void) 1274static int led_init(void)
1140{ 1275{
1141 if (!led_handle) 1276 if (!led_handle)
@@ -1242,6 +1377,12 @@ static int led_write(char *buf)
1242 return 0; 1377 return 0;
1243} 1378}
1244 1379
1380/*************************************************************************
1381 * Beep subdriver
1382 */
1383
1384IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
1385
1245static int beep_read(char *p) 1386static int beep_read(char *p)
1246{ 1387{
1247 int len = 0; 1388 int len = 0;
@@ -1277,34 +1418,9 @@ static int beep_write(char *buf)
1277 return 0; 1418 return 0;
1278} 1419}
1279 1420
1280static int acpi_ec_read(int i, u8 * p) 1421/*************************************************************************
1281{ 1422 * Thermal subdriver
1282 int v; 1423 */
1283
1284 if (ecrd_handle) {
1285 if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
1286 return 0;
1287 *p = v;
1288 } else {
1289 if (ec_read(i, p) < 0)
1290 return 0;
1291 }
1292
1293 return 1;
1294}
1295
1296static int acpi_ec_write(int i, u8 v)
1297{
1298 if (ecwr_handle) {
1299 if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
1300 return 0;
1301 } else {
1302 if (ec_write(i, v) < 0)
1303 return 0;
1304 }
1305
1306 return 1;
1307}
1308 1424
1309static enum thermal_access_mode thermal_read_mode; 1425static enum thermal_access_mode thermal_read_mode;
1310 1426
@@ -1446,6 +1562,10 @@ static int thermal_read(char *p)
1446 return len; 1562 return len;
1447} 1563}
1448 1564
1565/*************************************************************************
1566 * EC Dump subdriver
1567 */
1568
1449static u8 ecdump_regs[256]; 1569static u8 ecdump_regs[256];
1450 1570
1451static int ecdump_read(char *p) 1571static int ecdump_read(char *p)
@@ -1505,6 +1625,55 @@ static int ecdump_write(char *buf)
1505 return 0; 1625 return 0;
1506} 1626}
1507 1627
1628/*************************************************************************
1629 * Backlight/brightness subdriver
1630 */
1631
1632static struct backlight_device *ibm_backlight_device = NULL;
1633
1634static struct backlight_ops ibm_backlight_data = {
1635 .get_brightness = brightness_get,
1636 .update_status = brightness_update_status,
1637};
1638
1639static int brightness_init(void)
1640{
1641 int b;
1642
1643 b = brightness_get(NULL);
1644 if (b < 0)
1645 return b;
1646
1647 ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
1648 &ibm_backlight_data);
1649 if (IS_ERR(ibm_backlight_device)) {
1650 printk(IBM_ERR "Could not register backlight device\n");
1651 return PTR_ERR(ibm_backlight_device);
1652 }
1653
1654 ibm_backlight_device->props.max_brightness = 7;
1655 ibm_backlight_device->props.brightness = b;
1656 backlight_update_status(ibm_backlight_device);
1657
1658 return 0;
1659}
1660
1661static void brightness_exit(void)
1662{
1663 if (ibm_backlight_device) {
1664 backlight_device_unregister(ibm_backlight_device);
1665 ibm_backlight_device = NULL;
1666 }
1667}
1668
1669static int brightness_update_status(struct backlight_device *bd)
1670{
1671 return brightness_set(
1672 (bd->props.fb_blank == FB_BLANK_UNBLANK &&
1673 bd->props.power == FB_BLANK_UNBLANK) ?
1674 bd->props.brightness : 0);
1675}
1676
1508static int brightness_get(struct backlight_device *bd) 1677static int brightness_get(struct backlight_device *bd)
1509{ 1678{
1510 u8 level; 1679 u8 level;
@@ -1516,23 +1685,6 @@ static int brightness_get(struct backlight_device *bd)
1516 return level; 1685 return level;
1517} 1686}
1518 1687
1519static int brightness_read(char *p)
1520{
1521 int len = 0;
1522 int level;
1523
1524 if ((level = brightness_get(NULL)) < 0) {
1525 len += sprintf(p + len, "level:\t\tunreadable\n");
1526 } else {
1527 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
1528 len += sprintf(p + len, "commands:\tup, down\n");
1529 len += sprintf(p + len, "commands:\tlevel <level>"
1530 " (<level> is 0-7)\n");
1531 }
1532
1533 return len;
1534}
1535
1536static int brightness_set(int value) 1688static int brightness_set(int value)
1537{ 1689{
1538 int cmos_cmd, inc, i; 1690 int cmos_cmd, inc, i;
@@ -1540,8 +1692,7 @@ static int brightness_set(int value)
1540 1692
1541 value &= 7; 1693 value &= 7;
1542 1694
1543 cmos_cmd = value > current_value ? 1695 cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
1544 TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
1545 inc = value > current_value ? 1 : -1; 1696 inc = value > current_value ? 1 : -1;
1546 for (i = current_value; i != value; i += inc) { 1697 for (i = current_value; i != value; i += inc) {
1547 if (!cmos_eval(cmos_cmd)) 1698 if (!cmos_eval(cmos_cmd))
@@ -1553,6 +1704,23 @@ static int brightness_set(int value)
1553 return 0; 1704 return 0;
1554} 1705}
1555 1706
1707static int brightness_read(char *p)
1708{
1709 int len = 0;
1710 int level;
1711
1712 if ((level = brightness_get(NULL)) < 0) {
1713 len += sprintf(p + len, "level:\t\tunreadable\n");
1714 } else {
1715 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
1716 len += sprintf(p + len, "commands:\tup, down\n");
1717 len += sprintf(p + len, "commands:\tlevel <level>"
1718 " (<level> is 0-7)\n");
1719 }
1720
1721 return len;
1722}
1723
1556static int brightness_write(char *buf) 1724static int brightness_write(char *buf)
1557{ 1725{
1558 int level; 1726 int level;
@@ -1580,48 +1748,9 @@ static int brightness_write(char *buf)
1580 return 0; 1748 return 0;
1581} 1749}
1582 1750
1583static int brightness_update_status(struct backlight_device *bd) 1751/*************************************************************************
1584{ 1752 * Volume subdriver
1585 return brightness_set( 1753 */
1586 (bd->props.fb_blank == FB_BLANK_UNBLANK &&
1587 bd->props.power == FB_BLANK_UNBLANK) ?
1588 bd->props.brightness : 0);
1589}
1590
1591static struct backlight_ops ibm_backlight_data = {
1592 .get_brightness = brightness_get,
1593 .update_status = brightness_update_status,
1594};
1595
1596static int brightness_init(void)
1597{
1598 int b;
1599
1600 b = brightness_get(NULL);
1601 if (b < 0)
1602 return b;
1603
1604 ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
1605 &ibm_backlight_data);
1606 if (IS_ERR(ibm_backlight_device)) {
1607 printk(IBM_ERR "Could not register backlight device\n");
1608 return PTR_ERR(ibm_backlight_device);
1609 }
1610
1611 ibm_backlight_device->props.max_brightness = 7;
1612 ibm_backlight_device->props.brightness = b;
1613 backlight_update_status(ibm_backlight_device);
1614
1615 return 0;
1616}
1617
1618static void brightness_exit(void)
1619{
1620 if (ibm_backlight_device) {
1621 backlight_device_unregister(ibm_backlight_device);
1622 ibm_backlight_device = NULL;
1623 }
1624}
1625 1754
1626static int volume_read(char *p) 1755static int volume_read(char *p)
1627{ 1756{
@@ -1673,8 +1802,7 @@ static int volume_write(char *buf)
1673 return -EINVAL; 1802 return -EINVAL;
1674 1803
1675 if (new_level != level) { /* mute doesn't change */ 1804 if (new_level != level) { /* mute doesn't change */
1676 cmos_cmd = new_level > level ? 1805 cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
1677 TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
1678 inc = new_level > level ? 1 : -1; 1806 inc = new_level > level ? 1 : -1;
1679 1807
1680 if (mute && (!cmos_eval(cmos_cmd) || 1808 if (mute && (!cmos_eval(cmos_cmd) ||
@@ -1693,8 +1821,7 @@ static int volume_write(char *buf)
1693 } 1821 }
1694 1822
1695 if (new_mute != mute) { /* level doesn't change */ 1823 if (new_mute != mute) { /* level doesn't change */
1696 cmos_cmd = new_mute ? 1824 cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
1697 TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
1698 1825
1699 if (!cmos_eval(cmos_cmd) || 1826 if (!cmos_eval(cmos_cmd) ||
1700 !acpi_ec_write(volume_offset, level + new_mute)) 1827 !acpi_ec_write(volume_offset, level + new_mute))
@@ -1705,6 +1832,111 @@ static int volume_write(char *buf)
1705 return 0; 1832 return 0;
1706} 1833}
1707 1834
1835
1836/*************************************************************************
1837 * Fan subdriver
1838 */
1839
1840/*
1841 * FAN ACCESS MODES
1842 *
1843 * IBMACPI_FAN_RD_ACPI_GFAN:
1844 * ACPI GFAN method: returns fan level
1845 *
1846 * see IBMACPI_FAN_WR_ACPI_SFAN
1847 * EC 0x2f not available if GFAN exists
1848 *
1849 * IBMACPI_FAN_WR_ACPI_SFAN:
1850 * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
1851 *
1852 * EC 0x2f might be available *for reading*, but never for writing.
1853 *
1854 * IBMACPI_FAN_WR_TPEC:
1855 * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
1856 * on almost all ThinkPads
1857 *
1858 * Fan speed changes of any sort (including those caused by the
1859 * disengaged mode) are usually done slowly by the firmware as the
1860 * maximum ammount of fan duty cycle change per second seems to be
1861 * limited.
1862 *
1863 * Reading is not available if GFAN exists.
1864 * Writing is not available if SFAN exists.
1865 *
1866 * Bits
1867 * 7 automatic mode engaged;
1868 * (default operation mode of the ThinkPad)
1869 * fan level is ignored in this mode.
1870 * 6 disengage mode (takes precedence over bit 7);
1871 * not available on all thinkpads. May disable
1872 * the tachometer, and speeds up fan to 100% duty-cycle,
1873 * which speeds it up far above the standard RPM
1874 * levels. It is not impossible that it could cause
1875 * hardware damage.
1876 * 5-3 unused in some models. Extra bits for fan level
1877 * in others, but still useless as all values above
1878 * 7 map to the same speed as level 7 in these models.
1879 * 2-0 fan level (0..7 usually)
1880 * 0x00 = stop
1881 * 0x07 = max (set when temperatures critical)
1882 * Some ThinkPads may have other levels, see
1883 * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
1884 *
1885 * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
1886 * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
1887 * does so, its initial value is meaningless (0x07).
1888 *
1889 * For firmware bugs, refer to:
1890 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
1891 *
1892 * ----
1893 *
1894 * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
1895 * Main fan tachometer reading (in RPM)
1896 *
1897 * This register is present on all ThinkPads with a new-style EC, and
1898 * it is known not to be present on the A21m/e, and T22, as there is
1899 * something else in offset 0x84 according to the ACPI DSDT. Other
1900 * ThinkPads from this same time period (and earlier) probably lack the
1901 * tachometer as well.
1902 *
1903 * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
1904 * was never fixed by IBM to report the EC firmware version string
1905 * probably support the tachometer (like the early X models), so
1906 * detecting it is quite hard. We need more data to know for sure.
1907 *
1908 * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
1909 * might result.
1910 *
1911 * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
1912 * register is not invalidated in ThinkPads that disable tachometer
1913 * readings. Thus, the tachometer readings go stale.
1914 *
1915 * For firmware bugs, refer to:
1916 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
1917 *
1918 * IBMACPI_FAN_WR_ACPI_FANS:
1919 * ThinkPad X31, X40, X41. Not available in the X60.
1920 *
1921 * FANS ACPI handle: takes three arguments: low speed, medium speed,
1922 * high speed. ACPI DSDT seems to map these three speeds to levels
1923 * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
1924 * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
1925 *
1926 * The speeds are stored on handles
1927 * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
1928 *
1929 * There are three default speed sets, acessible as handles:
1930 * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
1931 *
1932 * ACPI DSDT switches which set is in use depending on various
1933 * factors.
1934 *
1935 * IBMACPI_FAN_WR_TPEC is also available and should be used to
1936 * command the fan. The X31/X40/X41 seems to have 8 fan levels,
1937 * but the ACPI tables just mention level 7.
1938 */
1939
1708static enum fan_status_access_mode fan_status_access_mode; 1940static enum fan_status_access_mode fan_status_access_mode;
1709static enum fan_control_access_mode fan_control_access_mode; 1941static enum fan_control_access_mode fan_control_access_mode;
1710static enum fan_control_commands fan_control_commands; 1942static enum fan_control_commands fan_control_commands;
@@ -1716,6 +1948,14 @@ static void fan_watchdog_fire(struct work_struct *ignored);
1716static int fan_watchdog_maxinterval; 1948static int fan_watchdog_maxinterval;
1717static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); 1949static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
1718 1950
1951IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
1952IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
1953 "\\FSPD", /* 600e/x, 770e, 770x */
1954 ); /* all others */
1955IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
1956 "JFNS", /* 770x-JL */
1957 ); /* all others */
1958
1719static int fan_init(void) 1959static int fan_init(void)
1720{ 1960{
1721 fan_status_access_mode = IBMACPI_FAN_NONE; 1961 fan_status_access_mode = IBMACPI_FAN_NONE;
@@ -1831,6 +2071,12 @@ static int fan_get_status(u8 *status)
1831 return 0; 2071 return 0;
1832} 2072}
1833 2073
2074static void fan_exit(void)
2075{
2076 cancel_delayed_work(&fan_watchdog_task);
2077 flush_scheduled_work();
2078}
2079
1834static int fan_get_speed(unsigned int *speed) 2080static int fan_get_speed(unsigned int *speed)
1835{ 2081{
1836 u8 hi, lo; 2082 u8 hi, lo;
@@ -1854,10 +2100,14 @@ static int fan_get_speed(unsigned int *speed)
1854 return 0; 2100 return 0;
1855} 2101}
1856 2102
1857static void fan_exit(void) 2103static void fan_watchdog_fire(struct work_struct *ignored)
1858{ 2104{
1859 cancel_delayed_work(&fan_watchdog_task); 2105 printk(IBM_NOTICE "fan watchdog: enabling fan\n");
1860 flush_scheduled_work(); 2106 if (fan_set_enable()) {
2107 printk(IBM_ERR "fan watchdog: error while enabling fan\n");
2108 /* reschedule for later */
2109 fan_watchdog_reset();
2110 }
1861} 2111}
1862 2112
1863static void fan_watchdog_reset(void) 2113static void fan_watchdog_reset(void)
@@ -1879,90 +2129,6 @@ static void fan_watchdog_reset(void)
1879 fan_watchdog_active = 0; 2129 fan_watchdog_active = 0;
1880} 2130}
1881 2131
1882static int fan_read(char *p)
1883{
1884 int len = 0;
1885 int rc;
1886 u8 status;
1887 unsigned int speed = 0;
1888
1889 switch (fan_status_access_mode) {
1890 case IBMACPI_FAN_RD_ACPI_GFAN:
1891 /* 570, 600e/x, 770e, 770x */
1892 if ((rc = fan_get_status(&status)) < 0)
1893 return rc;
1894
1895 len += sprintf(p + len, "status:\t\t%s\n"
1896 "level:\t\t%d\n",
1897 (status != 0) ? "enabled" : "disabled", status);
1898 break;
1899
1900 case IBMACPI_FAN_RD_TPEC:
1901 /* all except 570, 600e/x, 770e, 770x */
1902 if ((rc = fan_get_status(&status)) < 0)
1903 return rc;
1904
1905 if (unlikely(!fan_control_status_known)) {
1906 if (status != fan_control_initial_status)
1907 fan_control_status_known = 1;
1908 else
1909 /* Return most likely status. In fact, it
1910 * might be the only possible status */
1911 status = IBMACPI_FAN_EC_AUTO;
1912 }
1913
1914 len += sprintf(p + len, "status:\t\t%s\n",
1915 (status != 0) ? "enabled" : "disabled");
1916
1917 /* No ThinkPad boots on disengaged mode, we can safely
1918 * assume the tachometer is online if fan control status
1919 * was unknown */
1920 if ((rc = fan_get_speed(&speed)) < 0)
1921 return rc;
1922
1923 len += sprintf(p + len, "speed:\t\t%d\n", speed);
1924
1925 if (status & IBMACPI_FAN_EC_DISENGAGED)
1926 /* Disengaged mode takes precedence */
1927 len += sprintf(p + len, "level:\t\tdisengaged\n");
1928 else if (status & IBMACPI_FAN_EC_AUTO)
1929 len += sprintf(p + len, "level:\t\tauto\n");
1930 else
1931 len += sprintf(p + len, "level:\t\t%d\n", status);
1932 break;
1933
1934 case IBMACPI_FAN_NONE:
1935 default:
1936 len += sprintf(p + len, "status:\t\tnot supported\n");
1937 }
1938
1939 if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
1940 len += sprintf(p + len, "commands:\tlevel <level>");
1941
1942 switch (fan_control_access_mode) {
1943 case IBMACPI_FAN_WR_ACPI_SFAN:
1944 len += sprintf(p + len, " (<level> is 0-7)\n");
1945 break;
1946
1947 default:
1948 len += sprintf(p + len, " (<level> is 0-7, "
1949 "auto, disengaged)\n");
1950 break;
1951 }
1952 }
1953
1954 if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
1955 len += sprintf(p + len, "commands:\tenable, disable\n"
1956 "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
1957 "1-120 (seconds))\n");
1958
1959 if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
1960 len += sprintf(p + len, "commands:\tspeed <speed>"
1961 " (<speed> is 0-65535)\n");
1962
1963 return len;
1964}
1965
1966static int fan_set_level(int level) 2132static int fan_set_level(int level)
1967{ 2133{
1968 switch (fan_control_access_mode) { 2134 switch (fan_control_access_mode) {
@@ -2074,6 +2240,90 @@ static int fan_set_speed(int speed)
2074 return 0; 2240 return 0;
2075} 2241}
2076 2242
2243static int fan_read(char *p)
2244{
2245 int len = 0;
2246 int rc;
2247 u8 status;
2248 unsigned int speed = 0;
2249
2250 switch (fan_status_access_mode) {
2251 case IBMACPI_FAN_RD_ACPI_GFAN:
2252 /* 570, 600e/x, 770e, 770x */
2253 if ((rc = fan_get_status(&status)) < 0)
2254 return rc;
2255
2256 len += sprintf(p + len, "status:\t\t%s\n"
2257 "level:\t\t%d\n",
2258 (status != 0) ? "enabled" : "disabled", status);
2259 break;
2260
2261 case IBMACPI_FAN_RD_TPEC:
2262 /* all except 570, 600e/x, 770e, 770x */
2263 if ((rc = fan_get_status(&status)) < 0)
2264 return rc;
2265
2266 if (unlikely(!fan_control_status_known)) {
2267 if (status != fan_control_initial_status)
2268 fan_control_status_known = 1;
2269 else
2270 /* Return most likely status. In fact, it
2271 * might be the only possible status */
2272 status = IBMACPI_FAN_EC_AUTO;
2273 }
2274
2275 len += sprintf(p + len, "status:\t\t%s\n",
2276 (status != 0) ? "enabled" : "disabled");
2277
2278 /* No ThinkPad boots on disengaged mode, we can safely
2279 * assume the tachometer is online if fan control status
2280 * was unknown */
2281 if ((rc = fan_get_speed(&speed)) < 0)
2282 return rc;
2283
2284 len += sprintf(p + len, "speed:\t\t%d\n", speed);
2285
2286 if (status & IBMACPI_FAN_EC_DISENGAGED)
2287 /* Disengaged mode takes precedence */
2288 len += sprintf(p + len, "level:\t\tdisengaged\n");
2289 else if (status & IBMACPI_FAN_EC_AUTO)
2290 len += sprintf(p + len, "level:\t\tauto\n");
2291 else
2292 len += sprintf(p + len, "level:\t\t%d\n", status);
2293 break;
2294
2295 case IBMACPI_FAN_NONE:
2296 default:
2297 len += sprintf(p + len, "status:\t\tnot supported\n");
2298 }
2299
2300 if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
2301 len += sprintf(p + len, "commands:\tlevel <level>");
2302
2303 switch (fan_control_access_mode) {
2304 case IBMACPI_FAN_WR_ACPI_SFAN:
2305 len += sprintf(p + len, " (<level> is 0-7)\n");
2306 break;
2307
2308 default:
2309 len += sprintf(p + len, " (<level> is 0-7, "
2310 "auto, disengaged)\n");
2311 break;
2312 }
2313 }
2314
2315 if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
2316 len += sprintf(p + len, "commands:\tenable, disable\n"
2317 "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
2318 "1-120 (seconds))\n");
2319
2320 if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
2321 len += sprintf(p + len, "commands:\tspeed <speed>"
2322 " (<speed> is 0-65535)\n");
2323
2324 return len;
2325}
2326
2077static int fan_write_cmd_level(const char *cmd, int *rc) 2327static int fan_write_cmd_level(const char *cmd, int *rc)
2078{ 2328{
2079 int level; 2329 int level;
@@ -2171,16 +2421,18 @@ static int fan_write(char *buf)
2171 return rc; 2421 return rc;
2172} 2422}
2173 2423
2174static void fan_watchdog_fire(struct work_struct *ignored) 2424/****************************************************************************
2175{ 2425 ****************************************************************************
2176 printk(IBM_NOTICE "fan watchdog: enabling fan\n"); 2426 *
2177 if (fan_set_enable()) { 2427 * Infrastructure
2178 printk(IBM_ERR "fan watchdog: error while enabling fan\n"); 2428 *
2179 /* reschedule for later */ 2429 ****************************************************************************
2180 fan_watchdog_reset(); 2430 ****************************************************************************/
2181 } 2431
2182} 2432/* /proc support */
2433static struct proc_dir_entry *proc_dir = NULL;
2183 2434
2435/* Subdriver registry */
2184static struct ibm_struct ibms[] = { 2436static struct ibm_struct ibms[] = {
2185 { 2437 {
2186 .name = "driver", 2438 .name = "driver",
@@ -2301,132 +2553,9 @@ static struct ibm_struct ibms[] = {
2301 }, 2553 },
2302}; 2554};
2303 2555
2304static int dispatch_read(char *page, char **start, off_t off, int count, 2556/*
2305 int *eof, void *data) 2557 * Module and infrastructure proble, init and exit handling
2306{ 2558 */
2307 struct ibm_struct *ibm = data;
2308 int len;
2309
2310 if (!ibm || !ibm->read)
2311 return -EINVAL;
2312
2313 len = ibm->read(page);
2314 if (len < 0)
2315 return len;
2316
2317 if (len <= off + count)
2318 *eof = 1;
2319 *start = page + off;
2320 len -= off;
2321 if (len > count)
2322 len = count;
2323 if (len < 0)
2324 len = 0;
2325
2326 return len;
2327}
2328
2329static int dispatch_write(struct file *file, const char __user * userbuf,
2330 unsigned long count, void *data)
2331{
2332 struct ibm_struct *ibm = data;
2333 char *kernbuf;
2334 int ret;
2335
2336 if (!ibm || !ibm->write)
2337 return -EINVAL;
2338
2339 kernbuf = kmalloc(count + 2, GFP_KERNEL);
2340 if (!kernbuf)
2341 return -ENOMEM;
2342
2343 if (copy_from_user(kernbuf, userbuf, count)) {
2344 kfree(kernbuf);
2345 return -EFAULT;
2346 }
2347
2348 kernbuf[count] = 0;
2349 strcat(kernbuf, ",");
2350 ret = ibm->write(kernbuf);
2351 if (ret == 0)
2352 ret = count;
2353
2354 kfree(kernbuf);
2355
2356 return ret;
2357}
2358
2359static void dispatch_notify(acpi_handle handle, u32 event, void *data)
2360{
2361 struct ibm_struct *ibm = data;
2362
2363 if (!ibm || !ibm->notify)
2364 return;
2365
2366 ibm->notify(ibm, event);
2367}
2368
2369static int __init setup_notify(struct ibm_struct *ibm)
2370{
2371 acpi_status status;
2372 int ret;
2373
2374 if (!*ibm->handle)
2375 return 0;
2376
2377 ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
2378 if (ret < 0) {
2379 printk(IBM_ERR "%s device not present\n", ibm->name);
2380 return -ENODEV;
2381 }
2382
2383 acpi_driver_data(ibm->device) = ibm;
2384 sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
2385
2386 status = acpi_install_notify_handler(*ibm->handle, ibm->type,
2387 dispatch_notify, ibm);
2388 if (ACPI_FAILURE(status)) {
2389 if (status == AE_ALREADY_EXISTS) {
2390 printk(IBM_NOTICE "another device driver is already handling %s events\n",
2391 ibm->name);
2392 } else {
2393 printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
2394 ibm->name, status);
2395 }
2396 return -ENODEV;
2397 }
2398 ibm->notify_installed = 1;
2399 return 0;
2400}
2401
2402static int __init ibm_device_add(struct acpi_device *device)
2403{
2404 return 0;
2405}
2406
2407static int __init register_ibmacpi_subdriver(struct ibm_struct *ibm)
2408{
2409 int ret;
2410
2411 ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
2412 if (!ibm->driver) {
2413 printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
2414 return -1;
2415 }
2416
2417 sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
2418 ibm->driver->ids = ibm->hid;
2419 ibm->driver->ops.add = &ibm_device_add;
2420
2421 ret = acpi_bus_register_driver(ibm->driver);
2422 if (ret < 0) {
2423 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
2424 ibm->hid, ret);
2425 kfree(ibm->driver);
2426 }
2427
2428 return ret;
2429}
2430 2559
2431static int __init ibm_init(struct ibm_struct *ibm) 2560static int __init ibm_init(struct ibm_struct *ibm)
2432{ 2561{
@@ -2500,27 +2629,35 @@ static void ibm_exit(struct ibm_struct *ibm)
2500 } 2629 }
2501} 2630}
2502 2631
2503static void __init ibm_handle_init(char *name, 2632/* Probing */
2504 acpi_handle * handle, acpi_handle parent, 2633
2505 char **paths, int num_paths, char **path) 2634static char *ibm_thinkpad_ec_found = NULL;
2635
2636static char* __init check_dmi_for_ec(void)
2506{ 2637{
2507 int i; 2638 struct dmi_device *dev = NULL;
2508 acpi_status status; 2639 char ec_fw_string[18];
2509 2640
2510 for (i = 0; i < num_paths; i++) { 2641 /*
2511 status = acpi_get_handle(parent, paths[i], handle); 2642 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
2512 if (ACPI_SUCCESS(status)) { 2643 * X32 or newer, all Z series; Some models must have an
2513 *path = paths[i]; 2644 * up-to-date BIOS or they will not be detected.
2514 return; 2645 *
2646 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
2647 */
2648 while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
2649 if (sscanf(dev->name,
2650 "IBM ThinkPad Embedded Controller -[%17c",
2651 ec_fw_string) == 1) {
2652 ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
2653 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
2654 return kstrdup(ec_fw_string, GFP_KERNEL);
2515 } 2655 }
2516 } 2656 }
2517 2657 return NULL;
2518 *handle = NULL;
2519} 2658}
2520 2659
2521#define IBM_HANDLE_INIT(object) \ 2660/* Module init, exit, parameters */
2522 ibm_handle_init(#object, &object##_handle, *object##_parent, \
2523 object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
2524 2661
2525static int __init set_ibm_param(const char *val, struct kernel_param *kp) 2662static int __init set_ibm_param(const char *val, struct kernel_param *kp)
2526{ 2663{
@@ -2538,6 +2675,9 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp)
2538 return -EINVAL; 2675 return -EINVAL;
2539} 2676}
2540 2677
2678static int experimental;
2679module_param(experimental, int, 0);
2680
2541#define IBM_PARAM(feature) \ 2681#define IBM_PARAM(feature) \
2542 module_param_call(feature, set_ibm_param, NULL, NULL, 0) 2682 module_param_call(feature, set_ibm_param, NULL, NULL, 0)
2543 2683
@@ -2559,44 +2699,6 @@ IBM_PARAM(brightness);
2559IBM_PARAM(volume); 2699IBM_PARAM(volume);
2560IBM_PARAM(fan); 2700IBM_PARAM(fan);
2561 2701
2562static void acpi_ibm_exit(void)
2563{
2564 int i;
2565
2566 for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
2567 ibm_exit(&ibms[i]);
2568
2569 if (proc_dir)
2570 remove_proc_entry(IBM_DIR, acpi_root_dir);
2571
2572 if (ibm_thinkpad_ec_found)
2573 kfree(ibm_thinkpad_ec_found);
2574}
2575
2576static char* __init check_dmi_for_ec(void)
2577{
2578 struct dmi_device *dev = NULL;
2579 char ec_fw_string[18];
2580
2581 /*
2582 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
2583 * X32 or newer, all Z series; Some models must have an
2584 * up-to-date BIOS or they will not be detected.
2585 *
2586 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
2587 */
2588 while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
2589 if (sscanf(dev->name,
2590 "IBM ThinkPad Embedded Controller -[%17c",
2591 ec_fw_string) == 1) {
2592 ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
2593 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
2594 return kstrdup(ec_fw_string, GFP_KERNEL);
2595 }
2596 }
2597 return NULL;
2598}
2599
2600static int __init acpi_ibm_init(void) 2702static int __init acpi_ibm_init(void)
2601{ 2703{
2602 int ret, i; 2704 int ret, i;
@@ -2662,5 +2764,19 @@ static int __init acpi_ibm_init(void)
2662 return 0; 2764 return 0;
2663} 2765}
2664 2766
2767static void acpi_ibm_exit(void)
2768{
2769 int i;
2770
2771 for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
2772 ibm_exit(&ibms[i]);
2773
2774 if (proc_dir)
2775 remove_proc_entry(IBM_DIR, acpi_root_dir);
2776
2777 if (ibm_thinkpad_ec_found)
2778 kfree(ibm_thinkpad_ec_found);
2779}
2780
2665module_init(acpi_ibm_init); 2781module_init(acpi_ibm_init);
2666module_exit(acpi_ibm_exit); 2782module_exit(acpi_ibm_exit);