Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Pull platform-drivers into test branch

Len Brown 6bfe5c9d b3617350

+1143 -233
+126 -37
Documentation/ibm-acpi.txt
··· 398 398 399 399 Most ThinkPads include six or more separate temperature sensors but 400 400 only expose the CPU temperature through the standard ACPI methods. 401 - This feature shows readings from up to eight different sensors. Some 402 - readings may not be valid, e.g. may show large negative values. For 403 - example, on the X40, a typical output may be: 404 - 405 - temperatures: 42 42 45 41 36 -128 33 -128 406 - 407 - Thomas Gruber took his R51 apart and traced all six active sensors in 408 - his laptop (the location of sensors may vary on other models): 409 - 410 - 1: CPU 411 - 2: Mini PCI Module 412 - 3: HDD 413 - 4: GPU 414 - 5: Battery 415 - 6: N/A 416 - 7: Battery 417 - 8: N/A 401 + This feature shows readings from up to eight different sensors on older 402 + ThinkPads, and it has experimental support for up to sixteen different 403 + sensors on newer ThinkPads. Readings from sensors that are not available 404 + return -128. 418 405 419 406 No commands can be written to this file. 407 + 408 + EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the 409 + implementation directly accesses hardware registers and may not work as 410 + expected. USE WITH CAUTION! To use this feature, you need to supply the 411 + experimental=1 parameter when loading the module. When EXPERIMENTAL 412 + mode is enabled, reading the first 8 sensors on newer ThinkPads will 413 + also use an new experimental thermal sensor access mode. 414 + 415 + For example, on the X40, a typical output may be: 416 + temperatures: 42 42 45 41 36 -128 33 -128 417 + 418 + EXPERIMENTAL: On the T43/p, a typical output may be: 419 + temperatures: 48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128 420 + 421 + The mapping of thermal sensors to physical locations varies depending on 422 + system-board model (and thus, on ThinkPad model). 423 + 424 + http://thinkwiki.org/wiki/Thermal_Sensors is a public wiki page that 425 + tries to track down these locations for various models. 426 + 427 + Most (newer?) models seem to follow this pattern: 428 + 429 + 1: CPU 430 + 2: (depends on model) 431 + 3: (depends on model) 432 + 4: GPU 433 + 5: Main battery: main sensor 434 + 6: Bay battery: main sensor 435 + 7: Main battery: secondary sensor 436 + 8: Bay battery: secondary sensor 437 + 9-15: (depends on model) 438 + 439 + For the R51 (source: Thomas Gruber): 440 + 2: Mini-PCI 441 + 3: Internal HDD 442 + 443 + For the T43, T43/p (source: Shmidoax/Thinkwiki.org) 444 + http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p 445 + 2: System board, left side (near PCMCIA slot), reported as HDAPS temp 446 + 3: PCMCIA slot 447 + 9: MCH (northbridge) to DRAM Bus 448 + 10: ICH (southbridge), under Mini-PCI card, under touchpad 449 + 11: Power regulator, underside of system board, below F2 key 450 + 451 + The A31 has a very atypical layout for the thermal sensors 452 + (source: Milos Popovic, http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_A31) 453 + 1: CPU 454 + 2: Main Battery: main sensor 455 + 3: Power Converter 456 + 4: Bay Battery: main sensor 457 + 5: MCH (northbridge) 458 + 6: PCMCIA/ambient 459 + 7: Main Battery: secondary sensor 460 + 8: Bay Battery: secondary sensor 461 + 420 462 421 463 EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump 422 464 ------------------------------------------------------------------------ ··· 571 529 WITH CAUTION! To use this feature, you need to supply the 572 530 experimental=1 parameter when loading the module. 573 531 574 - This feature attempts to show the current fan speed. The speed is read 575 - directly from the hardware registers of the embedded controller. This 576 - is known to work on later R, T and X series ThinkPads but may show a 577 - bogus value on other models. 532 + This feature attempts to show the current fan speed, control mode and 533 + other fan data that might be available. The speed is read directly 534 + from the hardware registers of the embedded controller. This is known 535 + to work on later R, T and X series ThinkPads but may show a bogus 536 + value on other models. 537 + 538 + Most ThinkPad fans work in "levels". Level 0 stops the fan. The higher 539 + the level, the higher the fan speed, although adjacent levels often map 540 + to the same fan speed. 7 is the highest level, where the fan reaches 541 + the maximum recommended speed. Level "auto" means the EC changes the 542 + fan level according to some internal algorithm, usually based on 543 + readings from the thermal sensors. Level "disengaged" means the EC 544 + disables the speed-locked closed-loop fan control, and drives the fan as 545 + fast as it can go, which might exceed hardware limits, so use this level 546 + with caution. 547 + 548 + The fan usually ramps up or down slowly from one speed to another, 549 + and it is normal for the EC to take several seconds to react to fan 550 + commands. 578 551 579 552 The fan may be enabled or disabled with the following commands: 580 553 581 554 echo enable >/proc/acpi/ibm/fan 582 555 echo disable >/proc/acpi/ibm/fan 583 556 584 - WARNING WARNING WARNING: do not leave the fan disabled unless you are 585 - monitoring the temperature sensor readings and you are ready to enable 586 - it if necessary to avoid overheating. 557 + Placing a fan on level 0 is the same as disabling it. Enabling a fan 558 + will try to place it in a safe level if it is too slow or disabled. 587 559 588 - The fan only runs if it's enabled *and* the various temperature 589 - sensors which control it read high enough. On the X40, this seems to 590 - depend on the CPU and HDD temperatures. Specifically, the fan is 591 - turned on when either the CPU temperature climbs to 56 degrees or the 592 - HDD temperature climbs to 46 degrees. The fan is turned off when the 593 - CPU temperature drops to 49 degrees and the HDD temperature drops to 594 - 41 degrees. These thresholds cannot currently be controlled. 560 + WARNING WARNING WARNING: do not leave the fan disabled unless you are 561 + monitoring all of the temperature sensor readings and you are ready to 562 + enable it if necessary to avoid overheating. 563 + 564 + An enabled fan in level "auto" may stop spinning if the EC decides the 565 + ThinkPad is cool enough and doesn't need the extra airflow. This is 566 + normal, and the EC will spin the fan up if the varios thermal readings 567 + rise too much. 568 + 569 + On the X40, this seems to depend on the CPU and HDD temperatures. 570 + Specifically, the fan is turned on when either the CPU temperature 571 + climbs to 56 degrees or the HDD temperature climbs to 46 degrees. The 572 + fan is turned off when the CPU temperature drops to 49 degrees and the 573 + HDD temperature drops to 41 degrees. These thresholds cannot 574 + currently be controlled. 575 + 576 + The fan level can be controlled with the command: 577 + 578 + echo 'level <level>' > /proc/acpi/ibm/thermal 579 + 580 + Where <level> is an integer from 0 to 7, or one of the words "auto" 581 + or "disengaged" (without the quotes). Not all ThinkPads support the 582 + "auto" and "disengaged" levels. 595 583 596 584 On the X31 and X40 (and ONLY on those models), the fan speed can be 597 585 controlled to a certain degree. Once the fan is running, it can be ··· 634 562 any effect or the fan speed eventually settles somewhere in that 635 563 range. The fan cannot be stopped or started with this command. 636 564 637 - On the 570, temperature readings are not available through this 638 - feature and the fan control works a little differently. The fan speed 639 - is reported in levels from 0 (off) to 7 (max) and can be controlled 640 - with the following command: 641 - 642 - echo 'level <level>' > /proc/acpi/ibm/thermal 565 + The ThinkPad's ACPI DSDT code will reprogram the fan on its own when 566 + certain conditions are met. It will override any fan programming done 567 + through ibm-acpi. 643 568 644 569 EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan 645 570 --------------------------------------- ··· 669 600 example: 670 601 671 602 modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable 603 + 604 + The ibm-acpi kernel driver can be programmed to revert the fan level 605 + to a safe setting if userspace does not issue one of the fan commands: 606 + "enable", "disable", "level" or "watchdog" within a configurable 607 + ammount of time. To do this, use the "watchdog" command. 608 + 609 + echo 'watchdog <interval>' > /proc/acpi/ibm/fan 610 + 611 + Interval is the ammount of time in seconds to wait for one of the 612 + above mentioned fan commands before reseting the fan level to a safe 613 + one. If set to zero, the watchdog is disabled (default). When the 614 + watchdog timer runs out, it does the exact equivalent of the "enable" 615 + fan command. 616 + 617 + Note that the watchdog timer stops after it enables the fan. It will 618 + be rearmed again automatically (using the same interval) when one of 619 + the above mentioned fan commands is received. The fan watchdog is, 620 + therefore, not suitable to protect against fan mode changes made 621 + through means other than the "enable", "disable", and "level" fan 622 + commands. 672 623 673 624 674 625 Example Configuration
+14
drivers/acpi/Kconfig
··· 173 173 config ACPI_ASUS 174 174 tristate "ASUS/Medion Laptop Extras" 175 175 depends on X86 176 + select BACKLIGHT_CLASS_DEVICE 176 177 ---help--- 177 178 This driver provides support for extra features of ACPI-compatible 178 179 ASUS laptops. As some of Medion laptops are made by ASUS, it may also ··· 202 201 config ACPI_IBM 203 202 tristate "IBM ThinkPad Laptop Extras" 204 203 depends on X86 204 + select BACKLIGHT_CLASS_DEVICE 205 205 ---help--- 206 206 This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds 207 207 support for Fn-Fx key combinations, Bluetooth control, video ··· 225 223 226 224 If you are not sure, say N here. 227 225 226 + config ACPI_IBM_BAY 227 + bool "Legacy Removable Bay Support" 228 + depends on ACPI_IBM 229 + depends on ACPI_BAY=n 230 + default n 231 + ---help--- 232 + Allows the ibm_acpi driver to handle removable bays. 233 + This support is obsoleted by CONFIG_ACPI_BAY. 234 + 235 + If you are not sure, say N here. 236 + 228 237 config ACPI_TOSHIBA 229 238 tristate "Toshiba Laptop Extras" 230 239 depends on X86 240 + select BACKLIGHT_CLASS_DEVICE 231 241 ---help--- 232 242 This driver adds support for access to certain system settings 233 243 on "legacy free" Toshiba laptops. These laptops can be recognized by
+46 -16
drivers/acpi/asus_acpi.c
··· 35 35 #include <linux/init.h> 36 36 #include <linux/types.h> 37 37 #include <linux/proc_fs.h> 38 + #include <linux/backlight.h> 38 39 #include <acpi/acpi_drivers.h> 39 40 #include <acpi/acpi_bus.h> 40 41 #include <asm/uaccess.h> ··· 402 401 403 402 /* procdir we use */ 404 403 static struct proc_dir_entry *asus_proc_dir; 404 + 405 + static struct backlight_device *asus_backlight_device; 405 406 406 407 /* 407 408 * This header is made available to allow proper configuration given model, ··· 782 779 return rv; 783 780 } 784 781 785 - static int read_brightness(void) 782 + static int read_brightness(struct backlight_device *bd) 786 783 { 787 784 int value; 788 785 ··· 804 801 /* 805 802 * Change the brightness level 806 803 */ 807 - static void set_brightness(int value) 804 + static int set_brightness(int value) 808 805 { 809 806 acpi_status status = 0; 807 + int ret = 0; 810 808 811 809 /* SPLV laptop */ 812 810 if (hotk->methods->brightness_set) { ··· 815 811 value, NULL)) 816 812 printk(KERN_WARNING 817 813 "Asus ACPI: Error changing brightness\n"); 818 - return; 814 + ret = -EIO; 815 + goto out; 819 816 } 820 817 821 818 /* No SPLV method if we are here, act as appropriate */ 822 - value -= read_brightness(); 819 + value -= read_brightness(NULL); 823 820 while (value != 0) { 824 821 status = acpi_evaluate_object(NULL, (value > 0) ? 825 822 hotk->methods->brightness_up : ··· 830 825 if (ACPI_FAILURE(status)) 831 826 printk(KERN_WARNING 832 827 "Asus ACPI: Error changing brightness\n"); 828 + ret = -EIO; 833 829 } 834 - return; 830 + out: 831 + return ret; 832 + } 833 + 834 + static int set_brightness_status(struct backlight_device *bd) 835 + { 836 + return set_brightness(bd->props->brightness); 835 837 } 836 838 837 839 static int 838 840 proc_read_brn(char *page, char **start, off_t off, int count, int *eof, 839 841 void *data) 840 842 { 841 - return sprintf(page, "%d\n", read_brightness()); 843 + return sprintf(page, "%d\n", read_brightness(NULL)); 842 844 } 843 845 844 846 static int ··· 1345 1333 return 0; 1346 1334 } 1347 1335 1336 + static struct backlight_properties asus_backlight_data = { 1337 + .owner = THIS_MODULE, 1338 + .get_brightness = read_brightness, 1339 + .update_status = set_brightness_status, 1340 + .max_brightness = 15, 1341 + }; 1342 + 1343 + static void __exit asus_acpi_exit(void) 1344 + { 1345 + if (asus_backlight_device) 1346 + backlight_device_unregister(asus_backlight_device); 1347 + 1348 + acpi_bus_unregister_driver(&asus_hotk_driver); 1349 + remove_proc_entry(PROC_ASUS, acpi_root_dir); 1350 + 1351 + kfree(asus_info); 1352 + 1353 + return; 1354 + } 1355 + 1348 1356 static int __init asus_acpi_init(void) 1349 1357 { 1350 1358 int result; ··· 1402 1370 return result; 1403 1371 } 1404 1372 1373 + asus_backlight_device = backlight_device_register("asus", NULL, 1374 + &asus_backlight_data); 1375 + if (IS_ERR(asus_backlight_device)) { 1376 + printk(KERN_ERR "Could not register asus backlight device\n"); 1377 + asus_backlight_device = NULL; 1378 + asus_acpi_exit(); 1379 + } 1380 + 1405 1381 return 0; 1406 - } 1407 - 1408 - static void __exit asus_acpi_exit(void) 1409 - { 1410 - acpi_bus_unregister_driver(&asus_hotk_driver); 1411 - remove_proc_entry(PROC_ASUS, acpi_root_dir); 1412 - 1413 - kfree(asus_info); 1414 - 1415 - return; 1416 1382 } 1417 1383 1418 1384 module_init(asus_acpi_init);
+892 -157
drivers/acpi/ibm_acpi.c
··· 3 3 * 4 4 * 5 5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> 6 + * Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br> 6 7 * 7 8 * This program is free software; you can redistribute it and/or modify 8 9 * it under the terms of the GNU General Public License as published by ··· 20 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 20 */ 22 21 23 - #define IBM_VERSION "0.12a" 22 + #define IBM_VERSION "0.13" 24 23 25 24 /* 26 25 * Changelog: 26 + * 27 + * 2006-11-22 0.13 new maintainer 28 + * changelog now lives in git commit history, and will 29 + * not be updated further in-file. 27 30 * 28 31 * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels 29 32 * 2005-03-17 0.11 support for 600e, 770x ··· 82 77 #include <linux/module.h> 83 78 #include <linux/init.h> 84 79 #include <linux/types.h> 80 + #include <linux/string.h> 81 + 85 82 #include <linux/proc_fs.h> 83 + #include <linux/backlight.h> 86 84 #include <asm/uaccess.h> 85 + 86 + #include <linux/dmi.h> 87 + #include <linux/jiffies.h> 88 + #include <linux/workqueue.h> 87 89 88 90 #include <acpi/acpi_drivers.h> 89 91 #include <acpi/acnamesp.h> ··· 100 88 #define IBM_FILE "ibm_acpi" 101 89 #define IBM_URL "http://ibm-acpi.sf.net/" 102 90 103 - MODULE_AUTHOR("Borislav Deianov"); 91 + MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); 104 92 MODULE_DESCRIPTION(IBM_DESC); 105 93 MODULE_VERSION(IBM_VERSION); 106 94 MODULE_LICENSE("GPL"); ··· 127 115 static acpi_handle *object##_parent = &parent##_handle; \ 128 116 static char *object##_path; \ 129 117 static char *object##_paths[] = { paths } 130 - 131 - /* 132 - * The following models are supported to various degrees: 133 - * 134 - * 570, 600e, 600x, 770e, 770x 135 - * A20m, A21e, A21m, A21p, A22p, A30, A30p, A31, A31p 136 - * G40, G41 137 - * R30, R31, R32, R40, R40e, R50, R50e, R50p, R51 138 - * T20, T21, T22, T23, T30, T40, T40p, T41, T41p, T42, T42p, T43 139 - * X20, X21, X22, X23, X24, X30, X31, X40 140 - * 141 - * The following models have no supported features: 142 - * 143 - * 240, 240x, i1400 144 - * 145 - * Still missing DSDTs for the following models: 146 - * 147 - * A20p, A22e, A22m 148 - * R52 149 - * S31 150 - * T43p 151 - */ 152 118 153 119 IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ 154 120 "\\_SB.PCI.ISA.EC", /* 570 */ ··· 157 167 "\\_SB.PCI.ISA.SLCE", /* 570 */ 158 168 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ 159 169 #endif 170 + #ifdef CONFIG_ACPI_IBM_BAY 160 171 IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ 161 172 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ 173 + "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ 162 174 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ 163 175 ); /* A21e, R30, R31 */ 164 176 ··· 175 183 IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ 176 184 "_EJ0", /* 770x */ 177 185 ); /* all others */ 186 + #endif 178 187 179 188 /* don't list other alternatives as we install a notify handler on the 570 */ 180 189 IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ ··· 196 203 IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ 197 204 IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ 198 205 IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ 199 - IBM_HANDLE(fans, ec, "FANS"); /* X31, X40 */ 206 + IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ 200 207 201 208 IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ 202 209 "\\FSPD", /* 600e/x, 770e, 770x */ ··· 208 215 209 216 #define IBM_HKEY_HID "IBM0068" 210 217 #define IBM_PCI_HID "PNP0A03" 218 + 219 + enum thermal_access_mode { 220 + IBMACPI_THERMAL_NONE = 0, /* No thermal support */ 221 + IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ 222 + IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ 223 + IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ 224 + IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ 225 + }; 226 + 227 + #define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ 228 + struct ibm_thermal_sensors_struct { 229 + s32 temp[IBMACPI_MAX_THERMAL_SENSORS]; 230 + }; 231 + 232 + /* 233 + * FAN ACCESS MODES 234 + * 235 + * IBMACPI_FAN_RD_ACPI_GFAN: 236 + * ACPI GFAN method: returns fan level 237 + * 238 + * see IBMACPI_FAN_WR_ACPI_SFAN 239 + * EC 0x2f not available if GFAN exists 240 + * 241 + * IBMACPI_FAN_WR_ACPI_SFAN: 242 + * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max) 243 + * 244 + * EC 0x2f might be available *for reading*, but never for writing. 245 + * 246 + * IBMACPI_FAN_WR_TPEC: 247 + * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported 248 + * on almost all ThinkPads 249 + * 250 + * Fan speed changes of any sort (including those caused by the 251 + * disengaged mode) are usually done slowly by the firmware as the 252 + * maximum ammount of fan duty cycle change per second seems to be 253 + * limited. 254 + * 255 + * Reading is not available if GFAN exists. 256 + * Writing is not available if SFAN exists. 257 + * 258 + * Bits 259 + * 7 automatic mode engaged; 260 + * (default operation mode of the ThinkPad) 261 + * fan level is ignored in this mode. 262 + * 6 disengage mode (takes precedence over bit 7); 263 + * not available on all thinkpads. May disable 264 + * the tachometer, and speeds up fan to 100% duty-cycle, 265 + * which speeds it up far above the standard RPM 266 + * levels. It is not impossible that it could cause 267 + * hardware damage. 268 + * 5-3 unused in some models. Extra bits for fan level 269 + * in others, but still useless as all values above 270 + * 7 map to the same speed as level 7 in these models. 271 + * 2-0 fan level (0..7 usually) 272 + * 0x00 = stop 273 + * 0x07 = max (set when temperatures critical) 274 + * Some ThinkPads may have other levels, see 275 + * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41) 276 + * 277 + * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at 278 + * boot. Apparently the EC does not intialize it, so unless ACPI DSDT 279 + * does so, its initial value is meaningless (0x07). 280 + * 281 + * For firmware bugs, refer to: 282 + * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues 283 + * 284 + * ---- 285 + * 286 + * ThinkPad EC register 0x84 (LSB), 0x85 (MSB): 287 + * Main fan tachometer reading (in RPM) 288 + * 289 + * This register is present on all ThinkPads with a new-style EC, and 290 + * it is known not to be present on the A21m/e, and T22, as there is 291 + * something else in offset 0x84 according to the ACPI DSDT. Other 292 + * ThinkPads from this same time period (and earlier) probably lack the 293 + * tachometer as well. 294 + * 295 + * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare 296 + * was never fixed by IBM to report the EC firmware version string 297 + * probably support the tachometer (like the early X models), so 298 + * detecting it is quite hard. We need more data to know for sure. 299 + * 300 + * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings 301 + * might result. 302 + * 303 + * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this 304 + * register is not invalidated in ThinkPads that disable tachometer 305 + * readings. Thus, the tachometer readings go stale. 306 + * 307 + * For firmware bugs, refer to: 308 + * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues 309 + * 310 + * IBMACPI_FAN_WR_ACPI_FANS: 311 + * ThinkPad X31, X40, X41. Not available in the X60. 312 + * 313 + * FANS ACPI handle: takes three arguments: low speed, medium speed, 314 + * high speed. ACPI DSDT seems to map these three speeds to levels 315 + * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH 316 + * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3") 317 + * 318 + * The speeds are stored on handles 319 + * (FANA:FAN9), (FANC:FANB), (FANE:FAND). 320 + * 321 + * There are three default speed sets, acessible as handles: 322 + * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H 323 + * 324 + * ACPI DSDT switches which set is in use depending on various 325 + * factors. 326 + * 327 + * IBMACPI_FAN_WR_TPEC is also available and should be used to 328 + * command the fan. The X31/X40/X41 seems to have 8 fan levels, 329 + * but the ACPI tables just mention level 7. 330 + */ 331 + 332 + enum fan_status_access_mode { 333 + IBMACPI_FAN_NONE = 0, /* No fan status or control */ 334 + IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ 335 + IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ 336 + }; 337 + 338 + enum fan_control_access_mode { 339 + IBMACPI_FAN_WR_NONE = 0, /* No fan control */ 340 + IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ 341 + IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ 342 + IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ 343 + }; 344 + 345 + enum fan_control_commands { 346 + IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ 347 + IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ 348 + IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, 349 + * and also watchdog cmd */ 350 + }; 351 + 352 + enum { /* Fan control constants */ 353 + fan_status_offset = 0x2f, /* EC register 0x2f */ 354 + fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) 355 + * 0x84 must be read before 0x85 */ 356 + 357 + IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer 358 + * disengaged */ 359 + IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan 360 + * control */ 361 + }; 362 + 363 + static char *ibm_thinkpad_ec_found = NULL; 211 364 212 365 struct ibm_struct { 213 366 char *name; ··· 381 242 }; 382 243 383 244 static struct proc_dir_entry *proc_dir = NULL; 245 + 246 + static struct backlight_device *ibm_backlight_device = NULL; 384 247 385 248 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") 386 249 #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") ··· 722 581 { 723 582 int status; 724 583 725 - if (!wan_supported || 726 - !acpi_evalf(hkey_handle, &status, "GWAN", "d")) 584 + if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d")) 727 585 status = 0; 728 586 729 587 return status; ··· 770 630 return 0; 771 631 } 772 632 773 - static int video_supported; 774 - static int video_orig_autosw; 633 + enum video_access_mode { 634 + IBMACPI_VIDEO_NONE = 0, 635 + IBMACPI_VIDEO_570, /* 570 */ 636 + IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */ 637 + IBMACPI_VIDEO_NEW, /* all others */ 638 + }; 775 639 776 - #define VIDEO_570 1 777 - #define VIDEO_770 2 778 - #define VIDEO_NEW 3 640 + static enum video_access_mode video_supported; 641 + static int video_orig_autosw; 779 642 780 643 static int video_init(void) 781 644 { ··· 790 647 791 648 if (!vid_handle) 792 649 /* video switching not supported on R30, R31 */ 793 - video_supported = 0; 650 + video_supported = IBMACPI_VIDEO_NONE; 794 651 else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) 795 652 /* 570 */ 796 - video_supported = VIDEO_570; 653 + video_supported = IBMACPI_VIDEO_570; 797 654 else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) 798 655 /* 600e/x, 770e, 770x */ 799 - video_supported = VIDEO_770; 656 + video_supported = IBMACPI_VIDEO_770; 800 657 else 801 658 /* all others */ 802 - video_supported = VIDEO_NEW; 659 + video_supported = IBMACPI_VIDEO_NEW; 803 660 804 661 return 0; 805 662 } ··· 809 666 int status = 0; 810 667 int i; 811 668 812 - if (video_supported == VIDEO_570) { 669 + if (video_supported == IBMACPI_VIDEO_570) { 813 670 if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87)) 814 671 status = i & 3; 815 - } else if (video_supported == VIDEO_770) { 672 + } else if (video_supported == IBMACPI_VIDEO_770) { 816 673 if (acpi_evalf(NULL, &i, "\\VCDL", "d")) 817 674 status |= 0x01 * i; 818 675 if (acpi_evalf(NULL, &i, "\\VCDC", "d")) 819 676 status |= 0x02 * i; 820 - } else if (video_supported == VIDEO_NEW) { 677 + } else if (video_supported == IBMACPI_VIDEO_NEW) { 821 678 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1); 822 679 if (acpi_evalf(NULL, &i, "\\VCDC", "d")) 823 680 status |= 0x02 * i; ··· 836 693 { 837 694 int autosw = 0; 838 695 839 - if (video_supported == VIDEO_570) 696 + if (video_supported == IBMACPI_VIDEO_570) 840 697 acpi_evalf(vid_handle, &autosw, "SWIT", "d"); 841 - else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW) 698 + else if (video_supported == IBMACPI_VIDEO_770 || 699 + video_supported == IBMACPI_VIDEO_NEW) 842 700 acpi_evalf(vid_handle, &autosw, "^VDEE", "d"); 843 701 844 702 return autosw & 1; ··· 859 715 len += sprintf(p + len, "status:\t\tsupported\n"); 860 716 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); 861 717 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); 862 - if (video_supported == VIDEO_NEW) 718 + if (video_supported == IBMACPI_VIDEO_NEW) 863 719 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); 864 720 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); 865 721 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); 866 722 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); 867 - if (video_supported == VIDEO_NEW) 723 + if (video_supported == IBMACPI_VIDEO_NEW) 868 724 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); 869 725 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); 870 726 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); ··· 879 735 880 736 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) 881 737 return -EIO; 882 - ret = video_supported == VIDEO_570 ? 738 + ret = video_supported == IBMACPI_VIDEO_570 ? 883 739 acpi_evalf(ec_handle, NULL, "_Q16", "v") : 884 740 acpi_evalf(vid_handle, NULL, "VSWT", "v"); 885 741 acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); ··· 889 745 890 746 static int video_expand(void) 891 747 { 892 - if (video_supported == VIDEO_570) 748 + if (video_supported == IBMACPI_VIDEO_570) 893 749 return acpi_evalf(ec_handle, NULL, "_Q17", "v"); 894 - else if (video_supported == VIDEO_770) 750 + else if (video_supported == IBMACPI_VIDEO_770) 895 751 return acpi_evalf(vid_handle, NULL, "VEXP", "v"); 896 752 else 897 753 return acpi_evalf(NULL, NULL, "\\VEXP", "v"); ··· 901 757 { 902 758 int ret; 903 759 904 - if (video_supported == VIDEO_570) { 760 + if (video_supported == IBMACPI_VIDEO_570) { 905 761 ret = acpi_evalf(NULL, NULL, 906 762 "\\_SB.PHS2", "vdd", 0x8b, status | 0x80); 907 - } else if (video_supported == VIDEO_770) { 763 + } else if (video_supported == IBMACPI_VIDEO_770) { 908 764 int autosw = video_autosw(); 909 765 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) 910 766 return -EIO; ··· 940 796 enable |= 0x02; 941 797 } else if (strlencmp(cmd, "crt_disable") == 0) { 942 798 disable |= 0x02; 943 - } else if (video_supported == VIDEO_NEW && 799 + } else if (video_supported == IBMACPI_VIDEO_NEW && 944 800 strlencmp(cmd, "dvi_enable") == 0) { 945 801 enable |= 0x08; 946 - } else if (video_supported == VIDEO_NEW && 802 + } else if (video_supported == IBMACPI_VIDEO_NEW && 947 803 strlencmp(cmd, "dvi_disable") == 0) { 948 804 disable |= 0x08; 949 805 } else if (strlencmp(cmd, "auto_enable") == 0) { ··· 1042 898 return 0; 1043 899 } 1044 900 901 + #if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY) 1045 902 static int _sta(acpi_handle handle) 1046 903 { 1047 904 int status; ··· 1052 907 1053 908 return status; 1054 909 } 910 + #endif 1055 911 #ifdef CONFIG_ACPI_IBM_DOCK 1056 912 #define dock_docked() (_sta(dock_handle) & 1) 1057 913 ··· 1118 972 } 1119 973 #endif 1120 974 975 + #ifdef CONFIG_ACPI_IBM_BAY 1121 976 static int bay_status_supported; 1122 977 static int bay_status2_supported; 1123 978 static int bay_eject_supported; ··· 1194 1047 { 1195 1048 acpi_bus_generate_event(ibm->device, event, 0); 1196 1049 } 1050 + #endif 1197 1051 1198 1052 static int cmos_read(char *p) 1199 1053 { ··· 1242 1094 return 0; 1243 1095 } 1244 1096 1245 - static int led_supported; 1246 - 1247 - #define LED_570 1 1248 - #define LED_OLD 2 1249 - #define LED_NEW 3 1097 + enum led_access_mode { 1098 + IBMACPI_LED_NONE = 0, 1099 + IBMACPI_LED_570, /* 570 */ 1100 + IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ 1101 + IBMACPI_LED_NEW, /* all others */ 1102 + }; 1103 + static enum led_access_mode led_supported; 1250 1104 1251 1105 static int led_init(void) 1252 1106 { 1253 1107 if (!led_handle) 1254 1108 /* led not supported on R30, R31 */ 1255 - led_supported = 0; 1109 + led_supported = IBMACPI_LED_NONE; 1256 1110 else if (strlencmp(led_path, "SLED") == 0) 1257 1111 /* 570 */ 1258 - led_supported = LED_570; 1112 + led_supported = IBMACPI_LED_570; 1259 1113 else if (strlencmp(led_path, "SYSL") == 0) 1260 1114 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ 1261 - led_supported = LED_OLD; 1115 + led_supported = IBMACPI_LED_OLD; 1262 1116 else 1263 1117 /* all others */ 1264 - led_supported = LED_NEW; 1118 + led_supported = IBMACPI_LED_NEW; 1265 1119 1266 1120 return 0; 1267 1121 } ··· 1280 1130 } 1281 1131 len += sprintf(p + len, "status:\t\tsupported\n"); 1282 1132 1283 - if (led_supported == LED_570) { 1133 + if (led_supported == IBMACPI_LED_570) { 1284 1134 /* 570 */ 1285 1135 int i, status; 1286 1136 for (i = 0; i < 8; i++) { ··· 1329 1179 } else 1330 1180 return -EINVAL; 1331 1181 1332 - if (led_supported == LED_570) { 1182 + if (led_supported == IBMACPI_LED_570) { 1333 1183 /* 570 */ 1334 1184 led = 1 << led; 1335 1185 if (!acpi_evalf(led_handle, NULL, NULL, "vdd", 1336 1186 led, led_sled_arg1[ind])) 1337 1187 return -EIO; 1338 - } else if (led_supported == LED_OLD) { 1188 + } else if (led_supported == IBMACPI_LED_OLD) { 1339 1189 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ 1340 1190 led = 1 << led; 1341 1191 ret = ec_write(EC_HLMS, led); ··· 1422 1272 return 1; 1423 1273 } 1424 1274 1425 - static int thermal_tmp_supported; 1426 - static int thermal_updt_supported; 1275 + static enum thermal_access_mode thermal_read_mode; 1427 1276 1428 1277 static int thermal_init(void) 1429 1278 { 1430 - /* temperatures not supported on 570, G4x, R30, R31, R32 */ 1431 - thermal_tmp_supported = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); 1279 + u8 t, ta1, ta2; 1280 + int i; 1281 + int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); 1432 1282 1433 - /* 600e/x, 770e, 770x */ 1434 - thermal_updt_supported = acpi_evalf(ec_handle, NULL, "UPDT", "qv"); 1283 + if (ibm_thinkpad_ec_found && experimental) { 1284 + /* 1285 + * Direct EC access mode: sensors at registers 1286 + * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for 1287 + * non-implemented, thermal sensors return 0x80 when 1288 + * not available 1289 + */ 1290 + 1291 + ta1 = ta2 = 0; 1292 + for (i = 0; i < 8; i++) { 1293 + if (likely(acpi_ec_read(0x78 + i, &t))) { 1294 + ta1 |= t; 1295 + } else { 1296 + ta1 = 0; 1297 + break; 1298 + } 1299 + if (likely(acpi_ec_read(0xC0 + i, &t))) { 1300 + ta2 |= t; 1301 + } else { 1302 + ta1 = 0; 1303 + break; 1304 + } 1305 + } 1306 + if (ta1 == 0) { 1307 + /* This is sheer paranoia, but we handle it anyway */ 1308 + if (acpi_tmp7) { 1309 + printk(IBM_ERR 1310 + "ThinkPad ACPI EC access misbehaving, " 1311 + "falling back to ACPI TMPx access mode\n"); 1312 + thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07; 1313 + } else { 1314 + printk(IBM_ERR 1315 + "ThinkPad ACPI EC access misbehaving, " 1316 + "disabling thermal sensors access\n"); 1317 + thermal_read_mode = IBMACPI_THERMAL_NONE; 1318 + } 1319 + } else { 1320 + thermal_read_mode = 1321 + (ta2 != 0) ? 1322 + IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8; 1323 + } 1324 + } else if (acpi_tmp7) { 1325 + if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { 1326 + /* 600e/x, 770e, 770x */ 1327 + thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT; 1328 + } else { 1329 + /* Standard ACPI TMPx access, max 8 sensors */ 1330 + thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07; 1331 + } 1332 + } else { 1333 + /* temperatures not supported on 570, G4x, R30, R31, R32 */ 1334 + thermal_read_mode = IBMACPI_THERMAL_NONE; 1335 + } 1435 1336 1436 1337 return 0; 1338 + } 1339 + 1340 + static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) 1341 + { 1342 + int i, t; 1343 + s8 tmp; 1344 + char tmpi[] = "TMPi"; 1345 + 1346 + if (!s) 1347 + return -EINVAL; 1348 + 1349 + switch (thermal_read_mode) { 1350 + #if IBMACPI_MAX_THERMAL_SENSORS >= 16 1351 + case IBMACPI_THERMAL_TPEC_16: 1352 + for (i = 0; i < 8; i++) { 1353 + if (!acpi_ec_read(0xC0 + i, &tmp)) 1354 + return -EIO; 1355 + s->temp[i + 8] = tmp * 1000; 1356 + } 1357 + /* fallthrough */ 1358 + #endif 1359 + case IBMACPI_THERMAL_TPEC_8: 1360 + for (i = 0; i < 8; i++) { 1361 + if (!acpi_ec_read(0x78 + i, &tmp)) 1362 + return -EIO; 1363 + s->temp[i] = tmp * 1000; 1364 + } 1365 + return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8; 1366 + 1367 + case IBMACPI_THERMAL_ACPI_UPDT: 1368 + if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) 1369 + return -EIO; 1370 + for (i = 0; i < 8; i++) { 1371 + tmpi[3] = '0' + i; 1372 + if (!acpi_evalf(ec_handle, &t, tmpi, "d")) 1373 + return -EIO; 1374 + s->temp[i] = (t - 2732) * 100; 1375 + } 1376 + return 8; 1377 + 1378 + case IBMACPI_THERMAL_ACPI_TMP07: 1379 + for (i = 0; i < 8; i++) { 1380 + tmpi[3] = '0' + i; 1381 + if (!acpi_evalf(ec_handle, &t, tmpi, "d")) 1382 + return -EIO; 1383 + s->temp[i] = t * 1000; 1384 + } 1385 + return 8; 1386 + 1387 + case IBMACPI_THERMAL_NONE: 1388 + default: 1389 + return 0; 1390 + } 1437 1391 } 1438 1392 1439 1393 static int thermal_read(char *p) 1440 1394 { 1441 1395 int len = 0; 1396 + int n, i; 1397 + struct ibm_thermal_sensors_struct t; 1442 1398 1443 - if (!thermal_tmp_supported) 1444 - len += sprintf(p + len, "temperatures:\tnot supported\n"); 1445 - else { 1446 - int i, t; 1447 - char tmpi[] = "TMPi"; 1448 - s8 tmp[8]; 1399 + n = thermal_get_sensors(&t); 1400 + if (unlikely(n < 0)) 1401 + return n; 1449 1402 1450 - if (thermal_updt_supported) 1451 - if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) 1452 - return -EIO; 1403 + len += sprintf(p + len, "temperatures:\t"); 1453 1404 1454 - for (i = 0; i < 8; i++) { 1455 - tmpi[3] = '0' + i; 1456 - if (!acpi_evalf(ec_handle, &t, tmpi, "d")) 1457 - return -EIO; 1458 - if (thermal_updt_supported) 1459 - tmp[i] = (t - 2732 + 5) / 10; 1460 - else 1461 - tmp[i] = t; 1462 - } 1463 - 1464 - len += sprintf(p + len, 1465 - "temperatures:\t%d %d %d %d %d %d %d %d\n", 1466 - tmp[0], tmp[1], tmp[2], tmp[3], 1467 - tmp[4], tmp[5], tmp[6], tmp[7]); 1468 - } 1405 + if (n > 0) { 1406 + for (i = 0; i < (n - 1); i++) 1407 + len += sprintf(p + len, "%d ", t.temp[i] / 1000); 1408 + len += sprintf(p + len, "%d\n", t.temp[i] / 1000); 1409 + } else 1410 + len += sprintf(p + len, "not supported\n"); 1469 1411 1470 1412 return len; 1471 1413 } ··· 1623 1381 1624 1382 static int brightness_offset = 0x31; 1625 1383 1384 + static int brightness_get(struct backlight_device *bd) 1385 + { 1386 + u8 level; 1387 + if (!acpi_ec_read(brightness_offset, &level)) 1388 + return -EIO; 1389 + 1390 + level &= 0x7; 1391 + 1392 + return level; 1393 + } 1394 + 1626 1395 static int brightness_read(char *p) 1627 1396 { 1628 1397 int len = 0; 1629 - u8 level; 1398 + int level; 1630 1399 1631 - if (!acpi_ec_read(brightness_offset, &level)) { 1400 + if ((level = brightness_get(NULL)) < 0) { 1632 1401 len += sprintf(p + len, "level:\t\tunreadable\n"); 1633 1402 } else { 1634 1403 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); ··· 1654 1401 #define BRIGHTNESS_UP 4 1655 1402 #define BRIGHTNESS_DOWN 5 1656 1403 1657 - static int brightness_write(char *buf) 1404 + static int brightness_set(int value) 1658 1405 { 1659 1406 int cmos_cmd, inc, i; 1660 - u8 level; 1407 + int current_value = brightness_get(NULL); 1408 + 1409 + value &= 7; 1410 + 1411 + cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN; 1412 + inc = value > current_value ? 1 : -1; 1413 + for (i = current_value; i != value; i += inc) { 1414 + if (!cmos_eval(cmos_cmd)) 1415 + return -EIO; 1416 + if (!acpi_ec_write(brightness_offset, i + inc)) 1417 + return -EIO; 1418 + } 1419 + 1420 + return 0; 1421 + } 1422 + 1423 + static int brightness_write(char *buf) 1424 + { 1425 + int level; 1661 1426 int new_level; 1662 1427 char *cmd; 1663 1428 1664 1429 while ((cmd = next_cmd(&buf))) { 1665 - if (!acpi_ec_read(brightness_offset, &level)) 1666 - return -EIO; 1430 + if ((level = brightness_get(NULL)) < 0) 1431 + return level; 1667 1432 level &= 7; 1668 1433 1669 1434 if (strlencmp(cmd, "up") == 0) { ··· 1694 1423 } else 1695 1424 return -EINVAL; 1696 1425 1697 - cmos_cmd = new_level > level ? BRIGHTNESS_UP : BRIGHTNESS_DOWN; 1698 - inc = new_level > level ? 1 : -1; 1699 - for (i = level; i != new_level; i += inc) { 1700 - if (!cmos_eval(cmos_cmd)) 1701 - return -EIO; 1702 - if (!acpi_ec_write(brightness_offset, i + inc)) 1703 - return -EIO; 1704 - } 1426 + brightness_set(new_level); 1705 1427 } 1706 1428 1707 1429 return 0; 1430 + } 1431 + 1432 + static int brightness_update_status(struct backlight_device *bd) 1433 + { 1434 + return brightness_set(bd->props->brightness); 1435 + } 1436 + 1437 + static struct backlight_properties ibm_backlight_data = { 1438 + .owner = THIS_MODULE, 1439 + .get_brightness = brightness_get, 1440 + .update_status = brightness_update_status, 1441 + .max_brightness = 7, 1442 + }; 1443 + 1444 + static int brightness_init(void) 1445 + { 1446 + ibm_backlight_device = backlight_device_register("ibm", NULL, 1447 + &ibm_backlight_data); 1448 + if (IS_ERR(ibm_backlight_device)) { 1449 + printk(IBM_ERR "Could not register backlight device\n"); 1450 + return PTR_ERR(ibm_backlight_device); 1451 + } 1452 + 1453 + return 0; 1454 + } 1455 + 1456 + static void brightness_exit(void) 1457 + { 1458 + if (ibm_backlight_device) { 1459 + backlight_device_unregister(ibm_backlight_device); 1460 + ibm_backlight_device = NULL; 1461 + } 1708 1462 } 1709 1463 1710 1464 static int volume_offset = 0x30; ··· 1818 1522 return 0; 1819 1523 } 1820 1524 1821 - static int fan_status_offset = 0x2f; 1822 - static int fan_rpm_offset = 0x84; 1525 + static enum fan_status_access_mode fan_status_access_mode; 1526 + static enum fan_control_access_mode fan_control_access_mode; 1527 + static enum fan_control_commands fan_control_commands; 1528 + 1529 + static int fan_control_status_known; 1530 + static u8 fan_control_initial_status; 1531 + 1532 + static void fan_watchdog_fire(void *ignored); 1533 + static int fan_watchdog_maxinterval; 1534 + static DECLARE_WORK(fan_watchdog_task, fan_watchdog_fire, NULL); 1535 + 1536 + static int fan_init(void) 1537 + { 1538 + fan_status_access_mode = IBMACPI_FAN_NONE; 1539 + fan_control_access_mode = IBMACPI_FAN_WR_NONE; 1540 + fan_control_commands = 0; 1541 + fan_control_status_known = 1; 1542 + fan_watchdog_maxinterval = 0; 1543 + 1544 + if (gfan_handle) { 1545 + /* 570, 600e/x, 770e, 770x */ 1546 + fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN; 1547 + } else { 1548 + /* all other ThinkPads: note that even old-style 1549 + * ThinkPad ECs supports the fan control register */ 1550 + if (likely(acpi_ec_read(fan_status_offset, 1551 + &fan_control_initial_status))) { 1552 + fan_status_access_mode = IBMACPI_FAN_RD_TPEC; 1553 + 1554 + /* In some ThinkPads, neither the EC nor the ACPI 1555 + * DSDT initialize the fan status, and it ends up 1556 + * being set to 0x07 when it *could* be either 1557 + * 0x07 or 0x80. 1558 + * 1559 + * Enable for TP-1Y (T43), TP-78 (R51e), 1560 + * TP-76 (R52), TP-70 (T43, R52), which are known 1561 + * to be buggy. */ 1562 + if (fan_control_initial_status == 0x07 && 1563 + ibm_thinkpad_ec_found && 1564 + ((ibm_thinkpad_ec_found[0] == '1' && 1565 + ibm_thinkpad_ec_found[1] == 'Y') || 1566 + (ibm_thinkpad_ec_found[0] == '7' && 1567 + (ibm_thinkpad_ec_found[1] == '6' || 1568 + ibm_thinkpad_ec_found[1] == '8' || 1569 + ibm_thinkpad_ec_found[1] == '0')) 1570 + )) { 1571 + printk(IBM_NOTICE 1572 + "fan_init: initial fan status is " 1573 + "unknown, assuming it is in auto " 1574 + "mode\n"); 1575 + fan_control_status_known = 0; 1576 + } 1577 + } else { 1578 + printk(IBM_ERR 1579 + "ThinkPad ACPI EC access misbehaving, " 1580 + "fan status and control unavailable\n"); 1581 + return 0; 1582 + } 1583 + } 1584 + 1585 + if (sfan_handle) { 1586 + /* 570, 770x-JL */ 1587 + fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN; 1588 + fan_control_commands |= 1589 + IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE; 1590 + } else { 1591 + if (!gfan_handle) { 1592 + /* gfan without sfan means no fan control */ 1593 + /* all other models implement TP EC 0x2f control */ 1594 + 1595 + if (fans_handle) { 1596 + /* X31, X40, X41 */ 1597 + fan_control_access_mode = 1598 + IBMACPI_FAN_WR_ACPI_FANS; 1599 + fan_control_commands |= 1600 + IBMACPI_FAN_CMD_SPEED | 1601 + IBMACPI_FAN_CMD_LEVEL | 1602 + IBMACPI_FAN_CMD_ENABLE; 1603 + } else { 1604 + fan_control_access_mode = IBMACPI_FAN_WR_TPEC; 1605 + fan_control_commands |= 1606 + IBMACPI_FAN_CMD_LEVEL | 1607 + IBMACPI_FAN_CMD_ENABLE; 1608 + } 1609 + } 1610 + } 1611 + 1612 + return 0; 1613 + } 1614 + 1615 + static int fan_get_status(u8 *status) 1616 + { 1617 + u8 s; 1618 + 1619 + /* TODO: 1620 + * Add IBMACPI_FAN_RD_ACPI_FANS ? */ 1621 + 1622 + switch (fan_status_access_mode) { 1623 + case IBMACPI_FAN_RD_ACPI_GFAN: 1624 + /* 570, 600e/x, 770e, 770x */ 1625 + 1626 + if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) 1627 + return -EIO; 1628 + 1629 + if (likely(status)) 1630 + *status = s & 0x07; 1631 + 1632 + break; 1633 + 1634 + case IBMACPI_FAN_RD_TPEC: 1635 + /* all except 570, 600e/x, 770e, 770x */ 1636 + if (unlikely(!acpi_ec_read(fan_status_offset, &s))) 1637 + return -EIO; 1638 + 1639 + if (likely(status)) 1640 + *status = s; 1641 + 1642 + break; 1643 + 1644 + default: 1645 + return -ENXIO; 1646 + } 1647 + 1648 + return 0; 1649 + } 1650 + 1651 + static int fan_get_speed(unsigned int *speed) 1652 + { 1653 + u8 hi, lo; 1654 + 1655 + switch (fan_status_access_mode) { 1656 + case IBMACPI_FAN_RD_TPEC: 1657 + /* all except 570, 600e/x, 770e, 770x */ 1658 + if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || 1659 + !acpi_ec_read(fan_rpm_offset + 1, &hi))) 1660 + return -EIO; 1661 + 1662 + if (likely(speed)) 1663 + *speed = (hi << 8) | lo; 1664 + 1665 + break; 1666 + 1667 + default: 1668 + return -ENXIO; 1669 + } 1670 + 1671 + return 0; 1672 + } 1673 + 1674 + static void fan_exit(void) 1675 + { 1676 + cancel_delayed_work(&fan_watchdog_task); 1677 + flush_scheduled_work(); 1678 + } 1679 + 1680 + static void fan_watchdog_reset(void) 1681 + { 1682 + static int fan_watchdog_active = 0; 1683 + 1684 + if (fan_watchdog_active) 1685 + cancel_delayed_work(&fan_watchdog_task); 1686 + 1687 + if (fan_watchdog_maxinterval > 0) { 1688 + fan_watchdog_active = 1; 1689 + if (!schedule_delayed_work(&fan_watchdog_task, 1690 + msecs_to_jiffies(fan_watchdog_maxinterval 1691 + * 1000))) { 1692 + printk(IBM_ERR "failed to schedule the fan watchdog, " 1693 + "watchdog will not trigger\n"); 1694 + } 1695 + } else 1696 + fan_watchdog_active = 0; 1697 + } 1823 1698 1824 1699 static int fan_read(char *p) 1825 1700 { 1826 1701 int len = 0; 1827 - int s; 1828 - u8 lo, hi, status; 1702 + int rc; 1703 + u8 status; 1704 + unsigned int speed = 0; 1829 1705 1830 - if (gfan_handle) { 1706 + switch (fan_status_access_mode) { 1707 + case IBMACPI_FAN_RD_ACPI_GFAN: 1831 1708 /* 570, 600e/x, 770e, 770x */ 1832 - if (!acpi_evalf(gfan_handle, &s, NULL, "d")) 1833 - return -EIO; 1709 + if ((rc = fan_get_status(&status)) < 0) 1710 + return rc; 1834 1711 1835 - len += sprintf(p + len, "level:\t\t%d\n", s); 1836 - } else { 1712 + len += sprintf(p + len, "status:\t\t%s\n" 1713 + "level:\t\t%d\n", 1714 + (status != 0) ? "enabled" : "disabled", status); 1715 + break; 1716 + 1717 + case IBMACPI_FAN_RD_TPEC: 1837 1718 /* all except 570, 600e/x, 770e, 770x */ 1838 - if (!acpi_ec_read(fan_status_offset, &status)) 1839 - len += sprintf(p + len, "status:\t\tunreadable\n"); 1840 - else 1841 - len += sprintf(p + len, "status:\t\t%s\n", 1842 - enabled(status, 7)); 1719 + if ((rc = fan_get_status(&status)) < 0) 1720 + return rc; 1843 1721 1844 - if (!acpi_ec_read(fan_rpm_offset, &lo) || 1845 - !acpi_ec_read(fan_rpm_offset + 1, &hi)) 1846 - len += sprintf(p + len, "speed:\t\tunreadable\n"); 1722 + if (unlikely(!fan_control_status_known)) { 1723 + if (status != fan_control_initial_status) 1724 + fan_control_status_known = 1; 1725 + else 1726 + /* Return most likely status. In fact, it 1727 + * might be the only possible status */ 1728 + status = IBMACPI_FAN_EC_AUTO; 1729 + } 1730 + 1731 + len += sprintf(p + len, "status:\t\t%s\n", 1732 + (status != 0) ? "enabled" : "disabled"); 1733 + 1734 + /* No ThinkPad boots on disengaged mode, we can safely 1735 + * assume the tachometer is online if fan control status 1736 + * was unknown */ 1737 + if ((rc = fan_get_speed(&speed)) < 0) 1738 + return rc; 1739 + 1740 + len += sprintf(p + len, "speed:\t\t%d\n", speed); 1741 + 1742 + if (status & IBMACPI_FAN_EC_DISENGAGED) 1743 + /* Disengaged mode takes precedence */ 1744 + len += sprintf(p + len, "level:\t\tdisengaged\n"); 1745 + else if (status & IBMACPI_FAN_EC_AUTO) 1746 + len += sprintf(p + len, "level:\t\tauto\n"); 1847 1747 else 1848 - len += sprintf(p + len, "speed:\t\t%d\n", 1849 - (hi << 8) + lo); 1748 + len += sprintf(p + len, "level:\t\t%d\n", status); 1749 + break; 1750 + 1751 + case IBMACPI_FAN_NONE: 1752 + default: 1753 + len += sprintf(p + len, "status:\t\tnot supported\n"); 1850 1754 } 1851 1755 1852 - if (sfan_handle) 1853 - /* 570, 770x-JL */ 1854 - len += sprintf(p + len, "commands:\tlevel <level>" 1855 - " (<level> is 0-7)\n"); 1856 - if (!gfan_handle) 1857 - /* all except 570, 600e/x, 770e, 770x */ 1858 - len += sprintf(p + len, "commands:\tenable, disable\n"); 1859 - if (fans_handle) 1860 - /* X31, X40 */ 1756 + if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) { 1757 + len += sprintf(p + len, "commands:\tlevel <level>"); 1758 + 1759 + switch (fan_control_access_mode) { 1760 + case IBMACPI_FAN_WR_ACPI_SFAN: 1761 + len += sprintf(p + len, " (<level> is 0-7)\n"); 1762 + break; 1763 + 1764 + default: 1765 + len += sprintf(p + len, " (<level> is 0-7, " 1766 + "auto, disengaged)\n"); 1767 + break; 1768 + } 1769 + } 1770 + 1771 + if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE) 1772 + len += sprintf(p + len, "commands:\tenable, disable\n" 1773 + "commands:\twatchdog <timeout> (<timeout> is 0 (off), " 1774 + "1-120 (seconds))\n"); 1775 + 1776 + if (fan_control_commands & IBMACPI_FAN_CMD_SPEED) 1861 1777 len += sprintf(p + len, "commands:\tspeed <speed>" 1862 1778 " (<speed> is 0-65535)\n"); 1863 1779 1864 1780 return len; 1865 1781 } 1866 1782 1867 - static int fan_write(char *buf) 1783 + static int fan_set_level(int level) 1868 1784 { 1869 - char *cmd; 1870 - int level, speed; 1871 - 1872 - while ((cmd = next_cmd(&buf))) { 1873 - if (sfan_handle && 1874 - sscanf(cmd, "level %d", &level) == 1 && 1875 - level >= 0 && level <= 7) { 1876 - /* 570, 770x-JL */ 1785 + switch (fan_control_access_mode) { 1786 + case IBMACPI_FAN_WR_ACPI_SFAN: 1787 + if (level >= 0 && level <= 7) { 1877 1788 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) 1878 1789 return -EIO; 1879 - } else if (!gfan_handle && strlencmp(cmd, "enable") == 0) { 1880 - /* all except 570, 600e/x, 770e, 770x */ 1881 - if (!acpi_ec_write(fan_status_offset, 0x80)) 1882 - return -EIO; 1883 - } else if (!gfan_handle && strlencmp(cmd, "disable") == 0) { 1884 - /* all except 570, 600e/x, 770e, 770x */ 1885 - if (!acpi_ec_write(fan_status_offset, 0x00)) 1886 - return -EIO; 1887 - } else if (fans_handle && 1888 - sscanf(cmd, "speed %d", &speed) == 1 && 1889 - speed >= 0 && speed <= 65535) { 1890 - /* X31, X40 */ 1790 + } else 1791 + return -EINVAL; 1792 + break; 1793 + 1794 + case IBMACPI_FAN_WR_ACPI_FANS: 1795 + case IBMACPI_FAN_WR_TPEC: 1796 + if ((level != IBMACPI_FAN_EC_AUTO) && 1797 + (level != IBMACPI_FAN_EC_DISENGAGED) && 1798 + ((level < 0) || (level > 7))) 1799 + return -EINVAL; 1800 + 1801 + if (!acpi_ec_write(fan_status_offset, level)) 1802 + return -EIO; 1803 + else 1804 + fan_control_status_known = 1; 1805 + break; 1806 + 1807 + default: 1808 + return -ENXIO; 1809 + } 1810 + return 0; 1811 + } 1812 + 1813 + static int fan_set_enable(void) 1814 + { 1815 + u8 s; 1816 + int rc; 1817 + 1818 + switch (fan_control_access_mode) { 1819 + case IBMACPI_FAN_WR_ACPI_FANS: 1820 + case IBMACPI_FAN_WR_TPEC: 1821 + if ((rc = fan_get_status(&s)) < 0) 1822 + return rc; 1823 + 1824 + /* Don't go out of emergency fan mode */ 1825 + if (s != 7) 1826 + s = IBMACPI_FAN_EC_AUTO; 1827 + 1828 + if (!acpi_ec_write(fan_status_offset, s)) 1829 + return -EIO; 1830 + else 1831 + fan_control_status_known = 1; 1832 + break; 1833 + 1834 + case IBMACPI_FAN_WR_ACPI_SFAN: 1835 + if ((rc = fan_get_status(&s)) < 0) 1836 + return rc; 1837 + 1838 + s &= 0x07; 1839 + 1840 + /* Set fan to at least level 4 */ 1841 + if (s < 4) 1842 + s = 4; 1843 + 1844 + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) 1845 + return -EIO; 1846 + break; 1847 + 1848 + default: 1849 + return -ENXIO; 1850 + } 1851 + return 0; 1852 + } 1853 + 1854 + static int fan_set_disable(void) 1855 + { 1856 + switch (fan_control_access_mode) { 1857 + case IBMACPI_FAN_WR_ACPI_FANS: 1858 + case IBMACPI_FAN_WR_TPEC: 1859 + if (!acpi_ec_write(fan_status_offset, 0x00)) 1860 + return -EIO; 1861 + else 1862 + fan_control_status_known = 1; 1863 + break; 1864 + 1865 + case IBMACPI_FAN_WR_ACPI_SFAN: 1866 + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) 1867 + return -EIO; 1868 + break; 1869 + 1870 + default: 1871 + return -ENXIO; 1872 + } 1873 + return 0; 1874 + } 1875 + 1876 + static int fan_set_speed(int speed) 1877 + { 1878 + switch (fan_control_access_mode) { 1879 + case IBMACPI_FAN_WR_ACPI_FANS: 1880 + if (speed >= 0 && speed <= 65535) { 1891 1881 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", 1892 1882 speed, speed, speed)) 1893 1883 return -EIO; 1894 1884 } else 1895 1885 return -EINVAL; 1886 + break; 1887 + 1888 + default: 1889 + return -ENXIO; 1890 + } 1891 + return 0; 1892 + } 1893 + 1894 + static int fan_write_cmd_level(const char *cmd, int *rc) 1895 + { 1896 + int level; 1897 + 1898 + if (strlencmp(cmd, "level auto") == 0) 1899 + level = IBMACPI_FAN_EC_AUTO; 1900 + else if (strlencmp(cmd, "level disengaged") == 0) 1901 + level = IBMACPI_FAN_EC_DISENGAGED; 1902 + else if (sscanf(cmd, "level %d", &level) != 1) 1903 + return 0; 1904 + 1905 + if ((*rc = fan_set_level(level)) == -ENXIO) 1906 + printk(IBM_ERR "level command accepted for unsupported " 1907 + "access mode %d", fan_control_access_mode); 1908 + 1909 + return 1; 1910 + } 1911 + 1912 + static int fan_write_cmd_enable(const char *cmd, int *rc) 1913 + { 1914 + if (strlencmp(cmd, "enable") != 0) 1915 + return 0; 1916 + 1917 + if ((*rc = fan_set_enable()) == -ENXIO) 1918 + printk(IBM_ERR "enable command accepted for unsupported " 1919 + "access mode %d", fan_control_access_mode); 1920 + 1921 + return 1; 1922 + } 1923 + 1924 + static int fan_write_cmd_disable(const char *cmd, int *rc) 1925 + { 1926 + if (strlencmp(cmd, "disable") != 0) 1927 + return 0; 1928 + 1929 + if ((*rc = fan_set_disable()) == -ENXIO) 1930 + printk(IBM_ERR "disable command accepted for unsupported " 1931 + "access mode %d", fan_control_access_mode); 1932 + 1933 + return 1; 1934 + } 1935 + 1936 + static int fan_write_cmd_speed(const char *cmd, int *rc) 1937 + { 1938 + int speed; 1939 + 1940 + /* TODO: 1941 + * Support speed <low> <medium> <high> ? */ 1942 + 1943 + if (sscanf(cmd, "speed %d", &speed) != 1) 1944 + return 0; 1945 + 1946 + if ((*rc = fan_set_speed(speed)) == -ENXIO) 1947 + printk(IBM_ERR "speed command accepted for unsupported " 1948 + "access mode %d", fan_control_access_mode); 1949 + 1950 + return 1; 1951 + } 1952 + 1953 + static int fan_write_cmd_watchdog(const char *cmd, int *rc) 1954 + { 1955 + int interval; 1956 + 1957 + if (sscanf(cmd, "watchdog %d", &interval) != 1) 1958 + return 0; 1959 + 1960 + if (interval < 0 || interval > 120) 1961 + *rc = -EINVAL; 1962 + else 1963 + fan_watchdog_maxinterval = interval; 1964 + 1965 + return 1; 1966 + } 1967 + 1968 + static int fan_write(char *buf) 1969 + { 1970 + char *cmd; 1971 + int rc = 0; 1972 + 1973 + while (!rc && (cmd = next_cmd(&buf))) { 1974 + if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) && 1975 + fan_write_cmd_level(cmd, &rc)) && 1976 + !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) && 1977 + (fan_write_cmd_enable(cmd, &rc) || 1978 + fan_write_cmd_disable(cmd, &rc) || 1979 + fan_write_cmd_watchdog(cmd, &rc))) && 1980 + !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) && 1981 + fan_write_cmd_speed(cmd, &rc)) 1982 + ) 1983 + rc = -EINVAL; 1984 + else if (!rc) 1985 + fan_watchdog_reset(); 1896 1986 } 1897 1987 1898 - return 0; 1988 + return rc; 1989 + } 1990 + 1991 + static void fan_watchdog_fire(void *ignored) 1992 + { 1993 + printk(IBM_NOTICE "fan watchdog: enabling fan\n"); 1994 + if (fan_set_enable()) { 1995 + printk(IBM_ERR "fan watchdog: error while enabling fan\n"); 1996 + /* reschedule for later */ 1997 + fan_watchdog_reset(); 1998 + } 1899 1999 } 1900 2000 1901 2001 static struct ibm_struct ibms[] = { ··· 2354 1662 .type = ACPI_SYSTEM_NOTIFY, 2355 1663 }, 2356 1664 #endif 1665 + #ifdef CONFIG_ACPI_IBM_BAY 2357 1666 { 2358 1667 .name = "bay", 2359 1668 .init = bay_init, ··· 2364 1671 .handle = &bay_handle, 2365 1672 .type = ACPI_SYSTEM_NOTIFY, 2366 1673 }, 1674 + #endif 2367 1675 { 2368 1676 .name = "cmos", 2369 1677 .read = cmos_read, ··· 2396 1702 .name = "brightness", 2397 1703 .read = brightness_read, 2398 1704 .write = brightness_write, 1705 + .init = brightness_init, 1706 + .exit = brightness_exit, 2399 1707 }, 2400 1708 { 2401 1709 .name = "volume", ··· 2408 1712 .name = "fan", 2409 1713 .read = fan_read, 2410 1714 .write = fan_write, 1715 + .init = fan_init, 1716 + .exit = fan_exit, 2411 1717 .experimental = 1, 2412 1718 }, 2413 1719 }; ··· 2523 1825 } 2524 1826 2525 1827 memset(ibm->driver, 0, sizeof(struct acpi_driver)); 2526 - sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name); 1828 + sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name); 2527 1829 ibm->driver->ids = ibm->hid; 2528 1830 ibm->driver->ops.add = &ibm_device_add; 2529 1831 ··· 2652 1954 #ifdef CONFIG_ACPI_IBM_DOCK 2653 1955 IBM_PARAM(dock); 2654 1956 #endif 1957 + #ifdef CONFIG_ACPI_IBM_BAY 2655 1958 IBM_PARAM(bay); 1959 + #endif 2656 1960 IBM_PARAM(cmos); 2657 1961 IBM_PARAM(led); 2658 1962 IBM_PARAM(beep); ··· 2671 1971 ibm_exit(&ibms[i]); 2672 1972 2673 1973 remove_proc_entry(IBM_DIR, acpi_root_dir); 1974 + 1975 + if (ibm_thinkpad_ec_found) 1976 + kfree(ibm_thinkpad_ec_found); 1977 + } 1978 + 1979 + static char* __init check_dmi_for_ec(void) 1980 + { 1981 + struct dmi_device *dev = NULL; 1982 + char ec_fw_string[18]; 1983 + 1984 + /* 1985 + * ThinkPad T23 or newer, A31 or newer, R50e or newer, 1986 + * X32 or newer, all Z series; Some models must have an 1987 + * up-to-date BIOS or they will not be detected. 1988 + * 1989 + * See http://thinkwiki.org/wiki/List_of_DMI_IDs 1990 + */ 1991 + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { 1992 + if (sscanf(dev->name, 1993 + "IBM ThinkPad Embedded Controller -[%17c", 1994 + ec_fw_string) == 1) { 1995 + ec_fw_string[sizeof(ec_fw_string) - 1] = 0; 1996 + ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; 1997 + return kstrdup(ec_fw_string, GFP_KERNEL); 1998 + } 1999 + } 2000 + return NULL; 2674 2001 } 2675 2002 2676 2003 static int __init acpi_ibm_init(void) ··· 2719 1992 return -ENODEV; 2720 1993 } 2721 1994 1995 + /* Models with newer firmware report the EC in DMI */ 1996 + ibm_thinkpad_ec_found = check_dmi_for_ec(); 1997 + if (ibm_thinkpad_ec_found) 1998 + printk(IBM_INFO "ThinkPad EC firmware %s\n", 1999 + ibm_thinkpad_ec_found); 2000 + 2722 2001 /* these handles are not required */ 2723 2002 IBM_HANDLE_INIT(vid); 2724 2003 IBM_HANDLE_INIT(vid2); ··· 2737 2004 IBM_HANDLE_INIT(dock); 2738 2005 #endif 2739 2006 IBM_HANDLE_INIT(pci); 2007 + #ifdef CONFIG_ACPI_IBM_BAY 2740 2008 IBM_HANDLE_INIT(bay); 2741 2009 if (bay_handle) 2742 2010 IBM_HANDLE_INIT(bay_ej); 2743 2011 IBM_HANDLE_INIT(bay2); 2744 2012 if (bay2_handle) 2745 2013 IBM_HANDLE_INIT(bay2_ej); 2014 + #endif 2746 2015 IBM_HANDLE_INIT(beep); 2747 2016 IBM_HANDLE_INIT(ecrd); 2748 2017 IBM_HANDLE_INIT(ecwr);
+65 -23
drivers/acpi/toshiba_acpi.c
··· 41 41 #include <linux/init.h> 42 42 #include <linux/types.h> 43 43 #include <linux/proc_fs.h> 44 + #include <linux/backlight.h> 45 + 44 46 #include <asm/uaccess.h> 45 47 46 48 #include <acpi/acpi_drivers.h> ··· 212 210 } 213 211 214 212 static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; 213 + static struct backlight_device *toshiba_backlight_device; 215 214 static int force_fan; 216 215 static int last_key_event; 217 216 static int key_event_valid; ··· 274 271 return result; 275 272 } 276 273 277 - static char *read_lcd(char *p) 274 + static int get_lcd(struct backlight_device *bd) 278 275 { 279 276 u32 hci_result; 280 277 u32 value; 281 278 282 279 hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result); 283 280 if (hci_result == HCI_SUCCESS) { 284 - value = value >> HCI_LCD_BRIGHTNESS_SHIFT; 281 + return (value >> HCI_LCD_BRIGHTNESS_SHIFT); 282 + } else 283 + return -EFAULT; 284 + } 285 + 286 + static char *read_lcd(char *p) 287 + { 288 + int value = get_lcd(NULL); 289 + 290 + if (value >= 0) { 285 291 p += sprintf(p, "brightness: %d\n", value); 286 292 p += sprintf(p, "brightness_levels: %d\n", 287 293 HCI_LCD_BRIGHTNESS_LEVELS); ··· 301 289 return p; 302 290 } 303 291 292 + static int set_lcd(int value) 293 + { 294 + u32 hci_result; 295 + 296 + value = value << HCI_LCD_BRIGHTNESS_SHIFT; 297 + hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result); 298 + if (hci_result != HCI_SUCCESS) 299 + return -EFAULT; 300 + 301 + return 0; 302 + } 303 + 304 + static int set_lcd_status(struct backlight_device *bd) 305 + { 306 + return set_lcd(bd->props->brightness); 307 + } 308 + 304 309 static unsigned long write_lcd(const char *buffer, unsigned long count) 305 310 { 306 311 int value; 307 - u32 hci_result; 312 + int ret = count; 308 313 309 314 if (sscanf(buffer, " brightness : %i", &value) == 1 && 310 - value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { 311 - value = value << HCI_LCD_BRIGHTNESS_SHIFT; 312 - hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result); 313 - if (hci_result != HCI_SUCCESS) 314 - return -EFAULT; 315 - } else { 316 - return -EINVAL; 317 - } 318 - 319 - return count; 315 + value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) 316 + ret = set_lcd(value); 317 + else 318 + ret = -EINVAL; 319 + return ret; 320 320 } 321 321 322 322 static char *read_video(char *p) ··· 530 506 return AE_OK; 531 507 } 532 508 509 + static struct backlight_properties toshiba_backlight_data = { 510 + .owner = THIS_MODULE, 511 + .get_brightness = get_lcd, 512 + .update_status = set_lcd_status, 513 + .max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1, 514 + }; 515 + 516 + static void __exit toshiba_acpi_exit(void) 517 + { 518 + if (toshiba_backlight_device) 519 + backlight_device_unregister(toshiba_backlight_device); 520 + 521 + remove_device(); 522 + 523 + if (toshiba_proc_dir) 524 + remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 525 + 526 + return; 527 + } 528 + 533 529 static int __init toshiba_acpi_init(void) 534 530 { 535 531 acpi_status status = AE_OK; ··· 590 546 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 591 547 } 592 548 549 + toshiba_backlight_device = backlight_device_register("toshiba", NULL, 550 + &toshiba_backlight_data); 551 + if (IS_ERR(toshiba_backlight_device)) { 552 + printk(KERN_ERR "Could not register toshiba backlight device\n"); 553 + toshiba_backlight_device = NULL; 554 + toshiba_acpi_exit(); 555 + } 556 + 593 557 return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; 594 - } 595 - 596 - static void __exit toshiba_acpi_exit(void) 597 - { 598 - remove_device(); 599 - 600 - if (toshiba_proc_dir) 601 - remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 602 - 603 - return; 604 558 } 605 559 606 560 module_init(toshiba_acpi_init);