aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2006-12-16 00:34:18 -0500
committerLen Brown <len.brown@intel.com>2006-12-16 00:34:18 -0500
commit6bfe5c9d6f4dcaa998f67e691359cf7b1c4b443d (patch)
tree94ee5b1c2b768a584b9bd0fe44382f80f2e4c96b /drivers
parentb361735043e3001eadb1d40916fd1a4fca1a9363 (diff)
parentf9ff43a6268d36acf8df18a76bb881a26a42dc1e (diff)
Pull platform-drivers into test branch
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Kconfig14
-rw-r--r--drivers/acpi/asus_acpi.c62
-rw-r--r--drivers/acpi/ibm_acpi.c1037
-rw-r--r--drivers/acpi/toshiba_acpi.c88
4 files changed, 1011 insertions, 190 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 0ed80122967..b0897a0b206 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -173,6 +173,7 @@ config ACPI_NUMA
173config ACPI_ASUS 173config ACPI_ASUS
174 tristate "ASUS/Medion Laptop Extras" 174 tristate "ASUS/Medion Laptop Extras"
175 depends on X86 175 depends on X86
176 select BACKLIGHT_CLASS_DEVICE
176 ---help--- 177 ---help---
177 This driver provides support for extra features of ACPI-compatible 178 This driver provides support for extra features of ACPI-compatible
178 ASUS laptops. As some of Medion laptops are made by ASUS, it may also 179 ASUS laptops. As some of Medion laptops are made by ASUS, it may also
@@ -201,6 +202,7 @@ config ACPI_ASUS
201config ACPI_IBM 202config ACPI_IBM
202 tristate "IBM ThinkPad Laptop Extras" 203 tristate "IBM ThinkPad Laptop Extras"
203 depends on X86 204 depends on X86
205 select BACKLIGHT_CLASS_DEVICE
204 ---help--- 206 ---help---
205 This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds 207 This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
206 support for Fn-Fx key combinations, Bluetooth control, video 208 support for Fn-Fx key combinations, Bluetooth control, video
@@ -223,9 +225,21 @@ config ACPI_IBM_DOCK
223 225
224 If you are not sure, say N here. 226 If you are not sure, say N here.
225 227
228config ACPI_IBM_BAY
229 bool "Legacy Removable Bay Support"
230 depends on ACPI_IBM
231 depends on ACPI_BAY=n
232 default n
233 ---help---
234 Allows the ibm_acpi driver to handle removable bays.
235 This support is obsoleted by CONFIG_ACPI_BAY.
236
237 If you are not sure, say N here.
238
226config ACPI_TOSHIBA 239config ACPI_TOSHIBA
227 tristate "Toshiba Laptop Extras" 240 tristate "Toshiba Laptop Extras"
228 depends on X86 241 depends on X86
242 select BACKLIGHT_CLASS_DEVICE
229 ---help--- 243 ---help---
230 This driver adds support for access to certain system settings 244 This driver adds support for access to certain system settings
231 on "legacy free" Toshiba laptops. These laptops can be recognized by 245 on "legacy free" Toshiba laptops. These laptops can be recognized by
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index c7ac9297a20..bf7bc25e680 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -35,6 +35,7 @@
35#include <linux/init.h> 35#include <linux/init.h>
36#include <linux/types.h> 36#include <linux/types.h>
37#include <linux/proc_fs.h> 37#include <linux/proc_fs.h>
38#include <linux/backlight.h>
38#include <acpi/acpi_drivers.h> 39#include <acpi/acpi_drivers.h>
39#include <acpi/acpi_bus.h> 40#include <acpi/acpi_bus.h>
40#include <asm/uaccess.h> 41#include <asm/uaccess.h>
@@ -402,6 +403,8 @@ static struct model_data model_conf[END_MODEL] = {
402/* procdir we use */ 403/* procdir we use */
403static struct proc_dir_entry *asus_proc_dir; 404static struct proc_dir_entry *asus_proc_dir;
404 405
406static struct backlight_device *asus_backlight_device;
407
405/* 408/*
406 * This header is made available to allow proper configuration given model, 409 * This header is made available to allow proper configuration given model,
407 * revision number , ... this info cannot go in struct asus_hotk because it is 410 * revision number , ... this info cannot go in struct asus_hotk because it is
@@ -779,7 +782,7 @@ proc_write_lcd(struct file *file, const char __user * buffer,
779 return rv; 782 return rv;
780} 783}
781 784
782static int read_brightness(void) 785static int read_brightness(struct backlight_device *bd)
783{ 786{
784 int value; 787 int value;
785 788
@@ -801,9 +804,10 @@ static int read_brightness(void)
801/* 804/*
802 * Change the brightness level 805 * Change the brightness level
803 */ 806 */
804static void set_brightness(int value) 807static int set_brightness(int value)
805{ 808{
806 acpi_status status = 0; 809 acpi_status status = 0;
810 int ret = 0;
807 811
808 /* SPLV laptop */ 812 /* SPLV laptop */
809 if (hotk->methods->brightness_set) { 813 if (hotk->methods->brightness_set) {
@@ -811,11 +815,12 @@ static void set_brightness(int value)
811 value, NULL)) 815 value, NULL))
812 printk(KERN_WARNING 816 printk(KERN_WARNING
813 "Asus ACPI: Error changing brightness\n"); 817 "Asus ACPI: Error changing brightness\n");
814 return; 818 ret = -EIO;
819 goto out;
815 } 820 }
816 821
817 /* No SPLV method if we are here, act as appropriate */ 822 /* No SPLV method if we are here, act as appropriate */
818 value -= read_brightness(); 823 value -= read_brightness(NULL);
819 while (value != 0) { 824 while (value != 0) {
820 status = acpi_evaluate_object(NULL, (value > 0) ? 825 status = acpi_evaluate_object(NULL, (value > 0) ?
821 hotk->methods->brightness_up : 826 hotk->methods->brightness_up :
@@ -825,15 +830,22 @@ static void set_brightness(int value)
825 if (ACPI_FAILURE(status)) 830 if (ACPI_FAILURE(status))
826 printk(KERN_WARNING 831 printk(KERN_WARNING
827 "Asus ACPI: Error changing brightness\n"); 832 "Asus ACPI: Error changing brightness\n");
833 ret = -EIO;
828 } 834 }
829 return; 835out:
836 return ret;
837}
838
839static int set_brightness_status(struct backlight_device *bd)
840{
841 return set_brightness(bd->props->brightness);
830} 842}
831 843
832static int 844static int
833proc_read_brn(char *page, char **start, off_t off, int count, int *eof, 845proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
834 void *data) 846 void *data)
835{ 847{
836 return sprintf(page, "%d\n", read_brightness()); 848 return sprintf(page, "%d\n", read_brightness(NULL));
837} 849}
838 850
839static int 851static int
@@ -1333,6 +1345,26 @@ static int asus_hotk_remove(struct acpi_device *device, int type)
1333 return 0; 1345 return 0;
1334} 1346}
1335 1347
1348static struct backlight_properties asus_backlight_data = {
1349 .owner = THIS_MODULE,
1350 .get_brightness = read_brightness,
1351 .update_status = set_brightness_status,
1352 .max_brightness = 15,
1353};
1354
1355static void __exit asus_acpi_exit(void)
1356{
1357 if (asus_backlight_device)
1358 backlight_device_unregister(asus_backlight_device);
1359
1360 acpi_bus_unregister_driver(&asus_hotk_driver);
1361 remove_proc_entry(PROC_ASUS, acpi_root_dir);
1362
1363 kfree(asus_info);
1364
1365 return;
1366}
1367
1336static int __init asus_acpi_init(void) 1368static int __init asus_acpi_init(void)
1337{ 1369{
1338 int result; 1370 int result;
@@ -1370,17 +1402,15 @@ static int __init asus_acpi_init(void)
1370 return result; 1402 return result;
1371 } 1403 }
1372 1404
1373 return 0; 1405 asus_backlight_device = backlight_device_register("asus", NULL,
1374} 1406 &asus_backlight_data);
1375 1407 if (IS_ERR(asus_backlight_device)) {
1376static void __exit asus_acpi_exit(void) 1408 printk(KERN_ERR "Could not register asus backlight device\n");
1377{ 1409 asus_backlight_device = NULL;
1378 acpi_bus_unregister_driver(&asus_hotk_driver); 1410 asus_acpi_exit();
1379 remove_proc_entry(PROC_ASUS, acpi_root_dir); 1411 }
1380
1381 kfree(asus_info);
1382 1412
1383 return; 1413 return 0;
1384} 1414}
1385 1415
1386module_init(asus_acpi_init); 1416module_init(asus_acpi_init);
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 003a9876c96..92e7b6eb8f1 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * 4 *
5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> 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 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -19,10 +20,14 @@
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 21 */
21 22
22#define IBM_VERSION "0.12a" 23#define IBM_VERSION "0.13"
23 24
24/* 25/*
25 * Changelog: 26 * Changelog:
27 *
28 * 2006-11-22 0.13 new maintainer
29 * changelog now lives in git commit history, and will
30 * not be updated further in-file.
26 * 31 *
27 * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels 32 * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
28 * 2005-03-17 0.11 support for 600e, 770x 33 * 2005-03-17 0.11 support for 600e, 770x
@@ -77,9 +82,16 @@
77#include <linux/module.h> 82#include <linux/module.h>
78#include <linux/init.h> 83#include <linux/init.h>
79#include <linux/types.h> 84#include <linux/types.h>
85#include <linux/string.h>
86
80#include <linux/proc_fs.h> 87#include <linux/proc_fs.h>
88#include <linux/backlight.h>
81#include <asm/uaccess.h> 89#include <asm/uaccess.h>
82 90
91#include <linux/dmi.h>
92#include <linux/jiffies.h>
93#include <linux/workqueue.h>
94
83#include <acpi/acpi_drivers.h> 95#include <acpi/acpi_drivers.h>
84#include <acpi/acnamesp.h> 96#include <acpi/acnamesp.h>
85 97
@@ -88,7 +100,7 @@
88#define IBM_FILE "ibm_acpi" 100#define IBM_FILE "ibm_acpi"
89#define IBM_URL "http://ibm-acpi.sf.net/" 101#define IBM_URL "http://ibm-acpi.sf.net/"
90 102
91MODULE_AUTHOR("Borislav Deianov"); 103MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
92MODULE_DESCRIPTION(IBM_DESC); 104MODULE_DESCRIPTION(IBM_DESC);
93MODULE_VERSION(IBM_VERSION); 105MODULE_VERSION(IBM_VERSION);
94MODULE_LICENSE("GPL"); 106MODULE_LICENSE("GPL");
@@ -116,28 +128,6 @@ static acpi_handle root_handle = NULL;
116 static char *object##_path; \ 128 static char *object##_path; \
117 static char *object##_paths[] = { paths } 129 static char *object##_paths[] = { paths }
118 130
119/*
120 * The following models are supported to various degrees:
121 *
122 * 570, 600e, 600x, 770e, 770x
123 * A20m, A21e, A21m, A21p, A22p, A30, A30p, A31, A31p
124 * G40, G41
125 * R30, R31, R32, R40, R40e, R50, R50e, R50p, R51
126 * T20, T21, T22, T23, T30, T40, T40p, T41, T41p, T42, T42p, T43
127 * X20, X21, X22, X23, X24, X30, X31, X40
128 *
129 * The following models have no supported features:
130 *
131 * 240, 240x, i1400
132 *
133 * Still missing DSDTs for the following models:
134 *
135 * A20p, A22e, A22m
136 * R52
137 * S31
138 * T43p
139 */
140
141IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ 131IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
142 "\\_SB.PCI.ISA.EC", /* 570 */ 132 "\\_SB.PCI.ISA.EC", /* 570 */
143 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ 133 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
@@ -167,8 +157,10 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
167 "\\_SB.PCI.ISA.SLCE", /* 570 */ 157 "\\_SB.PCI.ISA.SLCE", /* 570 */
168 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ 158 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
169#endif 159#endif
160#ifdef CONFIG_ACPI_IBM_BAY
170IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ 161IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
171 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ 162 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
163 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
172 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ 164 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
173 ); /* A21e, R30, R31 */ 165 ); /* A21e, R30, R31 */
174 166
@@ -183,6 +175,7 @@ IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
183IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ 175IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
184 "_EJ0", /* 770x */ 176 "_EJ0", /* 770x */
185 ); /* all others */ 177 ); /* all others */
178#endif
186 179
187/* don't list other alternatives as we install a notify handler on the 570 */ 180/* don't list other alternatives as we install a notify handler on the 570 */
188IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ 181IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
@@ -203,7 +196,7 @@ IBM_HANDLE(led, ec, "SLED", /* 570 */
203IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ 196IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
204IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ 197IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
205IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ 198IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
206IBM_HANDLE(fans, ec, "FANS"); /* X31, X40 */ 199IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
207 200
208IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ 201IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
209 "\\FSPD", /* 600e/x, 770e, 770x */ 202 "\\FSPD", /* 600e/x, 770e, 770x */
@@ -216,6 +209,152 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
216#define IBM_HKEY_HID "IBM0068" 209#define IBM_HKEY_HID "IBM0068"
217#define IBM_PCI_HID "PNP0A03" 210#define IBM_PCI_HID "PNP0A03"
218 211
212enum thermal_access_mode {
213 IBMACPI_THERMAL_NONE = 0, /* No thermal support */
214 IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
215 IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
216 IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
217 IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
218};
219
220#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
221struct ibm_thermal_sensors_struct {
222 s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
223};
224
225/*
226 * FAN ACCESS MODES
227 *
228 * IBMACPI_FAN_RD_ACPI_GFAN:
229 * ACPI GFAN method: returns fan level
230 *
231 * see IBMACPI_FAN_WR_ACPI_SFAN
232 * EC 0x2f not available if GFAN exists
233 *
234 * IBMACPI_FAN_WR_ACPI_SFAN:
235 * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
236 *
237 * EC 0x2f might be available *for reading*, but never for writing.
238 *
239 * IBMACPI_FAN_WR_TPEC:
240 * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
241 * on almost all ThinkPads
242 *
243 * Fan speed changes of any sort (including those caused by the
244 * disengaged mode) are usually done slowly by the firmware as the
245 * maximum ammount of fan duty cycle change per second seems to be
246 * limited.
247 *
248 * Reading is not available if GFAN exists.
249 * Writing is not available if SFAN exists.
250 *
251 * Bits
252 * 7 automatic mode engaged;
253 * (default operation mode of the ThinkPad)
254 * fan level is ignored in this mode.
255 * 6 disengage mode (takes precedence over bit 7);
256 * not available on all thinkpads. May disable
257 * the tachometer, and speeds up fan to 100% duty-cycle,
258 * which speeds it up far above the standard RPM
259 * levels. It is not impossible that it could cause
260 * hardware damage.
261 * 5-3 unused in some models. Extra bits for fan level
262 * in others, but still useless as all values above
263 * 7 map to the same speed as level 7 in these models.
264 * 2-0 fan level (0..7 usually)
265 * 0x00 = stop
266 * 0x07 = max (set when temperatures critical)
267 * Some ThinkPads may have other levels, see
268 * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
269 *
270 * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
271 * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
272 * does so, its initial value is meaningless (0x07).
273 *
274 * For firmware bugs, refer to:
275 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
276 *
277 * ----
278 *
279 * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
280 * Main fan tachometer reading (in RPM)
281 *
282 * This register is present on all ThinkPads with a new-style EC, and
283 * it is known not to be present on the A21m/e, and T22, as there is
284 * something else in offset 0x84 according to the ACPI DSDT. Other
285 * ThinkPads from this same time period (and earlier) probably lack the
286 * tachometer as well.
287 *
288 * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
289 * was never fixed by IBM to report the EC firmware version string
290 * probably support the tachometer (like the early X models), so
291 * detecting it is quite hard. We need more data to know for sure.
292 *
293 * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
294 * might result.
295 *
296 * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
297 * register is not invalidated in ThinkPads that disable tachometer
298 * readings. Thus, the tachometer readings go stale.
299 *
300 * For firmware bugs, refer to:
301 * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
302 *
303 * IBMACPI_FAN_WR_ACPI_FANS:
304 * ThinkPad X31, X40, X41. Not available in the X60.
305 *
306 * FANS ACPI handle: takes three arguments: low speed, medium speed,
307 * high speed. ACPI DSDT seems to map these three speeds to levels
308 * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
309 * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
310 *
311 * The speeds are stored on handles
312 * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
313 *
314 * There are three default speed sets, acessible as handles:
315 * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
316 *
317 * ACPI DSDT switches which set is in use depending on various
318 * factors.
319 *
320 * IBMACPI_FAN_WR_TPEC is also available and should be used to
321 * command the fan. The X31/X40/X41 seems to have 8 fan levels,
322 * but the ACPI tables just mention level 7.
323 */
324
325enum fan_status_access_mode {
326 IBMACPI_FAN_NONE = 0, /* No fan status or control */
327 IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
328 IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
329};
330
331enum fan_control_access_mode {
332 IBMACPI_FAN_WR_NONE = 0, /* No fan control */
333 IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
334 IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
335 IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
336};
337
338enum fan_control_commands {
339 IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
340 IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
341 IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
342 * and also watchdog cmd */
343};
344
345enum { /* Fan control constants */
346 fan_status_offset = 0x2f, /* EC register 0x2f */
347 fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
348 * 0x84 must be read before 0x85 */
349
350 IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer
351 * disengaged */
352 IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan
353 * control */
354};
355
356static char *ibm_thinkpad_ec_found = NULL;
357
219struct ibm_struct { 358struct ibm_struct {
220 char *name; 359 char *name;
221 char param[32]; 360 char param[32];
@@ -243,6 +382,8 @@ struct ibm_struct {
243 382
244static struct proc_dir_entry *proc_dir = NULL; 383static struct proc_dir_entry *proc_dir = NULL;
245 384
385static struct backlight_device *ibm_backlight_device = NULL;
386
246#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") 387#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
247#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") 388#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
248#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) 389#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -581,8 +722,7 @@ static int wan_status(void)
581{ 722{
582 int status; 723 int status;
583 724
584 if (!wan_supported || 725 if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
585 !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
586 status = 0; 726 status = 0;
587 727
588 return status; 728 return status;
@@ -630,12 +770,15 @@ static int wan_write(char *buf)
630 return 0; 770 return 0;
631} 771}
632 772
633static int video_supported; 773enum video_access_mode {
634static int video_orig_autosw; 774 IBMACPI_VIDEO_NONE = 0,
775 IBMACPI_VIDEO_570, /* 570 */
776 IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */
777 IBMACPI_VIDEO_NEW, /* all others */
778};
635 779
636#define VIDEO_570 1 780static enum video_access_mode video_supported;
637#define VIDEO_770 2 781static int video_orig_autosw;
638#define VIDEO_NEW 3
639 782
640static int video_init(void) 783static int video_init(void)
641{ 784{
@@ -647,16 +790,16 @@ static int video_init(void)
647 790
648 if (!vid_handle) 791 if (!vid_handle)
649 /* video switching not supported on R30, R31 */ 792 /* video switching not supported on R30, R31 */
650 video_supported = 0; 793 video_supported = IBMACPI_VIDEO_NONE;
651 else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) 794 else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
652 /* 570 */ 795 /* 570 */
653 video_supported = VIDEO_570; 796 video_supported = IBMACPI_VIDEO_570;
654 else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) 797 else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
655 /* 600e/x, 770e, 770x */ 798 /* 600e/x, 770e, 770x */
656 video_supported = VIDEO_770; 799 video_supported = IBMACPI_VIDEO_770;
657 else 800 else
658 /* all others */ 801 /* all others */
659 video_supported = VIDEO_NEW; 802 video_supported = IBMACPI_VIDEO_NEW;
660 803
661 return 0; 804 return 0;
662} 805}
@@ -666,15 +809,15 @@ static int video_status(void)
666 int status = 0; 809 int status = 0;
667 int i; 810 int i;
668 811
669 if (video_supported == VIDEO_570) { 812 if (video_supported == IBMACPI_VIDEO_570) {
670 if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87)) 813 if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
671 status = i & 3; 814 status = i & 3;
672 } else if (video_supported == VIDEO_770) { 815 } else if (video_supported == IBMACPI_VIDEO_770) {
673 if (acpi_evalf(NULL, &i, "\\VCDL", "d")) 816 if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
674 status |= 0x01 * i; 817 status |= 0x01 * i;
675 if (acpi_evalf(NULL, &i, "\\VCDC", "d")) 818 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
676 status |= 0x02 * i; 819 status |= 0x02 * i;
677 } else if (video_supported == VIDEO_NEW) { 820 } else if (video_supported == IBMACPI_VIDEO_NEW) {
678 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1); 821 acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
679 if (acpi_evalf(NULL, &i, "\\VCDC", "d")) 822 if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
680 status |= 0x02 * i; 823 status |= 0x02 * i;
@@ -693,9 +836,10 @@ static int video_autosw(void)
693{ 836{
694 int autosw = 0; 837 int autosw = 0;
695 838
696 if (video_supported == VIDEO_570) 839 if (video_supported == IBMACPI_VIDEO_570)
697 acpi_evalf(vid_handle, &autosw, "SWIT", "d"); 840 acpi_evalf(vid_handle, &autosw, "SWIT", "d");
698 else if (video_supported == VIDEO_770 || video_supported == VIDEO_NEW) 841 else if (video_supported == IBMACPI_VIDEO_770 ||
842 video_supported == IBMACPI_VIDEO_NEW)
699 acpi_evalf(vid_handle, &autosw, "^VDEE", "d"); 843 acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
700 844
701 return autosw & 1; 845 return autosw & 1;
@@ -715,12 +859,12 @@ static int video_read(char *p)
715 len += sprintf(p + len, "status:\t\tsupported\n"); 859 len += sprintf(p + len, "status:\t\tsupported\n");
716 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); 860 len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
717 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); 861 len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
718 if (video_supported == VIDEO_NEW) 862 if (video_supported == IBMACPI_VIDEO_NEW)
719 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); 863 len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
720 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); 864 len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
721 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); 865 len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
722 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); 866 len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
723 if (video_supported == VIDEO_NEW) 867 if (video_supported == IBMACPI_VIDEO_NEW)
724 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); 868 len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
725 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); 869 len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
726 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); 870 len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
@@ -735,7 +879,7 @@ static int video_switch(void)
735 879
736 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) 880 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
737 return -EIO; 881 return -EIO;
738 ret = video_supported == VIDEO_570 ? 882 ret = video_supported == IBMACPI_VIDEO_570 ?
739 acpi_evalf(ec_handle, NULL, "_Q16", "v") : 883 acpi_evalf(ec_handle, NULL, "_Q16", "v") :
740 acpi_evalf(vid_handle, NULL, "VSWT", "v"); 884 acpi_evalf(vid_handle, NULL, "VSWT", "v");
741 acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); 885 acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
@@ -745,9 +889,9 @@ static int video_switch(void)
745 889
746static int video_expand(void) 890static int video_expand(void)
747{ 891{
748 if (video_supported == VIDEO_570) 892 if (video_supported == IBMACPI_VIDEO_570)
749 return acpi_evalf(ec_handle, NULL, "_Q17", "v"); 893 return acpi_evalf(ec_handle, NULL, "_Q17", "v");
750 else if (video_supported == VIDEO_770) 894 else if (video_supported == IBMACPI_VIDEO_770)
751 return acpi_evalf(vid_handle, NULL, "VEXP", "v"); 895 return acpi_evalf(vid_handle, NULL, "VEXP", "v");
752 else 896 else
753 return acpi_evalf(NULL, NULL, "\\VEXP", "v"); 897 return acpi_evalf(NULL, NULL, "\\VEXP", "v");
@@ -757,10 +901,10 @@ static int video_switch2(int status)
757{ 901{
758 int ret; 902 int ret;
759 903
760 if (video_supported == VIDEO_570) { 904 if (video_supported == IBMACPI_VIDEO_570) {
761 ret = acpi_evalf(NULL, NULL, 905 ret = acpi_evalf(NULL, NULL,
762 "\\_SB.PHS2", "vdd", 0x8b, status | 0x80); 906 "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
763 } else if (video_supported == VIDEO_770) { 907 } else if (video_supported == IBMACPI_VIDEO_770) {
764 int autosw = video_autosw(); 908 int autosw = video_autosw();
765 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) 909 if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
766 return -EIO; 910 return -EIO;
@@ -796,10 +940,10 @@ static int video_write(char *buf)
796 enable |= 0x02; 940 enable |= 0x02;
797 } else if (strlencmp(cmd, "crt_disable") == 0) { 941 } else if (strlencmp(cmd, "crt_disable") == 0) {
798 disable |= 0x02; 942 disable |= 0x02;
799 } else if (video_supported == VIDEO_NEW && 943 } else if (video_supported == IBMACPI_VIDEO_NEW &&
800 strlencmp(cmd, "dvi_enable") == 0) { 944 strlencmp(cmd, "dvi_enable") == 0) {
801 enable |= 0x08; 945 enable |= 0x08;
802 } else if (video_supported == VIDEO_NEW && 946 } else if (video_supported == IBMACPI_VIDEO_NEW &&
803 strlencmp(cmd, "dvi_disable") == 0) { 947 strlencmp(cmd, "dvi_disable") == 0) {
804 disable |= 0x08; 948 disable |= 0x08;
805 } else if (strlencmp(cmd, "auto_enable") == 0) { 949 } else if (strlencmp(cmd, "auto_enable") == 0) {
@@ -898,6 +1042,7 @@ static int light_write(char *buf)
898 return 0; 1042 return 0;
899} 1043}
900 1044
1045#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
901static int _sta(acpi_handle handle) 1046static int _sta(acpi_handle handle)
902{ 1047{
903 int status; 1048 int status;
@@ -907,6 +1052,7 @@ static int _sta(acpi_handle handle)
907 1052
908 return status; 1053 return status;
909} 1054}
1055#endif
910#ifdef CONFIG_ACPI_IBM_DOCK 1056#ifdef CONFIG_ACPI_IBM_DOCK
911#define dock_docked() (_sta(dock_handle) & 1) 1057#define dock_docked() (_sta(dock_handle) & 1)
912 1058
@@ -972,6 +1118,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event)
972} 1118}
973#endif 1119#endif
974 1120
1121#ifdef CONFIG_ACPI_IBM_BAY
975static int bay_status_supported; 1122static int bay_status_supported;
976static int bay_status2_supported; 1123static int bay_status2_supported;
977static int bay_eject_supported; 1124static int bay_eject_supported;
@@ -1047,6 +1194,7 @@ static void bay_notify(struct ibm_struct *ibm, u32 event)
1047{ 1194{
1048 acpi_bus_generate_event(ibm->device, event, 0); 1195 acpi_bus_generate_event(ibm->device, event, 0);
1049} 1196}
1197#endif
1050 1198
1051static int cmos_read(char *p) 1199static int cmos_read(char *p)
1052{ 1200{
@@ -1094,26 +1242,28 @@ static int cmos_write(char *buf)
1094 return 0; 1242 return 0;
1095} 1243}
1096 1244
1097static int led_supported; 1245enum led_access_mode {
1098 1246 IBMACPI_LED_NONE = 0,
1099#define LED_570 1 1247 IBMACPI_LED_570, /* 570 */
1100#define LED_OLD 2 1248 IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
1101#define LED_NEW 3 1249 IBMACPI_LED_NEW, /* all others */
1250};
1251static enum led_access_mode led_supported;
1102 1252
1103static int led_init(void) 1253static int led_init(void)
1104{ 1254{
1105 if (!led_handle) 1255 if (!led_handle)
1106 /* led not supported on R30, R31 */ 1256 /* led not supported on R30, R31 */
1107 led_supported = 0; 1257 led_supported = IBMACPI_LED_NONE;
1108 else if (strlencmp(led_path, "SLED") == 0) 1258 else if (strlencmp(led_path, "SLED") == 0)
1109 /* 570 */ 1259 /* 570 */
1110 led_supported = LED_570; 1260 led_supported = IBMACPI_LED_570;
1111 else if (strlencmp(led_path, "SYSL") == 0) 1261 else if (strlencmp(led_path, "SYSL") == 0)
1112 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ 1262 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
1113 led_supported = LED_OLD; 1263 led_supported = IBMACPI_LED_OLD;
1114 else 1264 else
1115 /* all others */ 1265 /* all others */
1116 led_supported = LED_NEW; 1266 led_supported = IBMACPI_LED_NEW;
1117 1267
1118 return 0; 1268 return 0;
1119} 1269}
@@ -1130,7 +1280,7 @@ static int led_read(char *p)
1130 } 1280 }
1131 len += sprintf(p + len, "status:\t\tsupported\n"); 1281 len += sprintf(p + len, "status:\t\tsupported\n");
1132 1282
1133 if (led_supported == LED_570) { 1283 if (led_supported == IBMACPI_LED_570) {
1134 /* 570 */ 1284 /* 570 */
1135 int i, status; 1285 int i, status;
1136 for (i = 0; i < 8; i++) { 1286 for (i = 0; i < 8; i++) {
@@ -1179,13 +1329,13 @@ static int led_write(char *buf)
1179 } else 1329 } else
1180 return -EINVAL; 1330 return -EINVAL;
1181 1331
1182 if (led_supported == LED_570) { 1332 if (led_supported == IBMACPI_LED_570) {
1183 /* 570 */ 1333 /* 570 */
1184 led = 1 << led; 1334 led = 1 << led;
1185 if (!acpi_evalf(led_handle, NULL, NULL, "vdd", 1335 if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
1186 led, led_sled_arg1[ind])) 1336 led, led_sled_arg1[ind]))
1187 return -EIO; 1337 return -EIO;
1188 } else if (led_supported == LED_OLD) { 1338 } else if (led_supported == IBMACPI_LED_OLD) {
1189 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ 1339 /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
1190 led = 1 << led; 1340 led = 1 << led;
1191 ret = ec_write(EC_HLMS, led); 1341 ret = ec_write(EC_HLMS, led);
@@ -1272,50 +1422,142 @@ static int acpi_ec_write(int i, u8 v)
1272 return 1; 1422 return 1;
1273} 1423}
1274 1424
1275static int thermal_tmp_supported; 1425static enum thermal_access_mode thermal_read_mode;
1276static int thermal_updt_supported;
1277 1426
1278static int thermal_init(void) 1427static int thermal_init(void)
1279{ 1428{
1280 /* temperatures not supported on 570, G4x, R30, R31, R32 */ 1429 u8 t, ta1, ta2;
1281 thermal_tmp_supported = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); 1430 int i;
1431 int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
1432
1433 if (ibm_thinkpad_ec_found && experimental) {
1434 /*
1435 * Direct EC access mode: sensors at registers
1436 * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
1437 * non-implemented, thermal sensors return 0x80 when
1438 * not available
1439 */
1282 1440
1283 /* 600e/x, 770e, 770x */ 1441 ta1 = ta2 = 0;
1284 thermal_updt_supported = acpi_evalf(ec_handle, NULL, "UPDT", "qv"); 1442 for (i = 0; i < 8; i++) {
1443 if (likely(acpi_ec_read(0x78 + i, &t))) {
1444 ta1 |= t;
1445 } else {
1446 ta1 = 0;
1447 break;
1448 }
1449 if (likely(acpi_ec_read(0xC0 + i, &t))) {
1450 ta2 |= t;
1451 } else {
1452 ta1 = 0;
1453 break;
1454 }
1455 }
1456 if (ta1 == 0) {
1457 /* This is sheer paranoia, but we handle it anyway */
1458 if (acpi_tmp7) {
1459 printk(IBM_ERR
1460 "ThinkPad ACPI EC access misbehaving, "
1461 "falling back to ACPI TMPx access mode\n");
1462 thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
1463 } else {
1464 printk(IBM_ERR
1465 "ThinkPad ACPI EC access misbehaving, "
1466 "disabling thermal sensors access\n");
1467 thermal_read_mode = IBMACPI_THERMAL_NONE;
1468 }
1469 } else {
1470 thermal_read_mode =
1471 (ta2 != 0) ?
1472 IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
1473 }
1474 } else if (acpi_tmp7) {
1475 if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
1476 /* 600e/x, 770e, 770x */
1477 thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
1478 } else {
1479 /* Standard ACPI TMPx access, max 8 sensors */
1480 thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
1481 }
1482 } else {
1483 /* temperatures not supported on 570, G4x, R30, R31, R32 */
1484 thermal_read_mode = IBMACPI_THERMAL_NONE;
1485 }
1285 1486
1286 return 0; 1487 return 0;
1287} 1488}
1288 1489
1289static int thermal_read(char *p) 1490static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
1290{ 1491{
1291 int len = 0; 1492 int i, t;
1493 s8 tmp;
1494 char tmpi[] = "TMPi";
1292 1495
1293 if (!thermal_tmp_supported) 1496 if (!s)
1294 len += sprintf(p + len, "temperatures:\tnot supported\n"); 1497 return -EINVAL;
1295 else {
1296 int i, t;
1297 char tmpi[] = "TMPi";
1298 s8 tmp[8];
1299 1498
1300 if (thermal_updt_supported) 1499 switch (thermal_read_mode) {
1301 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) 1500#if IBMACPI_MAX_THERMAL_SENSORS >= 16
1501 case IBMACPI_THERMAL_TPEC_16:
1502 for (i = 0; i < 8; i++) {
1503 if (!acpi_ec_read(0xC0 + i, &tmp))
1504 return -EIO;
1505 s->temp[i + 8] = tmp * 1000;
1506 }
1507 /* fallthrough */
1508#endif
1509 case IBMACPI_THERMAL_TPEC_8:
1510 for (i = 0; i < 8; i++) {
1511 if (!acpi_ec_read(0x78 + i, &tmp))
1302 return -EIO; 1512 return -EIO;
1513 s->temp[i] = tmp * 1000;
1514 }
1515 return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
1303 1516
1517 case IBMACPI_THERMAL_ACPI_UPDT:
1518 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
1519 return -EIO;
1304 for (i = 0; i < 8; i++) { 1520 for (i = 0; i < 8; i++) {
1305 tmpi[3] = '0' + i; 1521 tmpi[3] = '0' + i;
1306 if (!acpi_evalf(ec_handle, &t, tmpi, "d")) 1522 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
1307 return -EIO; 1523 return -EIO;
1308 if (thermal_updt_supported) 1524 s->temp[i] = (t - 2732) * 100;
1309 tmp[i] = (t - 2732 + 5) / 10;
1310 else
1311 tmp[i] = t;
1312 } 1525 }
1526 return 8;
1313 1527
1314 len += sprintf(p + len, 1528 case IBMACPI_THERMAL_ACPI_TMP07:
1315 "temperatures:\t%d %d %d %d %d %d %d %d\n", 1529 for (i = 0; i < 8; i++) {
1316 tmp[0], tmp[1], tmp[2], tmp[3], 1530 tmpi[3] = '0' + i;
1317 tmp[4], tmp[5], tmp[6], tmp[7]); 1531 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
1532 return -EIO;
1533 s->temp[i] = t * 1000;
1534 }
1535 return 8;
1536
1537 case IBMACPI_THERMAL_NONE:
1538 default:
1539 return 0;
1318 } 1540 }
1541}
1542
1543static int thermal_read(char *p)
1544{
1545 int len = 0;
1546 int n, i;
1547 struct ibm_thermal_sensors_struct t;
1548
1549 n = thermal_get_sensors(&t);
1550 if (unlikely(n < 0))
1551 return n;
1552
1553 len += sprintf(p + len, "temperatures:\t");
1554
1555 if (n > 0) {
1556 for (i = 0; i < (n - 1); i++)
1557 len += sprintf(p + len, "%d ", t.temp[i] / 1000);
1558 len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
1559 } else
1560 len += sprintf(p + len, "not supported\n");
1319 1561
1320 return len; 1562 return len;
1321} 1563}
@@ -1381,12 +1623,23 @@ static int ecdump_write(char *buf)
1381 1623
1382static int brightness_offset = 0x31; 1624static int brightness_offset = 0x31;
1383 1625
1626static int brightness_get(struct backlight_device *bd)
1627{
1628 u8 level;
1629 if (!acpi_ec_read(brightness_offset, &level))
1630 return -EIO;
1631
1632 level &= 0x7;
1633
1634 return level;
1635}
1636
1384static int brightness_read(char *p) 1637static int brightness_read(char *p)
1385{ 1638{
1386 int len = 0; 1639 int len = 0;
1387 u8 level; 1640 int level;
1388 1641
1389 if (!acpi_ec_read(brightness_offset, &level)) { 1642 if ((level = brightness_get(NULL)) < 0) {
1390 len += sprintf(p + len, "level:\t\tunreadable\n"); 1643 len += sprintf(p + len, "level:\t\tunreadable\n");
1391 } else { 1644 } else {
1392 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); 1645 len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
@@ -1401,16 +1654,34 @@ static int brightness_read(char *p)
1401#define BRIGHTNESS_UP 4 1654#define BRIGHTNESS_UP 4
1402#define BRIGHTNESS_DOWN 5 1655#define BRIGHTNESS_DOWN 5
1403 1656
1404static int brightness_write(char *buf) 1657static int brightness_set(int value)
1405{ 1658{
1406 int cmos_cmd, inc, i; 1659 int cmos_cmd, inc, i;
1407 u8 level; 1660 int current_value = brightness_get(NULL);
1661
1662 value &= 7;
1663
1664 cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
1665 inc = value > current_value ? 1 : -1;
1666 for (i = current_value; i != value; i += inc) {
1667 if (!cmos_eval(cmos_cmd))
1668 return -EIO;
1669 if (!acpi_ec_write(brightness_offset, i + inc))
1670 return -EIO;
1671 }
1672
1673 return 0;
1674}
1675
1676static int brightness_write(char *buf)
1677{
1678 int level;
1408 int new_level; 1679 int new_level;
1409 char *cmd; 1680 char *cmd;
1410 1681
1411 while ((cmd = next_cmd(&buf))) { 1682 while ((cmd = next_cmd(&buf))) {
1412 if (!acpi_ec_read(brightness_offset, &level)) 1683 if ((level = brightness_get(NULL)) < 0)
1413 return -EIO; 1684 return level;
1414 level &= 7; 1685 level &= 7;
1415 1686
1416 if (strlencmp(cmd, "up") == 0) { 1687 if (strlencmp(cmd, "up") == 0) {
@@ -1423,19 +1694,44 @@ static int brightness_write(char *buf)
1423 } else 1694 } else
1424 return -EINVAL; 1695 return -EINVAL;
1425 1696
1426 cmos_cmd = new_level > level ? BRIGHTNESS_UP : BRIGHTNESS_DOWN; 1697 brightness_set(new_level);
1427 inc = new_level > level ? 1 : -1;
1428 for (i = level; i != new_level; i += inc) {
1429 if (!cmos_eval(cmos_cmd))
1430 return -EIO;
1431 if (!acpi_ec_write(brightness_offset, i + inc))
1432 return -EIO;
1433 }
1434 } 1698 }
1435 1699
1436 return 0; 1700 return 0;
1437} 1701}
1438 1702
1703static int brightness_update_status(struct backlight_device *bd)
1704{
1705 return brightness_set(bd->props->brightness);
1706}
1707
1708static struct backlight_properties ibm_backlight_data = {
1709 .owner = THIS_MODULE,
1710 .get_brightness = brightness_get,
1711 .update_status = brightness_update_status,
1712 .max_brightness = 7,
1713};
1714
1715static int brightness_init(void)
1716{
1717 ibm_backlight_device = backlight_device_register("ibm", NULL,
1718 &ibm_backlight_data);
1719 if (IS_ERR(ibm_backlight_device)) {
1720 printk(IBM_ERR "Could not register backlight device\n");
1721 return PTR_ERR(ibm_backlight_device);
1722 }
1723
1724 return 0;
1725}
1726
1727static void brightness_exit(void)
1728{
1729 if (ibm_backlight_device) {
1730 backlight_device_unregister(ibm_backlight_device);
1731 ibm_backlight_device = NULL;
1732 }
1733}
1734
1439static int volume_offset = 0x30; 1735static int volume_offset = 0x30;
1440 1736
1441static int volume_read(char *p) 1737static int volume_read(char *p)
@@ -1522,86 +1818,482 @@ static int volume_write(char *buf)
1522 return 0; 1818 return 0;
1523} 1819}
1524 1820
1525static int fan_status_offset = 0x2f; 1821static enum fan_status_access_mode fan_status_access_mode;
1526static int fan_rpm_offset = 0x84; 1822static enum fan_control_access_mode fan_control_access_mode;
1823static enum fan_control_commands fan_control_commands;
1527 1824
1528static int fan_read(char *p) 1825static int fan_control_status_known;
1826static u8 fan_control_initial_status;
1827
1828static void fan_watchdog_fire(void *ignored);
1829static int fan_watchdog_maxinterval;
1830static DECLARE_WORK(fan_watchdog_task, fan_watchdog_fire, NULL);
1831
1832static int fan_init(void)
1529{ 1833{
1530 int len = 0; 1834 fan_status_access_mode = IBMACPI_FAN_NONE;
1531 int s; 1835 fan_control_access_mode = IBMACPI_FAN_WR_NONE;
1532 u8 lo, hi, status; 1836 fan_control_commands = 0;
1837 fan_control_status_known = 1;
1838 fan_watchdog_maxinterval = 0;
1533 1839
1534 if (gfan_handle) { 1840 if (gfan_handle) {
1535 /* 570, 600e/x, 770e, 770x */ 1841 /* 570, 600e/x, 770e, 770x */
1536 if (!acpi_evalf(gfan_handle, &s, NULL, "d")) 1842 fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
1537 return -EIO; 1843 } else {
1844 /* all other ThinkPads: note that even old-style
1845 * ThinkPad ECs supports the fan control register */
1846 if (likely(acpi_ec_read(fan_status_offset,
1847 &fan_control_initial_status))) {
1848 fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
1849
1850 /* In some ThinkPads, neither the EC nor the ACPI
1851 * DSDT initialize the fan status, and it ends up
1852 * being set to 0x07 when it *could* be either
1853 * 0x07 or 0x80.
1854 *
1855 * Enable for TP-1Y (T43), TP-78 (R51e),
1856 * TP-76 (R52), TP-70 (T43, R52), which are known
1857 * to be buggy. */
1858 if (fan_control_initial_status == 0x07 &&
1859 ibm_thinkpad_ec_found &&
1860 ((ibm_thinkpad_ec_found[0] == '1' &&
1861 ibm_thinkpad_ec_found[1] == 'Y') ||
1862 (ibm_thinkpad_ec_found[0] == '7' &&
1863 (ibm_thinkpad_ec_found[1] == '6' ||
1864 ibm_thinkpad_ec_found[1] == '8' ||
1865 ibm_thinkpad_ec_found[1] == '0'))
1866 )) {
1867 printk(IBM_NOTICE
1868 "fan_init: initial fan status is "
1869 "unknown, assuming it is in auto "
1870 "mode\n");
1871 fan_control_status_known = 0;
1872 }
1873 } else {
1874 printk(IBM_ERR
1875 "ThinkPad ACPI EC access misbehaving, "
1876 "fan status and control unavailable\n");
1877 return 0;
1878 }
1879 }
1538 1880
1539 len += sprintf(p + len, "level:\t\t%d\n", s); 1881 if (sfan_handle) {
1882 /* 570, 770x-JL */
1883 fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
1884 fan_control_commands |=
1885 IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE;
1540 } else { 1886 } else {
1887 if (!gfan_handle) {
1888 /* gfan without sfan means no fan control */
1889 /* all other models implement TP EC 0x2f control */
1890
1891 if (fans_handle) {
1892 /* X31, X40, X41 */
1893 fan_control_access_mode =
1894 IBMACPI_FAN_WR_ACPI_FANS;
1895 fan_control_commands |=
1896 IBMACPI_FAN_CMD_SPEED |
1897 IBMACPI_FAN_CMD_LEVEL |
1898 IBMACPI_FAN_CMD_ENABLE;
1899 } else {
1900 fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
1901 fan_control_commands |=
1902 IBMACPI_FAN_CMD_LEVEL |
1903 IBMACPI_FAN_CMD_ENABLE;
1904 }
1905 }
1906 }
1907
1908 return 0;
1909}
1910
1911static int fan_get_status(u8 *status)
1912{
1913 u8 s;
1914
1915 /* TODO:
1916 * Add IBMACPI_FAN_RD_ACPI_FANS ? */
1917
1918 switch (fan_status_access_mode) {
1919 case IBMACPI_FAN_RD_ACPI_GFAN:
1920 /* 570, 600e/x, 770e, 770x */
1921
1922 if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
1923 return -EIO;
1924
1925 if (likely(status))
1926 *status = s & 0x07;
1927
1928 break;
1929
1930 case IBMACPI_FAN_RD_TPEC:
1541 /* all except 570, 600e/x, 770e, 770x */ 1931 /* all except 570, 600e/x, 770e, 770x */
1542 if (!acpi_ec_read(fan_status_offset, &status)) 1932 if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
1543 len += sprintf(p + len, "status:\t\tunreadable\n"); 1933 return -EIO;
1544 else
1545 len += sprintf(p + len, "status:\t\t%s\n",
1546 enabled(status, 7));
1547 1934
1548 if (!acpi_ec_read(fan_rpm_offset, &lo) || 1935 if (likely(status))
1549 !acpi_ec_read(fan_rpm_offset + 1, &hi)) 1936 *status = s;
1550 len += sprintf(p + len, "speed:\t\tunreadable\n"); 1937
1551 else 1938 break;
1552 len += sprintf(p + len, "speed:\t\t%d\n", 1939
1553 (hi << 8) + lo); 1940 default:
1941 return -ENXIO;
1554 } 1942 }
1555 1943
1556 if (sfan_handle) 1944 return 0;
1557 /* 570, 770x-JL */ 1945}
1558 len += sprintf(p + len, "commands:\tlevel <level>" 1946
1559 " (<level> is 0-7)\n"); 1947static int fan_get_speed(unsigned int *speed)
1560 if (!gfan_handle) 1948{
1949 u8 hi, lo;
1950
1951 switch (fan_status_access_mode) {
1952 case IBMACPI_FAN_RD_TPEC:
1561 /* all except 570, 600e/x, 770e, 770x */ 1953 /* all except 570, 600e/x, 770e, 770x */
1562 len += sprintf(p + len, "commands:\tenable, disable\n"); 1954 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
1563 if (fans_handle) 1955 !acpi_ec_read(fan_rpm_offset + 1, &hi)))
1564 /* X31, X40 */ 1956 return -EIO;
1957
1958 if (likely(speed))
1959 *speed = (hi << 8) | lo;
1960
1961 break;
1962
1963 default:
1964 return -ENXIO;
1965 }
1966
1967 return 0;
1968}
1969
1970static void fan_exit(void)
1971{
1972 cancel_delayed_work(&fan_watchdog_task);
1973 flush_scheduled_work();
1974}
1975
1976static void fan_watchdog_reset(void)
1977{
1978 static int fan_watchdog_active = 0;
1979
1980 if (fan_watchdog_active)
1981 cancel_delayed_work(&fan_watchdog_task);
1982
1983 if (fan_watchdog_maxinterval > 0) {
1984 fan_watchdog_active = 1;
1985 if (!schedule_delayed_work(&fan_watchdog_task,
1986 msecs_to_jiffies(fan_watchdog_maxinterval
1987 * 1000))) {
1988 printk(IBM_ERR "failed to schedule the fan watchdog, "
1989 "watchdog will not trigger\n");
1990 }
1991 } else
1992 fan_watchdog_active = 0;
1993}
1994
1995static int fan_read(char *p)
1996{
1997 int len = 0;
1998 int rc;
1999 u8 status;
2000 unsigned int speed = 0;
2001
2002 switch (fan_status_access_mode) {
2003 case IBMACPI_FAN_RD_ACPI_GFAN:
2004 /* 570, 600e/x, 770e, 770x */
2005 if ((rc = fan_get_status(&status)) < 0)
2006 return rc;
2007
2008 len += sprintf(p + len, "status:\t\t%s\n"
2009 "level:\t\t%d\n",
2010 (status != 0) ? "enabled" : "disabled", status);
2011 break;
2012
2013 case IBMACPI_FAN_RD_TPEC:
2014 /* all except 570, 600e/x, 770e, 770x */
2015 if ((rc = fan_get_status(&status)) < 0)
2016 return rc;
2017
2018 if (unlikely(!fan_control_status_known)) {
2019 if (status != fan_control_initial_status)
2020 fan_control_status_known = 1;
2021 else
2022 /* Return most likely status. In fact, it
2023 * might be the only possible status */
2024 status = IBMACPI_FAN_EC_AUTO;
2025 }
2026
2027 len += sprintf(p + len, "status:\t\t%s\n",
2028 (status != 0) ? "enabled" : "disabled");
2029
2030 /* No ThinkPad boots on disengaged mode, we can safely
2031 * assume the tachometer is online if fan control status
2032 * was unknown */
2033 if ((rc = fan_get_speed(&speed)) < 0)
2034 return rc;
2035
2036 len += sprintf(p + len, "speed:\t\t%d\n", speed);
2037
2038 if (status & IBMACPI_FAN_EC_DISENGAGED)
2039 /* Disengaged mode takes precedence */
2040 len += sprintf(p + len, "level:\t\tdisengaged\n");
2041 else if (status & IBMACPI_FAN_EC_AUTO)
2042 len += sprintf(p + len, "level:\t\tauto\n");
2043 else
2044 len += sprintf(p + len, "level:\t\t%d\n", status);
2045 break;
2046
2047 case IBMACPI_FAN_NONE:
2048 default:
2049 len += sprintf(p + len, "status:\t\tnot supported\n");
2050 }
2051
2052 if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
2053 len += sprintf(p + len, "commands:\tlevel <level>");
2054
2055 switch (fan_control_access_mode) {
2056 case IBMACPI_FAN_WR_ACPI_SFAN:
2057 len += sprintf(p + len, " (<level> is 0-7)\n");
2058 break;
2059
2060 default:
2061 len += sprintf(p + len, " (<level> is 0-7, "
2062 "auto, disengaged)\n");
2063 break;
2064 }
2065 }
2066
2067 if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
2068 len += sprintf(p + len, "commands:\tenable, disable\n"
2069 "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
2070 "1-120 (seconds))\n");
2071
2072 if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
1565 len += sprintf(p + len, "commands:\tspeed <speed>" 2073 len += sprintf(p + len, "commands:\tspeed <speed>"
1566 " (<speed> is 0-65535)\n"); 2074 " (<speed> is 0-65535)\n");
1567 2075
1568 return len; 2076 return len;
1569} 2077}
1570 2078
1571static int fan_write(char *buf) 2079static int fan_set_level(int level)
1572{ 2080{
1573 char *cmd; 2081 switch (fan_control_access_mode) {
1574 int level, speed; 2082 case IBMACPI_FAN_WR_ACPI_SFAN:
1575 2083 if (level >= 0 && level <= 7) {
1576 while ((cmd = next_cmd(&buf))) {
1577 if (sfan_handle &&
1578 sscanf(cmd, "level %d", &level) == 1 &&
1579 level >= 0 && level <= 7) {
1580 /* 570, 770x-JL */
1581 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) 2084 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
1582 return -EIO; 2085 return -EIO;
1583 } else if (!gfan_handle && strlencmp(cmd, "enable") == 0) { 2086 } else
1584 /* all except 570, 600e/x, 770e, 770x */ 2087 return -EINVAL;
1585 if (!acpi_ec_write(fan_status_offset, 0x80)) 2088 break;
1586 return -EIO; 2089
1587 } else if (!gfan_handle && strlencmp(cmd, "disable") == 0) { 2090 case IBMACPI_FAN_WR_ACPI_FANS:
1588 /* all except 570, 600e/x, 770e, 770x */ 2091 case IBMACPI_FAN_WR_TPEC:
1589 if (!acpi_ec_write(fan_status_offset, 0x00)) 2092 if ((level != IBMACPI_FAN_EC_AUTO) &&
1590 return -EIO; 2093 (level != IBMACPI_FAN_EC_DISENGAGED) &&
1591 } else if (fans_handle && 2094 ((level < 0) || (level > 7)))
1592 sscanf(cmd, "speed %d", &speed) == 1 && 2095 return -EINVAL;
1593 speed >= 0 && speed <= 65535) { 2096
1594 /* X31, X40 */ 2097 if (!acpi_ec_write(fan_status_offset, level))
2098 return -EIO;
2099 else
2100 fan_control_status_known = 1;
2101 break;
2102
2103 default:
2104 return -ENXIO;
2105 }
2106 return 0;
2107}
2108
2109static int fan_set_enable(void)
2110{
2111 u8 s;
2112 int rc;
2113
2114 switch (fan_control_access_mode) {
2115 case IBMACPI_FAN_WR_ACPI_FANS:
2116 case IBMACPI_FAN_WR_TPEC:
2117 if ((rc = fan_get_status(&s)) < 0)
2118 return rc;
2119
2120 /* Don't go out of emergency fan mode */
2121 if (s != 7)
2122 s = IBMACPI_FAN_EC_AUTO;
2123
2124 if (!acpi_ec_write(fan_status_offset, s))
2125 return -EIO;
2126 else
2127 fan_control_status_known = 1;
2128 break;
2129
2130 case IBMACPI_FAN_WR_ACPI_SFAN:
2131 if ((rc = fan_get_status(&s)) < 0)
2132 return rc;
2133
2134 s &= 0x07;
2135
2136 /* Set fan to at least level 4 */
2137 if (s < 4)
2138 s = 4;
2139
2140 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
2141 return -EIO;
2142 break;
2143
2144 default:
2145 return -ENXIO;
2146 }
2147 return 0;
2148}
2149
2150static int fan_set_disable(void)
2151{
2152 switch (fan_control_access_mode) {
2153 case IBMACPI_FAN_WR_ACPI_FANS:
2154 case IBMACPI_FAN_WR_TPEC:
2155 if (!acpi_ec_write(fan_status_offset, 0x00))
2156 return -EIO;
2157 else
2158 fan_control_status_known = 1;
2159 break;
2160
2161 case IBMACPI_FAN_WR_ACPI_SFAN:
2162 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
2163 return -EIO;
2164 break;
2165
2166 default:
2167 return -ENXIO;
2168 }
2169 return 0;
2170}
2171
2172static int fan_set_speed(int speed)
2173{
2174 switch (fan_control_access_mode) {
2175 case IBMACPI_FAN_WR_ACPI_FANS:
2176 if (speed >= 0 && speed <= 65535) {
1595 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", 2177 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
1596 speed, speed, speed)) 2178 speed, speed, speed))
1597 return -EIO; 2179 return -EIO;
1598 } else 2180 } else
1599 return -EINVAL; 2181 return -EINVAL;
1600 } 2182 break;
1601 2183
2184 default:
2185 return -ENXIO;
2186 }
1602 return 0; 2187 return 0;
1603} 2188}
1604 2189
2190static int fan_write_cmd_level(const char *cmd, int *rc)
2191{
2192 int level;
2193
2194 if (strlencmp(cmd, "level auto") == 0)
2195 level = IBMACPI_FAN_EC_AUTO;
2196 else if (strlencmp(cmd, "level disengaged") == 0)
2197 level = IBMACPI_FAN_EC_DISENGAGED;
2198 else if (sscanf(cmd, "level %d", &level) != 1)
2199 return 0;
2200
2201 if ((*rc = fan_set_level(level)) == -ENXIO)
2202 printk(IBM_ERR "level command accepted for unsupported "
2203 "access mode %d", fan_control_access_mode);
2204
2205 return 1;
2206}
2207
2208static int fan_write_cmd_enable(const char *cmd, int *rc)
2209{
2210 if (strlencmp(cmd, "enable") != 0)
2211 return 0;
2212
2213 if ((*rc = fan_set_enable()) == -ENXIO)
2214 printk(IBM_ERR "enable command accepted for unsupported "
2215 "access mode %d", fan_control_access_mode);
2216
2217 return 1;
2218}
2219
2220static int fan_write_cmd_disable(const char *cmd, int *rc)
2221{
2222 if (strlencmp(cmd, "disable") != 0)
2223 return 0;
2224
2225 if ((*rc = fan_set_disable()) == -ENXIO)
2226 printk(IBM_ERR "disable command accepted for unsupported "
2227 "access mode %d", fan_control_access_mode);
2228
2229 return 1;
2230}
2231
2232static int fan_write_cmd_speed(const char *cmd, int *rc)
2233{
2234 int speed;
2235
2236 /* TODO:
2237 * Support speed <low> <medium> <high> ? */
2238
2239 if (sscanf(cmd, "speed %d", &speed) != 1)
2240 return 0;
2241
2242 if ((*rc = fan_set_speed(speed)) == -ENXIO)
2243 printk(IBM_ERR "speed command accepted for unsupported "
2244 "access mode %d", fan_control_access_mode);
2245
2246 return 1;
2247}
2248
2249static int fan_write_cmd_watchdog(const char *cmd, int *rc)
2250{
2251 int interval;
2252
2253 if (sscanf(cmd, "watchdog %d", &interval) != 1)
2254 return 0;
2255
2256 if (interval < 0 || interval > 120)
2257 *rc = -EINVAL;
2258 else
2259 fan_watchdog_maxinterval = interval;
2260
2261 return 1;
2262}
2263
2264static int fan_write(char *buf)
2265{
2266 char *cmd;
2267 int rc = 0;
2268
2269 while (!rc && (cmd = next_cmd(&buf))) {
2270 if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) &&
2271 fan_write_cmd_level(cmd, &rc)) &&
2272 !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
2273 (fan_write_cmd_enable(cmd, &rc) ||
2274 fan_write_cmd_disable(cmd, &rc) ||
2275 fan_write_cmd_watchdog(cmd, &rc))) &&
2276 !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
2277 fan_write_cmd_speed(cmd, &rc))
2278 )
2279 rc = -EINVAL;
2280 else if (!rc)
2281 fan_watchdog_reset();
2282 }
2283
2284 return rc;
2285}
2286
2287static void fan_watchdog_fire(void *ignored)
2288{
2289 printk(IBM_NOTICE "fan watchdog: enabling fan\n");
2290 if (fan_set_enable()) {
2291 printk(IBM_ERR "fan watchdog: error while enabling fan\n");
2292 /* reschedule for later */
2293 fan_watchdog_reset();
2294 }
2295}
2296
1605static struct ibm_struct ibms[] = { 2297static struct ibm_struct ibms[] = {
1606 { 2298 {
1607 .name = "driver", 2299 .name = "driver",
@@ -1662,6 +2354,7 @@ static struct ibm_struct ibms[] = {
1662 .type = ACPI_SYSTEM_NOTIFY, 2354 .type = ACPI_SYSTEM_NOTIFY,
1663 }, 2355 },
1664#endif 2356#endif
2357#ifdef CONFIG_ACPI_IBM_BAY
1665 { 2358 {
1666 .name = "bay", 2359 .name = "bay",
1667 .init = bay_init, 2360 .init = bay_init,
@@ -1671,6 +2364,7 @@ static struct ibm_struct ibms[] = {
1671 .handle = &bay_handle, 2364 .handle = &bay_handle,
1672 .type = ACPI_SYSTEM_NOTIFY, 2365 .type = ACPI_SYSTEM_NOTIFY,
1673 }, 2366 },
2367#endif
1674 { 2368 {
1675 .name = "cmos", 2369 .name = "cmos",
1676 .read = cmos_read, 2370 .read = cmos_read,
@@ -1702,6 +2396,8 @@ static struct ibm_struct ibms[] = {
1702 .name = "brightness", 2396 .name = "brightness",
1703 .read = brightness_read, 2397 .read = brightness_read,
1704 .write = brightness_write, 2398 .write = brightness_write,
2399 .init = brightness_init,
2400 .exit = brightness_exit,
1705 }, 2401 },
1706 { 2402 {
1707 .name = "volume", 2403 .name = "volume",
@@ -1712,6 +2408,8 @@ static struct ibm_struct ibms[] = {
1712 .name = "fan", 2408 .name = "fan",
1713 .read = fan_read, 2409 .read = fan_read,
1714 .write = fan_write, 2410 .write = fan_write,
2411 .init = fan_init,
2412 .exit = fan_exit,
1715 .experimental = 1, 2413 .experimental = 1,
1716 }, 2414 },
1717}; 2415};
@@ -1825,7 +2523,7 @@ static int __init register_driver(struct ibm_struct *ibm)
1825 } 2523 }
1826 2524
1827 memset(ibm->driver, 0, sizeof(struct acpi_driver)); 2525 memset(ibm->driver, 0, sizeof(struct acpi_driver));
1828 sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name); 2526 sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
1829 ibm->driver->ids = ibm->hid; 2527 ibm->driver->ids = ibm->hid;
1830 ibm->driver->ops.add = &ibm_device_add; 2528 ibm->driver->ops.add = &ibm_device_add;
1831 2529
@@ -1954,7 +2652,9 @@ IBM_PARAM(light);
1954#ifdef CONFIG_ACPI_IBM_DOCK 2652#ifdef CONFIG_ACPI_IBM_DOCK
1955IBM_PARAM(dock); 2653IBM_PARAM(dock);
1956#endif 2654#endif
2655#ifdef CONFIG_ACPI_IBM_BAY
1957IBM_PARAM(bay); 2656IBM_PARAM(bay);
2657#endif
1958IBM_PARAM(cmos); 2658IBM_PARAM(cmos);
1959IBM_PARAM(led); 2659IBM_PARAM(led);
1960IBM_PARAM(beep); 2660IBM_PARAM(beep);
@@ -1971,6 +2671,33 @@ static void acpi_ibm_exit(void)
1971 ibm_exit(&ibms[i]); 2671 ibm_exit(&ibms[i]);
1972 2672
1973 remove_proc_entry(IBM_DIR, acpi_root_dir); 2673 remove_proc_entry(IBM_DIR, acpi_root_dir);
2674
2675 if (ibm_thinkpad_ec_found)
2676 kfree(ibm_thinkpad_ec_found);
2677}
2678
2679static char* __init check_dmi_for_ec(void)
2680{
2681 struct dmi_device *dev = NULL;
2682 char ec_fw_string[18];
2683
2684 /*
2685 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
2686 * X32 or newer, all Z series; Some models must have an
2687 * up-to-date BIOS or they will not be detected.
2688 *
2689 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
2690 */
2691 while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
2692 if (sscanf(dev->name,
2693 "IBM ThinkPad Embedded Controller -[%17c",
2694 ec_fw_string) == 1) {
2695 ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
2696 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
2697 return kstrdup(ec_fw_string, GFP_KERNEL);
2698 }
2699 }
2700 return NULL;
1974} 2701}
1975 2702
1976static int __init acpi_ibm_init(void) 2703static int __init acpi_ibm_init(void)
@@ -1992,6 +2719,12 @@ static int __init acpi_ibm_init(void)
1992 return -ENODEV; 2719 return -ENODEV;
1993 } 2720 }
1994 2721
2722 /* Models with newer firmware report the EC in DMI */
2723 ibm_thinkpad_ec_found = check_dmi_for_ec();
2724 if (ibm_thinkpad_ec_found)
2725 printk(IBM_INFO "ThinkPad EC firmware %s\n",
2726 ibm_thinkpad_ec_found);
2727
1995 /* these handles are not required */ 2728 /* these handles are not required */
1996 IBM_HANDLE_INIT(vid); 2729 IBM_HANDLE_INIT(vid);
1997 IBM_HANDLE_INIT(vid2); 2730 IBM_HANDLE_INIT(vid2);
@@ -2004,12 +2737,14 @@ static int __init acpi_ibm_init(void)
2004 IBM_HANDLE_INIT(dock); 2737 IBM_HANDLE_INIT(dock);
2005#endif 2738#endif
2006 IBM_HANDLE_INIT(pci); 2739 IBM_HANDLE_INIT(pci);
2740#ifdef CONFIG_ACPI_IBM_BAY
2007 IBM_HANDLE_INIT(bay); 2741 IBM_HANDLE_INIT(bay);
2008 if (bay_handle) 2742 if (bay_handle)
2009 IBM_HANDLE_INIT(bay_ej); 2743 IBM_HANDLE_INIT(bay_ej);
2010 IBM_HANDLE_INIT(bay2); 2744 IBM_HANDLE_INIT(bay2);
2011 if (bay2_handle) 2745 if (bay2_handle)
2012 IBM_HANDLE_INIT(bay2_ej); 2746 IBM_HANDLE_INIT(bay2_ej);
2747#endif
2013 IBM_HANDLE_INIT(beep); 2748 IBM_HANDLE_INIT(beep);
2014 IBM_HANDLE_INIT(ecrd); 2749 IBM_HANDLE_INIT(ecrd);
2015 IBM_HANDLE_INIT(ecwr); 2750 IBM_HANDLE_INIT(ecwr);
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index 7fe0b7ae973..2f35f891593 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -41,6 +41,8 @@
41#include <linux/init.h> 41#include <linux/init.h>
42#include <linux/types.h> 42#include <linux/types.h>
43#include <linux/proc_fs.h> 43#include <linux/proc_fs.h>
44#include <linux/backlight.h>
45
44#include <asm/uaccess.h> 46#include <asm/uaccess.h>
45 47
46#include <acpi/acpi_drivers.h> 48#include <acpi/acpi_drivers.h>
@@ -210,6 +212,7 @@ static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result)
210} 212}
211 213
212static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; 214static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
215static struct backlight_device *toshiba_backlight_device;
213static int force_fan; 216static int force_fan;
214static int last_key_event; 217static int last_key_event;
215static int key_event_valid; 218static int key_event_valid;
@@ -271,14 +274,23 @@ dispatch_write(struct file *file, const char __user * buffer,
271 return result; 274 return result;
272} 275}
273 276
274static char *read_lcd(char *p) 277static int get_lcd(struct backlight_device *bd)
275{ 278{
276 u32 hci_result; 279 u32 hci_result;
277 u32 value; 280 u32 value;
278 281
279 hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result); 282 hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
280 if (hci_result == HCI_SUCCESS) { 283 if (hci_result == HCI_SUCCESS) {
281 value = value >> HCI_LCD_BRIGHTNESS_SHIFT; 284 return (value >> HCI_LCD_BRIGHTNESS_SHIFT);
285 } else
286 return -EFAULT;
287}
288
289static char *read_lcd(char *p)
290{
291 int value = get_lcd(NULL);
292
293 if (value >= 0) {
282 p += sprintf(p, "brightness: %d\n", value); 294 p += sprintf(p, "brightness: %d\n", value);
283 p += sprintf(p, "brightness_levels: %d\n", 295 p += sprintf(p, "brightness_levels: %d\n",
284 HCI_LCD_BRIGHTNESS_LEVELS); 296 HCI_LCD_BRIGHTNESS_LEVELS);
@@ -289,22 +301,34 @@ static char *read_lcd(char *p)
289 return p; 301 return p;
290} 302}
291 303
304static int set_lcd(int value)
305{
306 u32 hci_result;
307
308 value = value << HCI_LCD_BRIGHTNESS_SHIFT;
309 hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
310 if (hci_result != HCI_SUCCESS)
311 return -EFAULT;
312
313 return 0;
314}
315
316static int set_lcd_status(struct backlight_device *bd)
317{
318 return set_lcd(bd->props->brightness);
319}
320
292static unsigned long write_lcd(const char *buffer, unsigned long count) 321static unsigned long write_lcd(const char *buffer, unsigned long count)
293{ 322{
294 int value; 323 int value;
295 u32 hci_result; 324 int ret = count;
296 325
297 if (sscanf(buffer, " brightness : %i", &value) == 1 && 326 if (sscanf(buffer, " brightness : %i", &value) == 1 &&
298 value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { 327 value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS)
299 value = value << HCI_LCD_BRIGHTNESS_SHIFT; 328 ret = set_lcd(value);
300 hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result); 329 else
301 if (hci_result != HCI_SUCCESS) 330 ret = -EINVAL;
302 return -EFAULT; 331 return ret;
303 } else {
304 return -EINVAL;
305 }
306
307 return count;
308} 332}
309 333
310static char *read_video(char *p) 334static char *read_video(char *p)
@@ -506,6 +530,26 @@ static acpi_status __exit remove_device(void)
506 return AE_OK; 530 return AE_OK;
507} 531}
508 532
533static struct backlight_properties toshiba_backlight_data = {
534 .owner = THIS_MODULE,
535 .get_brightness = get_lcd,
536 .update_status = set_lcd_status,
537 .max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1,
538};
539
540static void __exit toshiba_acpi_exit(void)
541{
542 if (toshiba_backlight_device)
543 backlight_device_unregister(toshiba_backlight_device);
544
545 remove_device();
546
547 if (toshiba_proc_dir)
548 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
549
550 return;
551}
552
509static int __init toshiba_acpi_init(void) 553static int __init toshiba_acpi_init(void)
510{ 554{
511 acpi_status status = AE_OK; 555 acpi_status status = AE_OK;
@@ -546,17 +590,15 @@ static int __init toshiba_acpi_init(void)
546 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 590 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
547 } 591 }
548 592
549 return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; 593 toshiba_backlight_device = backlight_device_register("toshiba", NULL,
550} 594 &toshiba_backlight_data);
551 595 if (IS_ERR(toshiba_backlight_device)) {
552static void __exit toshiba_acpi_exit(void) 596 printk(KERN_ERR "Could not register toshiba backlight device\n");
553{ 597 toshiba_backlight_device = NULL;
554 remove_device(); 598 toshiba_acpi_exit();
555 599 }
556 if (toshiba_proc_dir)
557 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
558 600
559 return; 601 return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
560} 602}
561 603
562module_init(toshiba_acpi_init); 604module_init(toshiba_acpi_init);