aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-07 12:45:58 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-07 12:45:58 -0500
commitf0f1b3364ae7f48084bdf2837fb979ff59622523 (patch)
treee5ef68c0071f44178cc8d1948b64e216d57422aa /drivers
parent4383f18b7f94a4d668c5eec68645c75d44556235 (diff)
parentb7143156c9ceee1a072c57aac8729d2dec5b3bf1 (diff)
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (112 commits) ACPI: fix build warning Revert "cpuidle: build fix for non-x86" ACPI: update intrd DSDT override console messages ACPI: update DSDT override documentation ACPI: Add "acpi_no_initrd_override" kernel parameter ACPI: its a directory not a folder.... ACPI: misc cleanups ACPI: add missing prink prefix strings ACPI: cleanup acpi.h ACPICA: fix CONFIG_ACPI_DEBUG_FUNC_TRACE build ACPI: video: Ignore ACPI video devices that aren't present in hardware ACPI: video: reset brightness on resume ACPI: video: call ACPI notifier chain for ACPI video notifications ACPI: create notifier chain to get hotkey events to graphics driver ACPI: video: delete unused display switch on hotkey event code ACPI: video: create "brightness_switch_enabled" modparam cpuidle: Add a poll_idle method ACPI: cpuidle: Support C1 idle time accounting ACPI: enable MWAIT for C1 idle ACPI: idle: Fix acpi_safe_halt usages and interrupt enabling/disabling ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/acpi/Kconfig40
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/asus_acpi.c55
-rw-r--r--drivers/acpi/battery.c5
-rw-r--r--drivers/acpi/bay.c10
-rw-r--r--drivers/acpi/blacklist.c58
-rw-r--r--drivers/acpi/bus.c26
-rw-r--r--drivers/acpi/debug.c57
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c4
-rw-r--r--drivers/acpi/dock.c14
-rw-r--r--drivers/acpi/ec.c19
-rw-r--r--drivers/acpi/event.c28
-rw-r--r--drivers/acpi/events/evevent.c2
-rw-r--r--drivers/acpi/events/evgpe.c27
-rw-r--r--drivers/acpi/fan.c92
-rw-r--r--drivers/acpi/glue.c4
-rw-r--r--drivers/acpi/hardware/hwsleep.c2
-rw-r--r--drivers/acpi/namespace/nsxfeval.c10
-rw-r--r--drivers/acpi/numa.c3
-rw-r--r--drivers/acpi/osl.c372
-rw-r--r--drivers/acpi/pci_bind.c4
-rw-r--r--drivers/acpi/pci_irq.c7
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/power.c6
-rw-r--r--drivers/acpi/processor_core.c42
-rw-r--r--drivers/acpi/processor_idle.c47
-rw-r--r--drivers/acpi/processor_perflib.c16
-rw-r--r--drivers/acpi/processor_thermal.c134
-rw-r--r--drivers/acpi/processor_throttling.c346
-rw-r--r--drivers/acpi/sbs.c2
-rw-r--r--drivers/acpi/sbshc.c4
-rw-r--r--drivers/acpi/scan.c110
-rw-r--r--drivers/acpi/sleep/main.c17
-rw-r--r--drivers/acpi/sleep/proc.c46
-rw-r--r--drivers/acpi/system.c208
-rw-r--r--drivers/acpi/tables/Makefile2
-rw-r--r--drivers/acpi/tables/tbxfroot.c4
-rw-r--r--drivers/acpi/thermal.c663
-rw-r--r--drivers/acpi/utilities/utglobal.c2
-rw-r--r--drivers/acpi/video.c262
-rw-r--r--drivers/acpi/wmi.c710
-rw-r--r--drivers/cpuidle/Kconfig4
-rw-r--r--drivers/cpuidle/cpuidle.c41
-rw-r--r--drivers/firmware/dmi_scan.c9
-rw-r--r--drivers/misc/Kconfig53
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/acer-wmi.c1109
-rw-r--r--drivers/misc/asus-laptop.c26
-rw-r--r--drivers/misc/intel_menlow.c526
-rw-r--r--drivers/misc/sony-laptop.c445
-rw-r--r--drivers/misc/tc1100-wmi.c290
-rw-r--r--drivers/misc/thinkpad_acpi.c3256
-rw-r--r--drivers/misc/thinkpad_acpi.h606
-rw-r--r--drivers/pnp/pnpacpi/core.c2
-rw-r--r--drivers/power/power_supply_sysfs.c1
-rw-r--r--drivers/thermal/Kconfig15
-rw-r--r--drivers/thermal/Makefile5
-rw-r--r--drivers/thermal/thermal.c714
60 files changed, 8204 insertions, 2367 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index d74d9fbb9fd2..b86877bdc7ac 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -60,6 +60,8 @@ source "drivers/power/Kconfig"
60 60
61source "drivers/hwmon/Kconfig" 61source "drivers/hwmon/Kconfig"
62 62
63source "drivers/thermal/Kconfig"
64
63source "drivers/watchdog/Kconfig" 65source "drivers/watchdog/Kconfig"
64 66
65source "drivers/ssb/Kconfig" 67source "drivers/ssb/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index f1c11db52a57..30ba97ec5eb5 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -65,6 +65,7 @@ obj-y += i2c/
65obj-$(CONFIG_W1) += w1/ 65obj-$(CONFIG_W1) += w1/
66obj-$(CONFIG_POWER_SUPPLY) += power/ 66obj-$(CONFIG_POWER_SUPPLY) += power/
67obj-$(CONFIG_HWMON) += hwmon/ 67obj-$(CONFIG_HWMON) += hwmon/
68obj-$(CONFIG_THERMAL) += thermal/
68obj-$(CONFIG_WATCHDOG) += watchdog/ 69obj-$(CONFIG_WATCHDOG) += watchdog/
69obj-$(CONFIG_PHONE) += telephony/ 70obj-$(CONFIG_PHONE) += telephony/
70obj-$(CONFIG_MD) += md/ 71obj-$(CONFIG_MD) += md/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index ccf6ea95f68c..7ef172c2a1d6 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -68,26 +68,28 @@ config ACPI_PROCFS
68 68
69 Say N to delete /proc/acpi/ files that have moved to /sys/ 69 Say N to delete /proc/acpi/ files that have moved to /sys/
70config ACPI_PROCFS_POWER 70config ACPI_PROCFS_POWER
71 bool "Deprecated power /proc/acpi folders" 71 bool "Deprecated power /proc/acpi directories"
72 depends on PROC_FS 72 depends on PROC_FS
73 default y 73 default y
74 ---help--- 74 ---help---
75 For backwards compatibility, this option allows 75 For backwards compatibility, this option allows
76 deprecated power /proc/acpi/ folders to exist, even when 76 deprecated power /proc/acpi/ directories to exist, even when
77 they have been replaced by functions in /sys. 77 they have been replaced by functions in /sys.
78 The deprecated folders (and their replacements) include: 78 The deprecated directories (and their replacements) include:
79 /proc/acpi/battery/* (/sys/class/power_supply/*) 79 /proc/acpi/battery/* (/sys/class/power_supply/*)
80 /proc/acpi/ac_adapter/* (sys/class/power_supply/*) 80 /proc/acpi/ac_adapter/* (sys/class/power_supply/*)
81 This option has no effect on /proc/acpi/ folders 81 This option has no effect on /proc/acpi/ directories
82 and functions, which do not yet exist in /sys 82 and functions, which do not yet exist in /sys
83 83
84 Say N to delete power /proc/acpi/ folders that have moved to /sys/ 84 Say N to delete power /proc/acpi/ directories that have moved to /sys/
85
85config ACPI_SYSFS_POWER 86config ACPI_SYSFS_POWER
86 bool "Future power /sys interface" 87 bool "Future power /sys interface"
87 select POWER_SUPPLY 88 select POWER_SUPPLY
88 default y 89 default y
89 ---help--- 90 ---help---
90 Say N to disable power /sys interface 91 Say N to disable power /sys interface
92
91config ACPI_PROC_EVENT 93config ACPI_PROC_EVENT
92 bool "Deprecated /proc/acpi/event support" 94 bool "Deprecated /proc/acpi/event support"
93 depends on PROC_FS 95 depends on PROC_FS
@@ -186,6 +188,7 @@ config ACPI_HOTPLUG_CPU
186config ACPI_THERMAL 188config ACPI_THERMAL
187 tristate "Thermal Zone" 189 tristate "Thermal Zone"
188 depends on ACPI_PROCESSOR 190 depends on ACPI_PROCESSOR
191 select THERMAL
189 default y 192 default y
190 help 193 help
191 This driver adds support for ACPI thermal zones. Most mobile and 194 This driver adds support for ACPI thermal zones. Most mobile and
@@ -199,6 +202,16 @@ config ACPI_NUMA
199 depends on (X86 || IA64) 202 depends on (X86 || IA64)
200 default y if IA64_GENERIC || IA64_SGI_SN2 203 default y if IA64_GENERIC || IA64_SGI_SN2
201 204
205config ACPI_WMI
206 tristate "WMI (EXPERIMENTAL)"
207 depends on EXPERIMENTAL
208 help
209 This driver adds support for the ACPI-WMI mapper device (PNP0C14)
210 found on some systems.
211
212 NOTE: You will need another driver or userspace application on top of
213 this to actually use anything defined in the ACPI-WMI mapper.
214
202config ACPI_ASUS 215config ACPI_ASUS
203 tristate "ASUS/Medion Laptop Extras" 216 tristate "ASUS/Medion Laptop Extras"
204 depends on X86 217 depends on X86
@@ -263,8 +276,10 @@ config ACPI_CUSTOM_DSDT
263 depends on !STANDALONE 276 depends on !STANDALONE
264 default n 277 default n
265 help 278 help
266 This option is to load a custom ACPI DSDT 279 This option supports a custom DSDT by linking it into the kernel.
267 If you don't know what that is, say N. 280 See Documentation/acpi/dsdt-override.txt
281
282 If unsure, say N.
268 283
269config ACPI_CUSTOM_DSDT_FILE 284config ACPI_CUSTOM_DSDT_FILE
270 string "Custom DSDT Table file to include" 285 string "Custom DSDT Table file to include"
@@ -274,6 +289,17 @@ config ACPI_CUSTOM_DSDT_FILE
274 Enter the full path name to the file which includes the AmlCode 289 Enter the full path name to the file which includes the AmlCode
275 declaration. 290 declaration.
276 291
292config ACPI_CUSTOM_DSDT_INITRD
293 bool "Read Custom DSDT from initramfs"
294 depends on BLK_DEV_INITRD
295 default n
296 help
297 This option supports a custom DSDT by optionally loading it from initrd.
298 See Documentation/acpi/dsdt-override.txt
299
300 If you are not using this feature now, but may use it later,
301 it is safe to say Y here.
302
277config ACPI_BLACKLIST_YEAR 303config ACPI_BLACKLIST_YEAR
278 int "Disable ACPI for systems before Jan 1st this year" if X86_32 304 int "Disable ACPI for systems before Jan 1st this year" if X86_32
279 default 0 305 default 0
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 456446f90077..f29812a86533 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_ACPI_THERMAL) += thermal.o
55obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o 55obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
56obj-$(CONFIG_ACPI_DEBUG) += debug.o 56obj-$(CONFIG_ACPI_DEBUG) += debug.o
57obj-$(CONFIG_ACPI_NUMA) += numa.o 57obj-$(CONFIG_ACPI_NUMA) += numa.o
58obj-$(CONFIG_ACPI_WMI) += wmi.o
58obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o 59obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
59obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 60obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
60obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o 61obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index d915fec9bf63..d25ef961415c 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -142,6 +142,7 @@ struct asus_hotk {
142 xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N 142 xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
143 A4S, //Z81sp 143 A4S, //Z81sp
144 //(Centrino) 144 //(Centrino)
145 F3Sa,
145 END_MODEL 146 END_MODEL
146 } model; //Models currently supported 147 } model; //Models currently supported
147 u16 event_count[128]; //count for each event TODO make this better 148 u16 event_count[128]; //count for each event TODO make this better
@@ -405,7 +406,20 @@ static struct model_data model_conf[END_MODEL] = {
405 .brightness_get = "GPLV", 406 .brightness_get = "GPLV",
406 .mt_bt_switch = "BLED", 407 .mt_bt_switch = "BLED",
407 .mt_wled = "WLED" 408 .mt_wled = "WLED"
408 } 409 },
410
411 {
412 .name = "F3Sa",
413 .mt_bt_switch = "BLED",
414 .mt_wled = "WLED",
415 .mt_mled = "MLED",
416 .brightness_get = "GPLV",
417 .brightness_set = "SPLV",
418 .mt_lcd_switch = "\\_SB.PCI0.SBRG.EC0._Q10",
419 .lcd_status = "\\_SB.PCI0.SBRG.EC0.RPIN",
420 .display_get = "\\ADVG",
421 .display_set = "SDSP",
422 },
409 423
410}; 424};
411 425
@@ -710,15 +724,8 @@ static int get_lcd_state(void)
710{ 724{
711 int lcd = 0; 725 int lcd = 0;
712 726
713 if (hotk->model != L3H) { 727 if (hotk->model == L3H) {
714 /* We don't have to check anything if we are here */ 728 /* L3H and the like have to be handled differently */
715 if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
716 printk(KERN_WARNING
717 "Asus ACPI: Error reading LCD status\n");
718
719 if (hotk->model == L2D)
720 lcd = ~lcd;
721 } else { /* L3H and the like have to be handled differently */
722 acpi_status status = 0; 729 acpi_status status = 0;
723 struct acpi_object_list input; 730 struct acpi_object_list input;
724 union acpi_object mt_params[2]; 731 union acpi_object mt_params[2];
@@ -745,6 +752,32 @@ static int get_lcd_state(void)
745 if (out_obj.type == ACPI_TYPE_INTEGER) 752 if (out_obj.type == ACPI_TYPE_INTEGER)
746 /* That's what the AML code does */ 753 /* That's what the AML code does */
747 lcd = out_obj.integer.value >> 8; 754 lcd = out_obj.integer.value >> 8;
755 } else if (hotk->model == F3Sa) {
756 unsigned long tmp;
757 union acpi_object param;
758 struct acpi_object_list input;
759 acpi_status status;
760
761 /* Read pin 11 */
762 param.type = ACPI_TYPE_INTEGER;
763 param.integer.value = 0x11;
764 input.count = 1;
765 input.pointer = &param;
766
767 status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
768 &input, &tmp);
769 if (status != AE_OK)
770 return -1;
771
772 lcd = tmp;
773 } else {
774 /* We don't have to check anything if we are here */
775 if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
776 printk(KERN_WARNING
777 "Asus ACPI: Error reading LCD status\n");
778
779 if (hotk->model == L2D)
780 lcd = ~lcd;
748 } 781 }
749 782
750 return (lcd & 1); 783 return (lcd & 1);
@@ -1134,6 +1167,8 @@ static int asus_model_match(char *model)
1134 return W5A; 1167 return W5A;
1135 else if (strncmp(model, "A4S", 3) == 0) 1168 else if (strncmp(model, "A4S", 3) == 0)
1136 return A4S; 1169 return A4S;
1170 else if (strncmp(model, "F3Sa", 4) == 0)
1171 return F3Sa;
1137 else 1172 else
1138 return END_MODEL; 1173 return END_MODEL;
1139} 1174}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index c4a769d1ba85..f6215e809808 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -194,6 +194,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
194 case POWER_SUPPLY_PROP_MANUFACTURER: 194 case POWER_SUPPLY_PROP_MANUFACTURER:
195 val->strval = battery->oem_info; 195 val->strval = battery->oem_info;
196 break; 196 break;
197 case POWER_SUPPLY_PROP_SERIAL_NUMBER:
198 val->strval = battery->serial_number;
199 break;
197 default: 200 default:
198 return -EINVAL; 201 return -EINVAL;
199 } 202 }
@@ -212,6 +215,7 @@ static enum power_supply_property charge_battery_props[] = {
212 POWER_SUPPLY_PROP_CHARGE_NOW, 215 POWER_SUPPLY_PROP_CHARGE_NOW,
213 POWER_SUPPLY_PROP_MODEL_NAME, 216 POWER_SUPPLY_PROP_MODEL_NAME,
214 POWER_SUPPLY_PROP_MANUFACTURER, 217 POWER_SUPPLY_PROP_MANUFACTURER,
218 POWER_SUPPLY_PROP_SERIAL_NUMBER,
215}; 219};
216 220
217static enum power_supply_property energy_battery_props[] = { 221static enum power_supply_property energy_battery_props[] = {
@@ -226,6 +230,7 @@ static enum power_supply_property energy_battery_props[] = {
226 POWER_SUPPLY_PROP_ENERGY_NOW, 230 POWER_SUPPLY_PROP_ENERGY_NOW,
227 POWER_SUPPLY_PROP_MODEL_NAME, 231 POWER_SUPPLY_PROP_MODEL_NAME,
228 POWER_SUPPLY_PROP_MANUFACTURER, 232 POWER_SUPPLY_PROP_MANUFACTURER,
233 POWER_SUPPLY_PROP_SERIAL_NUMBER,
229}; 234};
230#endif 235#endif
231 236
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index 6daf6088ac88..1fa86811b8ee 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -46,6 +46,12 @@ MODULE_LICENSE("GPL");
46 printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } 46 printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
47static void bay_notify(acpi_handle handle, u32 event, void *data); 47static void bay_notify(acpi_handle handle, u32 event, void *data);
48 48
49static const struct acpi_device_id bay_device_ids[] = {
50 {"LNXIOBAY", 0},
51 {"", 0},
52};
53MODULE_DEVICE_TABLE(acpi, bay_device_ids);
54
49struct bay { 55struct bay {
50 acpi_handle handle; 56 acpi_handle handle;
51 char *name; 57 char *name;
@@ -128,7 +134,7 @@ static ssize_t show_present(struct device *dev,
128 return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay)); 134 return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
129 135
130} 136}
131DEVICE_ATTR(present, S_IRUGO, show_present, NULL); 137static DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
132 138
133/* 139/*
134 * write_eject - write method for "eject" file in sysfs 140 * write_eject - write method for "eject" file in sysfs
@@ -144,7 +150,7 @@ static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
144 eject_device(bay->handle); 150 eject_device(bay->handle);
145 return count; 151 return count;
146} 152}
147DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject); 153static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
148 154
149/** 155/**
150 * is_ata - see if a device is an ata device 156 * is_ata - see if a device is an ata device
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 8809654d6cc9..6dbaa2d15fe0 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -70,8 +70,6 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
70 /* IBM 600E - _ADR should return 7, but it returns 1 */ 70 /* IBM 600E - _ADR should return 7, but it returns 1 */
71 {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal, 71 {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
72 "Incorrect _ADR", 1}, 72 "Incorrect _ADR", 1},
73 {"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions,
74 "Bogus PCI routing", 1},
75 73
76 {""} 74 {""}
77}; 75};
@@ -208,33 +206,35 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
208 * Disable OSI(Linux) warnings on all "Acer, inc." 206 * Disable OSI(Linux) warnings on all "Acer, inc."
209 * 207 *
210 * _OSI(Linux) disables the latest Windows BIOS code: 208 * _OSI(Linux) disables the latest Windows BIOS code:
209 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
211 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"), 210 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"),
211 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
212 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"), 212 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
213 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"), 213 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
214 * _OSI(Linux) effect unknown: 214 * _OSI(Linux) effect unknown:
215 * DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"), 215 * DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
216 */ 216 */
217 { 217 /*
218 .callback = dmi_disable_osi_linux, 218 * note that dmi_check_system() uses strstr()
219 .ident = "Acer, inc.", 219 * to match sub-strings rather than !strcmp(),
220 .matches = { 220 * so "Acer" below matches "Acer, inc." above.
221 DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."), 221 */
222 },
223 },
224 /* 222 /*
225 * Disable OSI(Linux) warnings on all "Acer" 223 * Disable OSI(Linux) warnings on all "Acer"
226 * 224 *
227 * _OSI(Linux) effect unknown: 225 * _OSI(Linux) effect unknown:
228 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
229 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), 226 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
230 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"), 227 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
231 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"), 228 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
232 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"), 229 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
233 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"), 230 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
234 * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"), 231 * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
232 *
233 * _OSI(Linux) is a NOP:
234 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
235 */ 235 */
236 { 236 {
237 .callback = dmi_unknown_osi_linux, 237 .callback = dmi_disable_osi_linux,
238 .ident = "Acer", 238 .ident = "Acer",
239 .matches = { 239 .matches = {
240 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 240 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -242,21 +242,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
242 }, 242 },
243 /* 243 /*
244 * Disable OSI(Linux) warnings on all "Apple Computer, Inc." 244 * Disable OSI(Linux) warnings on all "Apple Computer, Inc."
245 * Disable OSI(Linux) warnings on all "Apple Inc."
245 * 246 *
246 * _OSI(Linux) confirmed to be a NOP: 247 * _OSI(Linux) confirmed to be a NOP:
247 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), 248 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
248 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"), 249 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
249 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"), 250 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
251 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
250 * _OSI(Linux) effect unknown: 252 * _OSI(Linux) effect unknown:
251 * DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"), 253 * DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
252 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"), 254 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
253 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
254 */ 255 */
255 { 256 {
256 .callback = dmi_disable_osi_linux, 257 .callback = dmi_disable_osi_linux,
257 .ident = "Apple", 258 .ident = "Apple",
258 .matches = { 259 .matches = {
259 DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), 260 DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
260 }, 261 },
261 }, 262 },
262 /* 263 /*
@@ -294,13 +295,13 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
294 * DMI_MATCH(DMI_BOARD_NAME, "IFL91"), 295 * DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
295 */ 296 */
296 { 297 {
297 .callback = dmi_unknown_osi_linux, 298 .callback = dmi_disable_osi_linux,
298 .ident = "Compal", 299 .ident = "Compal",
299 .matches = { 300 .matches = {
300 DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), 301 DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
301 }, 302 },
302 }, 303 },
303 { /* OSI(Linux) touches USB, breaks suspend to disk */ 304 { /* OSI(Linux) touches USB, unknown side-effect */
304 .callback = dmi_disable_osi_linux, 305 .callback = dmi_disable_osi_linux,
305 .ident = "Dell Dimension 5150", 306 .ident = "Dell Dimension 5150",
306 .matches = { 307 .matches = {
@@ -310,7 +311,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
310 }, 311 },
311 { /* OSI(Linux) is a NOP */ 312 { /* OSI(Linux) is a NOP */
312 .callback = dmi_disable_osi_linux, 313 .callback = dmi_disable_osi_linux,
313 .ident = "Dell", 314 .ident = "Dell i1501",
314 .matches = { 315 .matches = {
315 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 316 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
316 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"), 317 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"),
@@ -318,7 +319,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
318 }, 319 },
319 { /* OSI(Linux) effect unknown */ 320 { /* OSI(Linux) effect unknown */
320 .callback = dmi_unknown_osi_linux, 321 .callback = dmi_unknown_osi_linux,
321 .ident = "Dell", 322 .ident = "Dell Latitude D830",
322 .matches = { 323 .matches = {
323 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 324 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
324 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"), 325 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"),
@@ -326,7 +327,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
326 }, 327 },
327 { /* OSI(Linux) effect unknown */ 328 { /* OSI(Linux) effect unknown */
328 .callback = dmi_unknown_osi_linux, 329 .callback = dmi_unknown_osi_linux,
329 .ident = "Dell", 330 .ident = "Dell OP GX620",
330 .matches = { 331 .matches = {
331 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 332 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
332 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"), 333 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"),
@@ -334,15 +335,23 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
334 }, 335 },
335 { /* OSI(Linux) effect unknown */ 336 { /* OSI(Linux) effect unknown */
336 .callback = dmi_unknown_osi_linux, 337 .callback = dmi_unknown_osi_linux,
337 .ident = "Dell", 338 .ident = "Dell PE 1900",
338 .matches = { 339 .matches = {
339 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 340 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
340 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"), 341 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"),
341 }, 342 },
342 }, 343 },
344 { /* OSI(Linux) is a NOP */
345 .callback = dmi_disable_osi_linux,
346 .ident = "Dell PE R200",
347 .matches = {
348 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
349 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R200"),
350 },
351 },
343 { /* OSI(Linux) touches USB */ 352 { /* OSI(Linux) touches USB */
344 .callback = dmi_disable_osi_linux, 353 .callback = dmi_disable_osi_linux,
345 .ident = "Dell", 354 .ident = "Dell PR 390",
346 .matches = { 355 .matches = {
347 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 356 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
348 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"), 357 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"),
@@ -358,7 +367,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
358 }, 367 },
359 { /* OSI(Linux) effect unknown */ 368 { /* OSI(Linux) effect unknown */
360 .callback = dmi_unknown_osi_linux, 369 .callback = dmi_unknown_osi_linux,
361 .ident = "Dell", 370 .ident = "Dell PE SC440",
362 .matches = { 371 .matches = {
363 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 372 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
364 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"), 373 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"),
@@ -474,6 +483,11 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
474 * 483 *
475 * _OSI(Linux) confirmed to be a NOP: 484 * _OSI(Linux) confirmed to be a NOP:
476 * DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"), 485 * DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"),
486 * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
487 *
488 * unknown:
489 * DMI_MATCH(DMI_PRODUCT_NAME, "S1-MDGDG"),
490 * with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
477 */ 491 */
478 { 492 {
479 .callback = dmi_disable_osi_linux, 493 .callback = dmi_disable_osi_linux,
@@ -516,7 +530,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
516 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"), 530 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
517 */ 531 */
518 { 532 {
519 .callback = dmi_unknown_osi_linux, 533 .callback = dmi_disable_osi_linux,
520 .ident = "Sony", 534 .ident = "Sony",
521 .matches = { 535 .matches = {
522 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 536 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 1b4cf984b081..8b0d4b7d188a 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -122,6 +122,31 @@ int acpi_bus_get_status(struct acpi_device *device)
122 122
123EXPORT_SYMBOL(acpi_bus_get_status); 123EXPORT_SYMBOL(acpi_bus_get_status);
124 124
125void acpi_bus_private_data_handler(acpi_handle handle,
126 u32 function, void *context)
127{
128 return;
129}
130EXPORT_SYMBOL(acpi_bus_private_data_handler);
131
132int acpi_bus_get_private_data(acpi_handle handle, void **data)
133{
134 acpi_status status = AE_OK;
135
136 if (!*data)
137 return -EINVAL;
138
139 status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
140 if (ACPI_FAILURE(status) || !*data) {
141 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
142 handle));
143 return -ENODEV;
144 }
145
146 return 0;
147}
148EXPORT_SYMBOL(acpi_bus_get_private_data);
149
125/* -------------------------------------------------------------------------- 150/* --------------------------------------------------------------------------
126 Power Management 151 Power Management
127 -------------------------------------------------------------------------- */ 152 -------------------------------------------------------------------------- */
@@ -366,7 +391,6 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
366 return 0; 391 return 0;
367} 392}
368 393
369EXPORT_SYMBOL(acpi_bus_receive_event);
370#endif /* CONFIG_ACPI_PROC_EVENT */ 394#endif /* CONFIG_ACPI_PROC_EVENT */
371 395
372/* -------------------------------------------------------------------------- 396/* --------------------------------------------------------------------------
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index bf513e07b773..6df564f4ca6e 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -130,6 +130,63 @@ static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
130module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644); 130module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
131module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644); 131module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
132 132
133static char trace_method_name[6];
134module_param_string(trace_method_name, trace_method_name, 6, 0644);
135static unsigned int trace_debug_layer;
136module_param(trace_debug_layer, uint, 0644);
137static unsigned int trace_debug_level;
138module_param(trace_debug_level, uint, 0644);
139
140static int param_set_trace_state(const char *val, struct kernel_param *kp)
141{
142 int result = 0;
143
144 if (!strncmp(val, "enable", strlen("enable") - 1)) {
145 result = acpi_debug_trace(trace_method_name, trace_debug_level,
146 trace_debug_layer, 0);
147 if (result)
148 result = -EBUSY;
149 goto exit;
150 }
151
152 if (!strncmp(val, "disable", strlen("disable") - 1)) {
153 int name = 0;
154 result = acpi_debug_trace((char *)&name, trace_debug_level,
155 trace_debug_layer, 0);
156 if (result)
157 result = -EBUSY;
158 goto exit;
159 }
160
161 if (!strncmp(val, "1", 1)) {
162 result = acpi_debug_trace(trace_method_name, trace_debug_level,
163 trace_debug_layer, 1);
164 if (result)
165 result = -EBUSY;
166 goto exit;
167 }
168
169 result = -EINVAL;
170exit:
171 return result;
172}
173
174static int param_get_trace_state(char *buffer, struct kernel_param *kp)
175{
176 if (!acpi_gbl_trace_method_name)
177 return sprintf(buffer, "disable");
178 else {
179 if (acpi_gbl_trace_flags & 1)
180 return sprintf(buffer, "1");
181 else
182 return sprintf(buffer, "enable");
183 }
184 return 0;
185}
186
187module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
188 NULL, 0644);
189
133/* -------------------------------------------------------------------------- 190/* --------------------------------------------------------------------------
134 FS Interface (/proc) 191 FS Interface (/proc)
135 -------------------------------------------------------------------------- */ 192 -------------------------------------------------------------------------- */
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index fc9da4879cbf..f501e083aac7 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -359,7 +359,9 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
359 359
360 status = acpi_os_validate_address(obj_desc->region.space_id, 360 status = acpi_os_validate_address(obj_desc->region.space_id,
361 obj_desc->region.address, 361 obj_desc->region.address,
362 (acpi_size) obj_desc->region.length); 362 (acpi_size) obj_desc->region.length,
363 acpi_ut_get_node_name(node));
364
363 if (ACPI_FAILURE(status)) { 365 if (ACPI_FAILURE(status)) {
364 /* 366 /*
365 * Invalid address/length. We will emit an error message and mark 367 * Invalid address/length. We will emit an error message and mark
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 1dabdf4c07b3..307cef65c247 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -51,6 +51,12 @@ static struct atomic_notifier_head dock_notifier_list;
51static struct platform_device *dock_device; 51static struct platform_device *dock_device;
52static char dock_device_name[] = "dock"; 52static char dock_device_name[] = "dock";
53 53
54static const struct acpi_device_id dock_device_ids[] = {
55 {"LNXDOCK", 0},
56 {"", 0},
57};
58MODULE_DEVICE_TABLE(acpi, dock_device_ids);
59
54struct dock_station { 60struct dock_station {
55 acpi_handle handle; 61 acpi_handle handle;
56 unsigned long last_dock_time; 62 unsigned long last_dock_time;
@@ -680,7 +686,7 @@ static ssize_t show_docked(struct device *dev,
680 return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); 686 return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
681 687
682} 688}
683DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); 689static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
684 690
685/* 691/*
686 * show_flags - read method for flags file in sysfs 692 * show_flags - read method for flags file in sysfs
@@ -691,7 +697,7 @@ static ssize_t show_flags(struct device *dev,
691 return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); 697 return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
692 698
693} 699}
694DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); 700static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
695 701
696/* 702/*
697 * write_undock - write method for "undock" file in sysfs 703 * write_undock - write method for "undock" file in sysfs
@@ -707,7 +713,7 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
707 ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST); 713 ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
708 return ret ? ret: count; 714 return ret ? ret: count;
709} 715}
710DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock); 716static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
711 717
712/* 718/*
713 * show_dock_uid - read method for "uid" file in sysfs 719 * show_dock_uid - read method for "uid" file in sysfs
@@ -723,7 +729,7 @@ static ssize_t show_dock_uid(struct device *dev,
723 729
724 return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); 730 return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
725} 731}
726DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); 732static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
727 733
728/** 734/**
729 * dock_add - add a new dock station 735 * dock_add - add a new dock station
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 987b967c7467..7222a18a0319 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -573,7 +573,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
573 void *handler_context, void *region_context) 573 void *handler_context, void *region_context)
574{ 574{
575 struct acpi_ec *ec = handler_context; 575 struct acpi_ec *ec = handler_context;
576 int result = 0, i = 0; 576 int result = 0, i;
577 u8 temp = 0; 577 u8 temp = 0;
578 578
579 if ((address > 0xFF) || !value || !handler_context) 579 if ((address > 0xFF) || !value || !handler_context)
@@ -585,7 +585,18 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
585 if (bits != 8 && acpi_strict) 585 if (bits != 8 && acpi_strict)
586 return AE_BAD_PARAMETER; 586 return AE_BAD_PARAMETER;
587 587
588 while (bits - i > 0) { 588 acpi_ec_burst_enable(ec);
589
590 if (function == ACPI_READ) {
591 result = acpi_ec_read(ec, address, &temp);
592 *value = temp;
593 } else {
594 temp = 0xff & (*value);
595 result = acpi_ec_write(ec, address, temp);
596 }
597
598 for (i = 8; unlikely(bits - i > 0); i += 8) {
599 ++address;
589 if (function == ACPI_READ) { 600 if (function == ACPI_READ) {
590 result = acpi_ec_read(ec, address, &temp); 601 result = acpi_ec_read(ec, address, &temp);
591 (*value) |= ((acpi_integer)temp) << i; 602 (*value) |= ((acpi_integer)temp) << i;
@@ -593,10 +604,10 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
593 temp = 0xff & ((*value) >> i); 604 temp = 0xff & ((*value) >> i);
594 result = acpi_ec_write(ec, address, temp); 605 result = acpi_ec_write(ec, address, temp);
595 } 606 }
596 i += 8;
597 ++address;
598 } 607 }
599 608
609 acpi_ec_burst_disable(ec);
610
600 switch (result) { 611 switch (result) {
601 case -EINVAL: 612 case -EINVAL:
602 return AE_BAD_PARAMETER; 613 return AE_BAD_PARAMETER;
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 5c95863f8fa9..5479dc0eeeec 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -109,6 +109,34 @@ static const struct file_operations acpi_system_event_ops = {
109}; 109};
110#endif /* CONFIG_ACPI_PROC_EVENT */ 110#endif /* CONFIG_ACPI_PROC_EVENT */
111 111
112/* ACPI notifier chain */
113BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
114
115int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
116{
117 struct acpi_bus_event event;
118
119 strcpy(event.device_class, dev->pnp.device_class);
120 strcpy(event.bus_id, dev->pnp.bus_id);
121 event.type = type;
122 event.data = data;
123 return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
124 == NOTIFY_BAD) ? -EINVAL : 0;
125}
126EXPORT_SYMBOL(acpi_notifier_call_chain);
127
128int register_acpi_notifier(struct notifier_block *nb)
129{
130 return blocking_notifier_chain_register(&acpi_chain_head, nb);
131}
132EXPORT_SYMBOL(register_acpi_notifier);
133
134int unregister_acpi_notifier(struct notifier_block *nb)
135{
136 return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
137}
138EXPORT_SYMBOL(unregister_acpi_notifier);
139
112#ifdef CONFIG_NET 140#ifdef CONFIG_NET
113static unsigned int acpi_event_seqnum; 141static unsigned int acpi_event_seqnum;
114struct acpi_genl_event { 142struct acpi_genl_event {
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index e41287815ea1..3048801a37b5 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -259,7 +259,7 @@ u32 acpi_ev_fixed_event_detect(void)
259 enable_bit_mask)) { 259 enable_bit_mask)) {
260 260
261 /* Found an active (signalled) event */ 261 /* Found an active (signalled) event */
262 262 acpi_os_fixed_event_count(i);
263 int_status |= acpi_ev_fixed_event_dispatch((u32) i); 263 int_status |= acpi_ev_fixed_event_dispatch((u32) i);
264 } 264 }
265 } 265 }
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index e22f4a973c0f..0dadd2adc800 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -270,18 +270,18 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
270 case ACPI_GPE_TYPE_WAKE_RUN: 270 case ACPI_GPE_TYPE_WAKE_RUN:
271 ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); 271 ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
272 272
273 /*lint -fallthrough */ 273 /* fallthrough */
274 274
275 case ACPI_GPE_TYPE_RUNTIME: 275 case ACPI_GPE_TYPE_RUNTIME:
276 276
277 /* Disable the requested runtime GPE */ 277 /* Disable the requested runtime GPE */
278 278
279 ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); 279 ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
280 status = acpi_hw_write_gpe_enable_reg(gpe_event_info); 280
281 break; 281 /* fallthrough */
282 282
283 default: 283 default:
284 return_ACPI_STATUS(AE_BAD_PARAMETER); 284 acpi_hw_write_gpe_enable_reg(gpe_event_info);
285 } 285 }
286 286
287 return_ACPI_STATUS(AE_OK); 287 return_ACPI_STATUS(AE_OK);
@@ -501,6 +501,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
501 * an interrupt handler. 501 * an interrupt handler.
502 * 502 *
503 ******************************************************************************/ 503 ******************************************************************************/
504static void acpi_ev_asynch_enable_gpe(void *context);
504 505
505static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) 506static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
506{ 507{
@@ -576,22 +577,30 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
576 method_node))); 577 method_node)));
577 } 578 }
578 } 579 }
580 /* Defer enabling of GPE until all notify handlers are done */
581 acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
582 gpe_event_info);
583 return_VOID;
584}
579 585
580 if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == 586static void acpi_ev_asynch_enable_gpe(void *context)
587{
588 struct acpi_gpe_event_info *gpe_event_info = context;
589 acpi_status status;
590 if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
581 ACPI_GPE_LEVEL_TRIGGERED) { 591 ACPI_GPE_LEVEL_TRIGGERED) {
582 /* 592 /*
583 * GPE is level-triggered, we clear the GPE status bit after 593 * GPE is level-triggered, we clear the GPE status bit after
584 * handling the event. 594 * handling the event.
585 */ 595 */
586 status = acpi_hw_clear_gpe(&local_gpe_event_info); 596 status = acpi_hw_clear_gpe(gpe_event_info);
587 if (ACPI_FAILURE(status)) { 597 if (ACPI_FAILURE(status)) {
588 return_VOID; 598 return_VOID;
589 } 599 }
590 } 600 }
591 601
592 /* Enable this GPE */ 602 /* Enable this GPE */
593 603 (void)acpi_hw_write_gpe_enable_reg(gpe_event_info);
594 (void)acpi_hw_write_gpe_enable_reg(&local_gpe_event_info);
595 return_VOID; 604 return_VOID;
596} 605}
597 606
@@ -618,7 +627,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
618 627
619 ACPI_FUNCTION_TRACE(ev_gpe_dispatch); 628 ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
620 629
621 acpi_gpe_count++; 630 acpi_os_gpe_count(gpe_number);
622 631
623 /* 632 /*
624 * If edge-triggered, clear the GPE status bit now. Note that 633 * If edge-triggered, clear the GPE status bit now. Note that
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index a6e149d692cb..48cb705b274a 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -30,7 +30,7 @@
30#include <linux/proc_fs.h> 30#include <linux/proc_fs.h>
31#include <linux/seq_file.h> 31#include <linux/seq_file.h>
32#include <asm/uaccess.h> 32#include <asm/uaccess.h>
33 33#include <linux/thermal.h>
34#include <acpi/acpi_bus.h> 34#include <acpi/acpi_bus.h>
35#include <acpi/acpi_drivers.h> 35#include <acpi/acpi_drivers.h>
36 36
@@ -68,9 +68,55 @@ static struct acpi_driver acpi_fan_driver = {
68 }, 68 },
69}; 69};
70 70
71/* thermal cooling device callbacks */
72static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf)
73{
74 /* ACPI fan device only support two states: ON/OFF */
75 return sprintf(buf, "1\n");
76}
77
78static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
79{
80 struct acpi_device *device = cdev->devdata;
81 int state;
82 int result;
83
84 if (!device)
85 return -EINVAL;
86
87 result = acpi_bus_get_power(device->handle, &state);
88 if (result)
89 return result;
90
91 return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
92 (state == ACPI_STATE_D0 ? "1" : "unknown"));
93}
94
95static int
96fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
97{
98 struct acpi_device *device = cdev->devdata;
99 int result;
100
101 if (!device || (state != 0 && state != 1))
102 return -EINVAL;
103
104 result = acpi_bus_set_power(device->handle,
105 state ? ACPI_STATE_D0 : ACPI_STATE_D3);
106
107 return result;
108}
109
110static struct thermal_cooling_device_ops fan_cooling_ops = {
111 .get_max_state = fan_get_max_state,
112 .get_cur_state = fan_get_cur_state,
113 .set_cur_state = fan_set_cur_state,
114};
115
71/* -------------------------------------------------------------------------- 116/* --------------------------------------------------------------------------
72 FS Interface (/proc) 117 FS Interface (/proc)
73 -------------------------------------------------------------------------- */ 118 -------------------------------------------------------------------------- */
119#ifdef CONFIG_ACPI_PROCFS
74 120
75static struct proc_dir_entry *acpi_fan_dir; 121static struct proc_dir_entry *acpi_fan_dir;
76 122
@@ -171,7 +217,17 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
171 217
172 return 0; 218 return 0;
173} 219}
220#else
221static int acpi_fan_add_fs(struct acpi_device *device)
222{
223 return 0;
224}
174 225
226static int acpi_fan_remove_fs(struct acpi_device *device)
227{
228 return 0;
229}
230#endif
175/* -------------------------------------------------------------------------- 231/* --------------------------------------------------------------------------
176 Driver Interface 232 Driver Interface
177 -------------------------------------------------------------------------- */ 233 -------------------------------------------------------------------------- */
@@ -179,9 +235,8 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
179static int acpi_fan_add(struct acpi_device *device) 235static int acpi_fan_add(struct acpi_device *device)
180{ 236{
181 int result = 0; 237 int result = 0;
182 struct acpi_fan *fan = NULL;
183 int state = 0; 238 int state = 0;
184 239 struct thermal_cooling_device *cdev;
185 240
186 if (!device) 241 if (!device)
187 return -EINVAL; 242 return -EINVAL;
@@ -199,6 +254,25 @@ static int acpi_fan_add(struct acpi_device *device)
199 acpi_bus_set_power(device->handle, state); 254 acpi_bus_set_power(device->handle, state);
200 device->flags.force_power_state = 0; 255 device->flags.force_power_state = 0;
201 256
257 cdev = thermal_cooling_device_register("Fan", device,
258 &fan_cooling_ops);
259 if (cdev)
260 printk(KERN_INFO PREFIX
261 "%s is registered as cooling_device%d\n",
262 device->dev.bus_id, cdev->id);
263 else
264 goto end;
265 acpi_driver_data(device) = cdev;
266 result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj,
267 "thermal_cooling");
268 if (result)
269 return result;
270
271 result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj,
272 "device");
273 if (result)
274 return result;
275
202 result = acpi_fan_add_fs(device); 276 result = acpi_fan_add_fs(device);
203 if (result) 277 if (result)
204 goto end; 278 goto end;
@@ -208,18 +282,20 @@ static int acpi_fan_add(struct acpi_device *device)
208 !device->power.state ? "on" : "off"); 282 !device->power.state ? "on" : "off");
209 283
210 end: 284 end:
211 if (result)
212 kfree(fan);
213
214 return result; 285 return result;
215} 286}
216 287
217static int acpi_fan_remove(struct acpi_device *device, int type) 288static int acpi_fan_remove(struct acpi_device *device, int type)
218{ 289{
219 if (!device || !acpi_driver_data(device)) 290 struct thermal_cooling_device *cdev = acpi_driver_data(device);
291
292 if (!device || !cdev)
220 return -EINVAL; 293 return -EINVAL;
221 294
222 acpi_fan_remove_fs(device); 295 acpi_fan_remove_fs(device);
296 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
297 sysfs_remove_link(&cdev->device.kobj, "device");
298 thermal_cooling_device_unregister(cdev);
223 299
224 return 0; 300 return 0;
225} 301}
@@ -261,10 +337,12 @@ static int __init acpi_fan_init(void)
261 int result = 0; 337 int result = 0;
262 338
263 339
340#ifdef CONFIG_ACPI_PROCFS
264 acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir); 341 acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
265 if (!acpi_fan_dir) 342 if (!acpi_fan_dir)
266 return -ENODEV; 343 return -ENODEV;
267 acpi_fan_dir->owner = THIS_MODULE; 344 acpi_fan_dir->owner = THIS_MODULE;
345#endif
268 346
269 result = acpi_bus_register_driver(&acpi_fan_driver); 347 result = acpi_bus_register_driver(&acpi_fan_driver);
270 if (result < 0) { 348 if (result < 0) {
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 4893e256e399..eda0978b57c6 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -36,8 +36,6 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
36 return -ENODEV; 36 return -ENODEV;
37} 37}
38 38
39EXPORT_SYMBOL(register_acpi_bus_type);
40
41int unregister_acpi_bus_type(struct acpi_bus_type *type) 39int unregister_acpi_bus_type(struct acpi_bus_type *type)
42{ 40{
43 if (acpi_disabled) 41 if (acpi_disabled)
@@ -53,8 +51,6 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type)
53 return -ENODEV; 51 return -ENODEV;
54} 52}
55 53
56EXPORT_SYMBOL(unregister_acpi_bus_type);
57
58static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type) 54static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
59{ 55{
60 struct acpi_bus_type *tmp, *ret = NULL; 56 struct acpi_bus_type *tmp, *ret = NULL;
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index fd1c4ba63367..058d0be5cbe2 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -286,13 +286,13 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
286 } 286 }
287 287
288 /* 288 /*
289 * 1) Disable/Clear all GPEs
289 * 2) Enable all wakeup GPEs 290 * 2) Enable all wakeup GPEs
290 */ 291 */
291 status = acpi_hw_disable_all_gpes(); 292 status = acpi_hw_disable_all_gpes();
292 if (ACPI_FAILURE(status)) { 293 if (ACPI_FAILURE(status)) {
293 return_ACPI_STATUS(status); 294 return_ACPI_STATUS(status);
294 } 295 }
295
296 acpi_gbl_system_awake_and_running = FALSE; 296 acpi_gbl_system_awake_and_running = FALSE;
297 297
298 status = acpi_hw_enable_all_wakeup_gpes(); 298 status = acpi_hw_enable_all_wakeup_gpes();
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index f39fbc6b9237..b92133faf5b7 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -443,6 +443,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
443 struct acpica_device_id hid; 443 struct acpica_device_id hid;
444 struct acpi_compatible_id_list *cid; 444 struct acpi_compatible_id_list *cid;
445 acpi_native_uint i; 445 acpi_native_uint i;
446 int found;
446 447
447 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 448 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
448 if (ACPI_FAILURE(status)) { 449 if (ACPI_FAILURE(status)) {
@@ -496,16 +497,19 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
496 497
497 /* Walk the CID list */ 498 /* Walk the CID list */
498 499
500 found = 0;
499 for (i = 0; i < cid->count; i++) { 501 for (i = 0; i < cid->count; i++) {
500 if (ACPI_STRNCMP(cid->id[i].value, info->hid, 502 if (ACPI_STRNCMP(cid->id[i].value, info->hid,
501 sizeof(struct 503 sizeof(struct
502 acpi_compatible_id)) != 504 acpi_compatible_id)) ==
503 0) { 505 0) {
504 ACPI_FREE(cid); 506 found = 1;
505 return (AE_OK); 507 break;
506 } 508 }
507 } 509 }
508 ACPI_FREE(cid); 510 ACPI_FREE(cid);
511 if (!found)
512 return (AE_OK);
509 } 513 }
510 } 514 }
511 515
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 0822d9fc1cb4..5d59cb33b1a5 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -78,6 +78,7 @@ int acpi_map_pxm_to_node(int pxm)
78 return node; 78 return node;
79} 79}
80 80
81#if 0
81void __cpuinit acpi_unmap_pxm_to_node(int node) 82void __cpuinit acpi_unmap_pxm_to_node(int node)
82{ 83{
83 int pxm = node_to_pxm_map[node]; 84 int pxm = node_to_pxm_map[node];
@@ -85,6 +86,7 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
85 node_to_pxm_map[node] = PXM_INVAL; 86 node_to_pxm_map[node] = PXM_INVAL;
86 node_clear(node, nodes_found_map); 87 node_clear(node, nodes_found_map);
87} 88}
89#endif /* 0 */
88 90
89static void __init 91static void __init
90acpi_table_print_srat_entry(struct acpi_subtable_header *header) 92acpi_table_print_srat_entry(struct acpi_subtable_header *header)
@@ -247,7 +249,6 @@ int acpi_get_pxm(acpi_handle h)
247 } while (ACPI_SUCCESS(status)); 249 } while (ACPI_SUCCESS(status));
248 return -1; 250 return -1;
249} 251}
250EXPORT_SYMBOL(acpi_get_pxm);
251 252
252int acpi_get_node(acpi_handle *handle) 253int acpi_get_node(acpi_handle *handle)
253{ 254{
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index e53fb516f9d4..27ccd68b8f46 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -44,6 +44,8 @@
44#include <asm/uaccess.h> 44#include <asm/uaccess.h>
45 45
46#include <linux/efi.h> 46#include <linux/efi.h>
47#include <linux/ioport.h>
48#include <linux/list.h>
47 49
48#define _COMPONENT ACPI_OS_SERVICES 50#define _COMPONENT ACPI_OS_SERVICES
49ACPI_MODULE_NAME("osl"); 51ACPI_MODULE_NAME("osl");
@@ -74,9 +76,25 @@ static void *acpi_irq_context;
74static struct workqueue_struct *kacpid_wq; 76static struct workqueue_struct *kacpid_wq;
75static struct workqueue_struct *kacpi_notify_wq; 77static struct workqueue_struct *kacpi_notify_wq;
76 78
79struct acpi_res_list {
80 resource_size_t start;
81 resource_size_t end;
82 acpi_adr_space_type resource_type; /* IO port, System memory, ...*/
83 char name[5]; /* only can have a length of 4 chars, make use of this
84 one instead of res->name, no need to kalloc then */
85 struct list_head resource_list;
86};
87
88static LIST_HEAD(resource_list_head);
89static DEFINE_SPINLOCK(acpi_res_lock);
90
77#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ 91#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
78static char osi_additional_string[OSI_STRING_LENGTH_MAX]; 92static char osi_additional_string[OSI_STRING_LENGTH_MAX];
79 93
94#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
95static int acpi_no_initrd_override;
96#endif
97
80/* 98/*
81 * "Ode to _OSI(Linux)" 99 * "Ode to _OSI(Linux)"
82 * 100 *
@@ -120,7 +138,7 @@ static char osi_additional_string[OSI_STRING_LENGTH_MAX];
120 */ 138 */
121#define OSI_LINUX_ENABLE 0 139#define OSI_LINUX_ENABLE 0
122 140
123struct osi_linux { 141static struct osi_linux {
124 unsigned int enable:1; 142 unsigned int enable:1;
125 unsigned int dmi:1; 143 unsigned int dmi:1;
126 unsigned int cmdline:1; 144 unsigned int cmdline:1;
@@ -219,8 +237,6 @@ void acpi_os_printf(const char *fmt, ...)
219 va_end(args); 237 va_end(args);
220} 238}
221 239
222EXPORT_SYMBOL(acpi_os_printf);
223
224void acpi_os_vprintf(const char *fmt, va_list args) 240void acpi_os_vprintf(const char *fmt, va_list args)
225{ 241{
226 static char buffer[512]; 242 static char buffer[512];
@@ -250,11 +266,16 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
250 "System description tables not found\n"); 266 "System description tables not found\n");
251 return 0; 267 return 0;
252 } 268 }
253 } else 269 } else {
254 return acpi_find_rsdp(); 270 acpi_physical_address pa = 0;
271
272 acpi_find_root_pointer(&pa);
273 return pa;
274 }
255} 275}
256 276
257void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size) 277void __iomem *__init_refok
278acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
258{ 279{
259 if (phys > ULONG_MAX) { 280 if (phys > ULONG_MAX) {
260 printk(KERN_ERR PREFIX "Cannot map memory that high\n"); 281 printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@ -312,6 +333,67 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
312 return AE_OK; 333 return AE_OK;
313} 334}
314 335
336#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
337struct acpi_table_header *acpi_find_dsdt_initrd(void)
338{
339 struct file *firmware_file;
340 mm_segment_t oldfs;
341 unsigned long len, len2;
342 struct acpi_table_header *dsdt_buffer, *ret = NULL;
343 struct kstat stat;
344 char *ramfs_dsdt_name = "/DSDT.aml";
345
346 printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT");
347
348 /*
349 * Never do this at home, only the user-space is allowed to open a file.
350 * The clean way would be to use the firmware loader.
351 * But this code must be run before there is any userspace available.
352 * A static/init firmware infrastructure doesn't exist yet...
353 */
354 if (vfs_stat(ramfs_dsdt_name, &stat) < 0)
355 return ret;
356
357 len = stat.size;
358 /* check especially against empty files */
359 if (len <= 4) {
360 printk(KERN_ERR PREFIX "Failed: DSDT only %lu bytes.\n", len);
361 return ret;
362 }
363
364 firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0);
365 if (IS_ERR(firmware_file)) {
366 printk(KERN_ERR PREFIX "Failed to open %s.\n", ramfs_dsdt_name);
367 return ret;
368 }
369
370 dsdt_buffer = kmalloc(len, GFP_ATOMIC);
371 if (!dsdt_buffer) {
372 printk(KERN_ERR PREFIX "Failed to allocate %lu bytes.\n", len);
373 goto err;
374 }
375
376 oldfs = get_fs();
377 set_fs(KERNEL_DS);
378 len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len,
379 &firmware_file->f_pos);
380 set_fs(oldfs);
381 if (len2 < len) {
382 printk(KERN_ERR PREFIX "Failed to read %lu bytes from %s.\n",
383 len, ramfs_dsdt_name);
384 ACPI_FREE(dsdt_buffer);
385 goto err;
386 }
387
388 printk(KERN_INFO PREFIX "Found %lu byte DSDT in %s.\n",
389 len, ramfs_dsdt_name);
390 ret = dsdt_buffer;
391err:
392 filp_close(firmware_file, NULL);
393 return ret;
394}
395#endif
396
315acpi_status 397acpi_status
316acpi_os_table_override(struct acpi_table_header * existing_table, 398acpi_os_table_override(struct acpi_table_header * existing_table,
317 struct acpi_table_header ** new_table) 399 struct acpi_table_header ** new_table)
@@ -319,20 +401,52 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
319 if (!existing_table || !new_table) 401 if (!existing_table || !new_table)
320 return AE_BAD_PARAMETER; 402 return AE_BAD_PARAMETER;
321 403
404 *new_table = NULL;
405
322#ifdef CONFIG_ACPI_CUSTOM_DSDT 406#ifdef CONFIG_ACPI_CUSTOM_DSDT
323 if (strncmp(existing_table->signature, "DSDT", 4) == 0) 407 if (strncmp(existing_table->signature, "DSDT", 4) == 0)
324 *new_table = (struct acpi_table_header *)AmlCode; 408 *new_table = (struct acpi_table_header *)AmlCode;
325 else
326 *new_table = NULL;
327#else
328 *new_table = NULL;
329#endif 409#endif
410#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
411 if ((strncmp(existing_table->signature, "DSDT", 4) == 0) &&
412 !acpi_no_initrd_override) {
413 struct acpi_table_header *initrd_table;
414
415 initrd_table = acpi_find_dsdt_initrd();
416 if (initrd_table)
417 *new_table = initrd_table;
418 }
419#endif
420 if (*new_table != NULL) {
421 printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], "
422 "this is unsafe: tainting kernel\n",
423 existing_table->signature,
424 existing_table->oem_table_id);
425 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
426 }
330 return AE_OK; 427 return AE_OK;
331} 428}
332 429
430#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
431int __init acpi_no_initrd_override_setup(char *s)
432{
433 acpi_no_initrd_override = 1;
434 return 1;
435}
436__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup);
437#endif
438
333static irqreturn_t acpi_irq(int irq, void *dev_id) 439static irqreturn_t acpi_irq(int irq, void *dev_id)
334{ 440{
335 return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE; 441 u32 handled;
442
443 handled = (*acpi_irq_handler) (acpi_irq_context);
444
445 if (handled) {
446 acpi_irq_handled++;
447 return IRQ_HANDLED;
448 } else
449 return IRQ_NONE;
336} 450}
337 451
338acpi_status 452acpi_status
@@ -341,6 +455,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
341{ 455{
342 unsigned int irq; 456 unsigned int irq;
343 457
458 acpi_irq_stats_init();
459
344 /* 460 /*
345 * Ignore the GSI from the core, and use the value in our copy of the 461 * Ignore the GSI from the core, and use the value in our copy of the
346 * FADT. It may not be the same if an interrupt source override exists 462 * FADT. It may not be the same if an interrupt source override exists
@@ -384,8 +500,6 @@ void acpi_os_sleep(acpi_integer ms)
384 schedule_timeout_interruptible(msecs_to_jiffies(ms)); 500 schedule_timeout_interruptible(msecs_to_jiffies(ms));
385} 501}
386 502
387EXPORT_SYMBOL(acpi_os_sleep);
388
389void acpi_os_stall(u32 us) 503void acpi_os_stall(u32 us)
390{ 504{
391 while (us) { 505 while (us) {
@@ -399,8 +513,6 @@ void acpi_os_stall(u32 us)
399 } 513 }
400} 514}
401 515
402EXPORT_SYMBOL(acpi_os_stall);
403
404/* 516/*
405 * Support ACPI 3.0 AML Timer operand 517 * Support ACPI 3.0 AML Timer operand
406 * Returns 64-bit free-running, monotonically increasing timer 518 * Returns 64-bit free-running, monotonically increasing timer
@@ -550,8 +662,6 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
550 return (result ? AE_ERROR : AE_OK); 662 return (result ? AE_ERROR : AE_OK);
551} 663}
552 664
553EXPORT_SYMBOL(acpi_os_read_pci_configuration);
554
555acpi_status 665acpi_status
556acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, 666acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
557 acpi_integer value, u32 width) 667 acpi_integer value, u32 width)
@@ -661,25 +771,6 @@ static void acpi_os_execute_deferred(struct work_struct *work)
661 dpc->function(dpc->context); 771 dpc->function(dpc->context);
662 kfree(dpc); 772 kfree(dpc);
663 773
664 /* Yield cpu to notify thread */
665 cond_resched();
666
667 return;
668}
669
670static void acpi_os_execute_notify(struct work_struct *work)
671{
672 struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
673
674 if (!dpc) {
675 printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
676 return;
677 }
678
679 dpc->function(dpc->context);
680
681 kfree(dpc);
682
683 return; 774 return;
684} 775}
685 776
@@ -703,7 +794,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
703{ 794{
704 acpi_status status = AE_OK; 795 acpi_status status = AE_OK;
705 struct acpi_os_dpc *dpc; 796 struct acpi_os_dpc *dpc;
706 797 struct workqueue_struct *queue;
707 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 798 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
708 "Scheduling function [%p(%p)] for deferred execution.\n", 799 "Scheduling function [%p(%p)] for deferred execution.\n",
709 function, context)); 800 function, context));
@@ -727,20 +818,13 @@ acpi_status acpi_os_execute(acpi_execute_type type,
727 dpc->function = function; 818 dpc->function = function;
728 dpc->context = context; 819 dpc->context = context;
729 820
730 if (type == OSL_NOTIFY_HANDLER) { 821 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
731 INIT_WORK(&dpc->work, acpi_os_execute_notify); 822 queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
732 if (!queue_work(kacpi_notify_wq, &dpc->work)) { 823 if (!queue_work(queue, &dpc->work)) {
733 status = AE_ERROR; 824 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
734 kfree(dpc); 825 "Call to queue_work() failed.\n"));
735 } 826 status = AE_ERROR;
736 } else { 827 kfree(dpc);
737 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
738 if (!queue_work(kacpid_wq, &dpc->work)) {
739 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
740 "Call to queue_work() failed.\n"));
741 status = AE_ERROR;
742 kfree(dpc);
743 }
744 } 828 }
745 return_ACPI_STATUS(status); 829 return_ACPI_STATUS(status);
746} 830}
@@ -793,8 +877,6 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
793 return AE_OK; 877 return AE_OK;
794} 878}
795 879
796EXPORT_SYMBOL(acpi_os_create_semaphore);
797
798/* 880/*
799 * TODO: A better way to delete semaphores? Linux doesn't have a 881 * TODO: A better way to delete semaphores? Linux doesn't have a
800 * 'delete_semaphore()' function -- may result in an invalid 882 * 'delete_semaphore()' function -- may result in an invalid
@@ -818,8 +900,6 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle)
818 return AE_OK; 900 return AE_OK;
819} 901}
820 902
821EXPORT_SYMBOL(acpi_os_delete_semaphore);
822
823/* 903/*
824 * TODO: The kernel doesn't have a 'down_timeout' function -- had to 904 * TODO: The kernel doesn't have a 'down_timeout' function -- had to
825 * improvise. The process is to sleep for one scheduler quantum 905 * improvise. The process is to sleep for one scheduler quantum
@@ -912,8 +992,6 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
912 return status; 992 return status;
913} 993}
914 994
915EXPORT_SYMBOL(acpi_os_wait_semaphore);
916
917/* 995/*
918 * TODO: Support for units > 1? 996 * TODO: Support for units > 1?
919 */ 997 */
@@ -936,8 +1014,6 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
936 return AE_OK; 1014 return AE_OK;
937} 1015}
938 1016
939EXPORT_SYMBOL(acpi_os_signal_semaphore);
940
941#ifdef ACPI_FUTURE_USAGE 1017#ifdef ACPI_FUTURE_USAGE
942u32 acpi_os_get_line(char *buffer) 1018u32 acpi_os_get_line(char *buffer)
943{ 1019{
@@ -981,8 +1057,6 @@ acpi_status acpi_os_signal(u32 function, void *info)
981 return AE_OK; 1057 return AE_OK;
982} 1058}
983 1059
984EXPORT_SYMBOL(acpi_os_signal);
985
986static int __init acpi_os_name_setup(char *str) 1060static int __init acpi_os_name_setup(char *str)
987{ 1061{
988 char *p = acpi_os_name; 1062 char *p = acpi_os_name;
@@ -1102,6 +1176,128 @@ static int __init acpi_wake_gpes_always_on_setup(char *str)
1102 1176
1103__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); 1177__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
1104 1178
1179/* Check of resource interference between native drivers and ACPI
1180 * OperationRegions (SystemIO and System Memory only).
1181 * IO ports and memory declared in ACPI might be used by the ACPI subsystem
1182 * in arbitrary AML code and can interfere with legacy drivers.
1183 * acpi_enforce_resources= can be set to:
1184 *
1185 * - strict (2)
1186 * -> further driver trying to access the resources will not load
1187 * - lax (default) (1)
1188 * -> further driver trying to access the resources will load, but you
1189 * get a system message that something might go wrong...
1190 *
1191 * - no (0)
1192 * -> ACPI Operation Region resources will not be registered
1193 *
1194 */
1195#define ENFORCE_RESOURCES_STRICT 2
1196#define ENFORCE_RESOURCES_LAX 1
1197#define ENFORCE_RESOURCES_NO 0
1198
1199static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
1200
1201static int __init acpi_enforce_resources_setup(char *str)
1202{
1203 if (str == NULL || *str == '\0')
1204 return 0;
1205
1206 if (!strcmp("strict", str))
1207 acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
1208 else if (!strcmp("lax", str))
1209 acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
1210 else if (!strcmp("no", str))
1211 acpi_enforce_resources = ENFORCE_RESOURCES_NO;
1212
1213 return 1;
1214}
1215
1216__setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
1217
1218/* Check for resource conflicts between ACPI OperationRegions and native
1219 * drivers */
1220int acpi_check_resource_conflict(struct resource *res)
1221{
1222 struct acpi_res_list *res_list_elem;
1223 int ioport;
1224 int clash = 0;
1225
1226 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1227 return 0;
1228 if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))
1229 return 0;
1230
1231 ioport = res->flags & IORESOURCE_IO;
1232
1233 spin_lock(&acpi_res_lock);
1234 list_for_each_entry(res_list_elem, &resource_list_head,
1235 resource_list) {
1236 if (ioport && (res_list_elem->resource_type
1237 != ACPI_ADR_SPACE_SYSTEM_IO))
1238 continue;
1239 if (!ioport && (res_list_elem->resource_type
1240 != ACPI_ADR_SPACE_SYSTEM_MEMORY))
1241 continue;
1242
1243 if (res->end < res_list_elem->start
1244 || res_list_elem->end < res->start)
1245 continue;
1246 clash = 1;
1247 break;
1248 }
1249 spin_unlock(&acpi_res_lock);
1250
1251 if (clash) {
1252 if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
1253 printk(KERN_INFO "%sACPI: %s resource %s [0x%llx-0x%llx]"
1254 " conflicts with ACPI region %s"
1255 " [0x%llx-0x%llx]\n",
1256 acpi_enforce_resources == ENFORCE_RESOURCES_LAX
1257 ? KERN_WARNING : KERN_ERR,
1258 ioport ? "I/O" : "Memory", res->name,
1259 (long long) res->start, (long long) res->end,
1260 res_list_elem->name,
1261 (long long) res_list_elem->start,
1262 (long long) res_list_elem->end);
1263 printk(KERN_INFO "ACPI: Device needs an ACPI driver\n");
1264 }
1265 if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
1266 return -EBUSY;
1267 }
1268 return 0;
1269}
1270EXPORT_SYMBOL(acpi_check_resource_conflict);
1271
1272int acpi_check_region(resource_size_t start, resource_size_t n,
1273 const char *name)
1274{
1275 struct resource res = {
1276 .start = start,
1277 .end = start + n - 1,
1278 .name = name,
1279 .flags = IORESOURCE_IO,
1280 };
1281
1282 return acpi_check_resource_conflict(&res);
1283}
1284EXPORT_SYMBOL(acpi_check_region);
1285
1286int acpi_check_mem_region(resource_size_t start, resource_size_t n,
1287 const char *name)
1288{
1289 struct resource res = {
1290 .start = start,
1291 .end = start + n - 1,
1292 .name = name,
1293 .flags = IORESOURCE_MEM,
1294 };
1295
1296 return acpi_check_resource_conflict(&res);
1297
1298}
1299EXPORT_SYMBOL(acpi_check_mem_region);
1300
1105/* 1301/*
1106 * Acquire a spinlock. 1302 * Acquire a spinlock.
1107 * 1303 *
@@ -1213,24 +1409,24 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
1213 * 1409 *
1214 * Returns 0 on success 1410 * Returns 0 on success
1215 */ 1411 */
1216int acpi_dmi_dump(void) 1412static int acpi_dmi_dump(void)
1217{ 1413{
1218 1414
1219 if (!dmi_available) 1415 if (!dmi_available)
1220 return -1; 1416 return -1;
1221 1417
1222 printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n", 1418 printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
1223 dmi_get_slot(DMI_SYS_VENDOR)); 1419 dmi_get_system_info(DMI_SYS_VENDOR));
1224 printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n", 1420 printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
1225 dmi_get_slot(DMI_PRODUCT_NAME)); 1421 dmi_get_system_info(DMI_PRODUCT_NAME));
1226 printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n", 1422 printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
1227 dmi_get_slot(DMI_PRODUCT_VERSION)); 1423 dmi_get_system_info(DMI_PRODUCT_VERSION));
1228 printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n", 1424 printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
1229 dmi_get_slot(DMI_BOARD_NAME)); 1425 dmi_get_system_info(DMI_BOARD_NAME));
1230 printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n", 1426 printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
1231 dmi_get_slot(DMI_BIOS_VENDOR)); 1427 dmi_get_system_info(DMI_BIOS_VENDOR));
1232 printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n", 1428 printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
1233 dmi_get_slot(DMI_BIOS_DATE)); 1429 dmi_get_system_info(DMI_BIOS_DATE));
1234 1430
1235 return 0; 1431 return 0;
1236} 1432}
@@ -1303,10 +1499,46 @@ acpi_status
1303acpi_os_validate_address ( 1499acpi_os_validate_address (
1304 u8 space_id, 1500 u8 space_id,
1305 acpi_physical_address address, 1501 acpi_physical_address address,
1306 acpi_size length) 1502 acpi_size length,
1503 char *name)
1307{ 1504{
1505 struct acpi_res_list *res;
1506 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1507 return AE_OK;
1308 1508
1309 return AE_OK; 1509 switch (space_id) {
1510 case ACPI_ADR_SPACE_SYSTEM_IO:
1511 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
1512 /* Only interference checks against SystemIO and SytemMemory
1513 are needed */
1514 res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL);
1515 if (!res)
1516 return AE_OK;
1517 /* ACPI names are fixed to 4 bytes, still better use strlcpy */
1518 strlcpy(res->name, name, 5);
1519 res->start = address;
1520 res->end = address + length - 1;
1521 res->resource_type = space_id;
1522 spin_lock(&acpi_res_lock);
1523 list_add(&res->resource_list, &resource_list_head);
1524 spin_unlock(&acpi_res_lock);
1525 pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, "
1526 "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
1527 ? "SystemIO" : "System Memory",
1528 (unsigned long long)res->start,
1529 (unsigned long long)res->end,
1530 res->name);
1531 break;
1532 case ACPI_ADR_SPACE_PCI_CONFIG:
1533 case ACPI_ADR_SPACE_EC:
1534 case ACPI_ADR_SPACE_SMBUS:
1535 case ACPI_ADR_SPACE_CMOS:
1536 case ACPI_ADR_SPACE_PCI_BAR_TARGET:
1537 case ACPI_ADR_SPACE_DATA_TABLE:
1538 case ACPI_ADR_SPACE_FIXED_HARDWARE:
1539 break;
1540 }
1541 return AE_OK;
1310} 1542}
1311 1543
1312#endif 1544#endif
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index 388300de005d..4b252ea0e952 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -44,6 +44,8 @@ struct acpi_pci_data {
44 struct pci_dev *dev; 44 struct pci_dev *dev;
45}; 45};
46 46
47static int acpi_pci_unbind(struct acpi_device *device);
48
47static void acpi_pci_data_handler(acpi_handle handle, u32 function, 49static void acpi_pci_data_handler(acpi_handle handle, u32 function,
48 void *context) 50 void *context)
49{ 51{
@@ -267,7 +269,7 @@ int acpi_pci_bind(struct acpi_device *device)
267 return result; 269 return result;
268} 270}
269 271
270int acpi_pci_unbind(struct acpi_device *device) 272static int acpi_pci_unbind(struct acpi_device *device)
271{ 273{
272 int result = 0; 274 int result = 0;
273 acpi_status status = AE_OK; 275 acpi_status status = AE_OK;
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 62010c2481b3..7f19859580c7 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -51,10 +51,8 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
51 int bus, 51 int bus,
52 int device, int pin) 52 int device, int pin)
53{ 53{
54 struct list_head *node = NULL;
55 struct acpi_prt_entry *entry = NULL; 54 struct acpi_prt_entry *entry = NULL;
56 55
57
58 if (!acpi_prt.count) 56 if (!acpi_prt.count)
59 return NULL; 57 return NULL;
60 58
@@ -64,8 +62,7 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
64 * 62 *
65 */ 63 */
66 spin_lock(&acpi_prt_lock); 64 spin_lock(&acpi_prt_lock);
67 list_for_each(node, &acpi_prt.entries) { 65 list_for_each_entry(entry, &acpi_prt.entries, node) {
68 entry = list_entry(node, struct acpi_prt_entry, node);
69 if ((segment == entry->id.segment) 66 if ((segment == entry->id.segment)
70 && (bus == entry->id.bus) 67 && (bus == entry->id.bus)
71 && (device == entry->id.device) 68 && (device == entry->id.device)
@@ -478,8 +475,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
478 return 0; 475 return 0;
479} 476}
480 477
481EXPORT_SYMBOL(acpi_pci_irq_enable);
482
483/* FIXME: implement x86/x86_64 version */ 478/* FIXME: implement x86/x86_64 version */
484void __attribute__ ((weak)) acpi_unregister_gsi(u32 i) 479void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)
485{ 480{
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 5400ea173f6f..233c40c51684 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -95,7 +95,7 @@ static struct {
95 int count; 95 int count;
96 struct list_head entries; 96 struct list_head entries;
97} acpi_link; 97} acpi_link;
98DEFINE_MUTEX(acpi_link_lock); 98static DEFINE_MUTEX(acpi_link_lock);
99 99
100/* -------------------------------------------------------------------------- 100/* --------------------------------------------------------------------------
101 PCI Link Device Management 101 PCI Link Device Management
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index af1769a20c7a..76bf6d90c700 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -458,11 +458,9 @@ int acpi_power_transition(struct acpi_device *device, int state)
458 } 458 }
459 459
460 end: 460 end:
461 if (result) { 461 if (result)
462 device->power.state = ACPI_STATE_UNKNOWN; 462 device->power.state = ACPI_STATE_UNKNOWN;
463 printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n", 463 else {
464 device->pnp.bus_id, state);
465 } else {
466 /* We shouldn't change the state till all above operations succeed */ 464 /* We shouldn't change the state till all above operations succeed */
467 device->power.state = state; 465 device->power.state = state;
468 } 466 }
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index e48ee4f8749f..75ccf5d18bf4 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -668,6 +668,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
668 668
669 acpi_processor_power_init(pr, device); 669 acpi_processor_power_init(pr, device);
670 670
671 pr->cdev = thermal_cooling_device_register("Processor", device,
672 &processor_cooling_ops);
673 if (pr->cdev)
674 printk(KERN_INFO PREFIX
675 "%s is registered as cooling_device%d\n",
676 device->dev.bus_id, pr->cdev->id);
677 else
678 goto end;
679
680 result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj,
681 "thermal_cooling");
682 if (result)
683 return result;
684 result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj,
685 "device");
686 if (result)
687 return result;
688
671 if (pr->flags.throttling) { 689 if (pr->flags.throttling) {
672 printk(KERN_INFO PREFIX "%s [%s] (supports", 690 printk(KERN_INFO PREFIX "%s [%s] (supports",
673 acpi_device_name(device), acpi_device_bid(device)); 691 acpi_device_name(device), acpi_device_bid(device));
@@ -791,6 +809,11 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
791 809
792 acpi_processor_remove_fs(device); 810 acpi_processor_remove_fs(device);
793 811
812 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
813 sysfs_remove_link(&pr->cdev->device.kobj, "device");
814 thermal_cooling_device_unregister(pr->cdev);
815 pr->cdev = NULL;
816
794 processors[pr->id] = NULL; 817 processors[pr->id] = NULL;
795 818
796 kfree(pr); 819 kfree(pr);
@@ -812,11 +835,18 @@ static int is_processor_present(acpi_handle handle)
812 835
813 836
814 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 837 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
815 if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) { 838 /*
816 ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present")); 839 * if a processor object does not have an _STA object,
817 return 0; 840 * OSPM assumes that the processor is present.
818 } 841 */
819 return 1; 842 if (status == AE_NOT_FOUND)
843 return 1;
844
845 if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
846 return 1;
847
848 ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
849 return 0;
820} 850}
821 851
822static 852static
@@ -1061,6 +1091,8 @@ static int __init acpi_processor_init(void)
1061 1091
1062 acpi_processor_ppc_init(); 1092 acpi_processor_ppc_init();
1063 1093
1094 acpi_processor_throttling_init();
1095
1064 return 0; 1096 return 0;
1065 1097
1066out_cpuidle: 1098out_cpuidle:
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 199ea2146153..32003fdc91e8 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -98,6 +98,9 @@ module_param(bm_history, uint, 0644);
98 98
99static int acpi_processor_set_power_policy(struct acpi_processor *pr); 99static int acpi_processor_set_power_policy(struct acpi_processor *pr);
100 100
101#else /* CONFIG_CPU_IDLE */
102static unsigned int latency_factor __read_mostly = 2;
103module_param(latency_factor, uint, 0644);
101#endif 104#endif
102 105
103/* 106/*
@@ -201,6 +204,10 @@ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
201 return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2); 204 return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
202} 205}
203 206
207/*
208 * Callers should disable interrupts before the call and enable
209 * interrupts after return.
210 */
204static void acpi_safe_halt(void) 211static void acpi_safe_halt(void)
205{ 212{
206 current_thread_info()->status &= ~TS_POLLING; 213 current_thread_info()->status &= ~TS_POLLING;
@@ -261,7 +268,7 @@ static atomic_t c3_cpu_count;
261/* Common C-state entry for C2, C3, .. */ 268/* Common C-state entry for C2, C3, .. */
262static void acpi_cstate_enter(struct acpi_processor_cx *cstate) 269static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
263{ 270{
264 if (cstate->space_id == ACPI_CSTATE_FFH) { 271 if (cstate->entry_method == ACPI_CSTATE_FFH) {
265 /* Call into architectural FFH based C-state */ 272 /* Call into architectural FFH based C-state */
266 acpi_processor_ffh_cstate_enter(cstate); 273 acpi_processor_ffh_cstate_enter(cstate);
267 } else { 274 } else {
@@ -413,6 +420,8 @@ static void acpi_processor_idle(void)
413 pm_idle_save(); 420 pm_idle_save();
414 else 421 else
415 acpi_safe_halt(); 422 acpi_safe_halt();
423
424 local_irq_enable();
416 return; 425 return;
417 } 426 }
418 427
@@ -521,6 +530,7 @@ static void acpi_processor_idle(void)
521 * skew otherwise. 530 * skew otherwise.
522 */ 531 */
523 sleep_ticks = 0xFFFFFFFF; 532 sleep_ticks = 0xFFFFFFFF;
533 local_irq_enable();
524 break; 534 break;
525 535
526 case ACPI_STATE_C2: 536 case ACPI_STATE_C2:
@@ -922,20 +932,20 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
922 cx.address = reg->address; 932 cx.address = reg->address;
923 cx.index = current_count + 1; 933 cx.index = current_count + 1;
924 934
925 cx.space_id = ACPI_CSTATE_SYSTEMIO; 935 cx.entry_method = ACPI_CSTATE_SYSTEMIO;
926 if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { 936 if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
927 if (acpi_processor_ffh_cstate_probe 937 if (acpi_processor_ffh_cstate_probe
928 (pr->id, &cx, reg) == 0) { 938 (pr->id, &cx, reg) == 0) {
929 cx.space_id = ACPI_CSTATE_FFH; 939 cx.entry_method = ACPI_CSTATE_FFH;
930 } else if (cx.type != ACPI_STATE_C1) { 940 } else if (cx.type == ACPI_STATE_C1) {
931 /* 941 /*
932 * C1 is a special case where FIXED_HARDWARE 942 * C1 is a special case where FIXED_HARDWARE
933 * can be handled in non-MWAIT way as well. 943 * can be handled in non-MWAIT way as well.
934 * In that case, save this _CST entry info. 944 * In that case, save this _CST entry info.
935 * That is, we retain space_id of SYSTEM_IO for
936 * halt based C1.
937 * Otherwise, ignore this info and continue. 945 * Otherwise, ignore this info and continue.
938 */ 946 */
947 cx.entry_method = ACPI_CSTATE_HALT;
948 } else {
939 continue; 949 continue;
940 } 950 }
941 } 951 }
@@ -1369,12 +1379,16 @@ static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr,
1369/** 1379/**
1370 * acpi_idle_do_entry - a helper function that does C2 and C3 type entry 1380 * acpi_idle_do_entry - a helper function that does C2 and C3 type entry
1371 * @cx: cstate data 1381 * @cx: cstate data
1382 *
1383 * Caller disables interrupt before call and enables interrupt after return.
1372 */ 1384 */
1373static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) 1385static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
1374{ 1386{
1375 if (cx->space_id == ACPI_CSTATE_FFH) { 1387 if (cx->entry_method == ACPI_CSTATE_FFH) {
1376 /* Call into architectural FFH based C-state */ 1388 /* Call into architectural FFH based C-state */
1377 acpi_processor_ffh_cstate_enter(cx); 1389 acpi_processor_ffh_cstate_enter(cx);
1390 } else if (cx->entry_method == ACPI_CSTATE_HALT) {
1391 acpi_safe_halt();
1378 } else { 1392 } else {
1379 int unused; 1393 int unused;
1380 /* IO port based C-state */ 1394 /* IO port based C-state */
@@ -1396,21 +1410,27 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
1396static int acpi_idle_enter_c1(struct cpuidle_device *dev, 1410static int acpi_idle_enter_c1(struct cpuidle_device *dev,
1397 struct cpuidle_state *state) 1411 struct cpuidle_state *state)
1398{ 1412{
1413 u32 t1, t2;
1399 struct acpi_processor *pr; 1414 struct acpi_processor *pr;
1400 struct acpi_processor_cx *cx = cpuidle_get_statedata(state); 1415 struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
1416
1401 pr = processors[smp_processor_id()]; 1417 pr = processors[smp_processor_id()];
1402 1418
1403 if (unlikely(!pr)) 1419 if (unlikely(!pr))
1404 return 0; 1420 return 0;
1405 1421
1422 local_irq_disable();
1406 if (pr->flags.bm_check) 1423 if (pr->flags.bm_check)
1407 acpi_idle_update_bm_rld(pr, cx); 1424 acpi_idle_update_bm_rld(pr, cx);
1408 1425
1409 acpi_safe_halt(); 1426 t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
1427 acpi_idle_do_entry(cx);
1428 t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
1410 1429
1430 local_irq_enable();
1411 cx->usage++; 1431 cx->usage++;
1412 1432
1413 return 0; 1433 return ticks_elapsed_in_us(t1, t2);
1414} 1434}
1415 1435
1416/** 1436/**
@@ -1517,7 +1537,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
1517 if (dev->safe_state) { 1537 if (dev->safe_state) {
1518 return dev->safe_state->enter(dev, dev->safe_state); 1538 return dev->safe_state->enter(dev, dev->safe_state);
1519 } else { 1539 } else {
1540 local_irq_disable();
1520 acpi_safe_halt(); 1541 acpi_safe_halt();
1542 local_irq_enable();
1521 return 0; 1543 return 0;
1522 } 1544 }
1523 } 1545 }
@@ -1609,7 +1631,7 @@ struct cpuidle_driver acpi_idle_driver = {
1609 */ 1631 */
1610static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) 1632static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
1611{ 1633{
1612 int i, count = 0; 1634 int i, count = CPUIDLE_DRIVER_STATE_START;
1613 struct acpi_processor_cx *cx; 1635 struct acpi_processor_cx *cx;
1614 struct cpuidle_state *state; 1636 struct cpuidle_state *state;
1615 struct cpuidle_device *dev = &pr->power.dev; 1637 struct cpuidle_device *dev = &pr->power.dev;
@@ -1638,13 +1660,14 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
1638 1660
1639 snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); 1661 snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
1640 state->exit_latency = cx->latency; 1662 state->exit_latency = cx->latency;
1641 state->target_residency = cx->latency * 6; 1663 state->target_residency = cx->latency * latency_factor;
1642 state->power_usage = cx->power; 1664 state->power_usage = cx->power;
1643 1665
1644 state->flags = 0; 1666 state->flags = 0;
1645 switch (cx->type) { 1667 switch (cx->type) {
1646 case ACPI_STATE_C1: 1668 case ACPI_STATE_C1:
1647 state->flags |= CPUIDLE_FLAG_SHALLOW; 1669 state->flags |= CPUIDLE_FLAG_SHALLOW;
1670 state->flags |= CPUIDLE_FLAG_TIME_VALID;
1648 state->enter = acpi_idle_enter_c1; 1671 state->enter = acpi_idle_enter_c1;
1649 dev->safe_state = state; 1672 dev->safe_state = state;
1650 break; 1673 break;
@@ -1667,6 +1690,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
1667 } 1690 }
1668 1691
1669 count++; 1692 count++;
1693 if (count == CPUIDLE_STATE_MAX)
1694 break;
1670 } 1695 }
1671 1696
1672 dev->state_count = count; 1697 dev->state_count = count;
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 463b0247cbc5..f32010bee4d5 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -60,6 +60,11 @@ static DEFINE_MUTEX(performance_mutex);
60 * policy is adjusted accordingly. 60 * policy is adjusted accordingly.
61 */ 61 */
62 62
63static unsigned int ignore_ppc = 0;
64module_param(ignore_ppc, uint, 0644);
65MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
66 "limited by BIOS, this should help");
67
63#define PPC_REGISTERED 1 68#define PPC_REGISTERED 1
64#define PPC_IN_USE 2 69#define PPC_IN_USE 2
65 70
@@ -72,6 +77,9 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
72 struct acpi_processor *pr; 77 struct acpi_processor *pr;
73 unsigned int ppc = 0; 78 unsigned int ppc = 0;
74 79
80 if (ignore_ppc)
81 return 0;
82
75 mutex_lock(&performance_mutex); 83 mutex_lock(&performance_mutex);
76 84
77 if (event != CPUFREQ_INCOMPATIBLE) 85 if (event != CPUFREQ_INCOMPATIBLE)
@@ -130,7 +138,13 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
130 138
131int acpi_processor_ppc_has_changed(struct acpi_processor *pr) 139int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
132{ 140{
133 int ret = acpi_processor_get_platform_limit(pr); 141 int ret;
142
143 if (ignore_ppc)
144 return 0;
145
146 ret = acpi_processor_get_platform_limit(pr);
147
134 if (ret < 0) 148 if (ret < 0)
135 return (ret); 149 return (ret);
136 else 150 else
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 06e6f3fb8825..9cb43f52f7b6 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -32,6 +32,7 @@
32#include <linux/cpufreq.h> 32#include <linux/cpufreq.h>
33#include <linux/proc_fs.h> 33#include <linux/proc_fs.h>
34#include <linux/seq_file.h> 34#include <linux/seq_file.h>
35#include <linux/sysdev.h>
35 36
36#include <asm/uaccess.h> 37#include <asm/uaccess.h>
37 38
@@ -93,6 +94,9 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr)
93 * _any_ cpufreq driver and not only the acpi-cpufreq driver. 94 * _any_ cpufreq driver and not only the acpi-cpufreq driver.
94 */ 95 */
95 96
97#define CPUFREQ_THERMAL_MIN_STEP 0
98#define CPUFREQ_THERMAL_MAX_STEP 3
99
96static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; 100static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];
97static unsigned int acpi_thermal_cpufreq_is_init = 0; 101static unsigned int acpi_thermal_cpufreq_is_init = 0;
98 102
@@ -109,8 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu)
109 if (!cpu_has_cpufreq(cpu)) 113 if (!cpu_has_cpufreq(cpu))
110 return -ENODEV; 114 return -ENODEV;
111 115
112 if (cpufreq_thermal_reduction_pctg[cpu] < 60) { 116 if (cpufreq_thermal_reduction_pctg[cpu] <
113 cpufreq_thermal_reduction_pctg[cpu] += 20; 117 CPUFREQ_THERMAL_MAX_STEP) {
118 cpufreq_thermal_reduction_pctg[cpu]++;
114 cpufreq_update_policy(cpu); 119 cpufreq_update_policy(cpu);
115 return 0; 120 return 0;
116 } 121 }
@@ -123,8 +128,9 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
123 if (!cpu_has_cpufreq(cpu)) 128 if (!cpu_has_cpufreq(cpu))
124 return -ENODEV; 129 return -ENODEV;
125 130
126 if (cpufreq_thermal_reduction_pctg[cpu] > 20) 131 if (cpufreq_thermal_reduction_pctg[cpu] >
127 cpufreq_thermal_reduction_pctg[cpu] -= 20; 132 (CPUFREQ_THERMAL_MIN_STEP + 1))
133 cpufreq_thermal_reduction_pctg[cpu]--;
128 else 134 else
129 cpufreq_thermal_reduction_pctg[cpu] = 0; 135 cpufreq_thermal_reduction_pctg[cpu] = 0;
130 cpufreq_update_policy(cpu); 136 cpufreq_update_policy(cpu);
@@ -143,7 +149,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
143 149
144 max_freq = 150 max_freq =
145 (policy->cpuinfo.max_freq * 151 (policy->cpuinfo.max_freq *
146 (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; 152 (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100;
147 153
148 cpufreq_verify_within_limits(policy, 0, max_freq); 154 cpufreq_verify_within_limits(policy, 0, max_freq);
149 155
@@ -155,6 +161,32 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
155 .notifier_call = acpi_thermal_cpufreq_notifier, 161 .notifier_call = acpi_thermal_cpufreq_notifier,
156}; 162};
157 163
164static int cpufreq_get_max_state(unsigned int cpu)
165{
166 if (!cpu_has_cpufreq(cpu))
167 return 0;
168
169 return CPUFREQ_THERMAL_MAX_STEP;
170}
171
172static int cpufreq_get_cur_state(unsigned int cpu)
173{
174 if (!cpu_has_cpufreq(cpu))
175 return 0;
176
177 return cpufreq_thermal_reduction_pctg[cpu];
178}
179
180static int cpufreq_set_cur_state(unsigned int cpu, int state)
181{
182 if (!cpu_has_cpufreq(cpu))
183 return 0;
184
185 cpufreq_thermal_reduction_pctg[cpu] = state;
186 cpufreq_update_policy(cpu);
187 return 0;
188}
189
158void acpi_thermal_cpufreq_init(void) 190void acpi_thermal_cpufreq_init(void)
159{ 191{
160 int i; 192 int i;
@@ -179,6 +211,20 @@ void acpi_thermal_cpufreq_exit(void)
179} 211}
180 212
181#else /* ! CONFIG_CPU_FREQ */ 213#else /* ! CONFIG_CPU_FREQ */
214static int cpufreq_get_max_state(unsigned int cpu)
215{
216 return 0;
217}
218
219static int cpufreq_get_cur_state(unsigned int cpu)
220{
221 return 0;
222}
223
224static int cpufreq_set_cur_state(unsigned int cpu, int state)
225{
226 return 0;
227}
182 228
183static int acpi_thermal_cpufreq_increase(unsigned int cpu) 229static int acpi_thermal_cpufreq_increase(unsigned int cpu)
184{ 230{
@@ -310,6 +356,84 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr)
310 return 0; 356 return 0;
311} 357}
312 358
359/* thermal coolign device callbacks */
360static int acpi_processor_max_state(struct acpi_processor *pr)
361{
362 int max_state = 0;
363
364 /*
365 * There exists four states according to
366 * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3
367 */
368 max_state += cpufreq_get_max_state(pr->id);
369 if (pr->flags.throttling)
370 max_state += (pr->throttling.state_count -1);
371
372 return max_state;
373}
374static int
375processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
376{
377 struct acpi_device *device = cdev->devdata;
378 struct acpi_processor *pr = acpi_driver_data(device);
379
380 if (!device || !pr)
381 return -EINVAL;
382
383 return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
384}
385
386static int
387processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
388{
389 struct acpi_device *device = cdev->devdata;
390 struct acpi_processor *pr = acpi_driver_data(device);
391 int cur_state;
392
393 if (!device || !pr)
394 return -EINVAL;
395
396 cur_state = cpufreq_get_cur_state(pr->id);
397 if (pr->flags.throttling)
398 cur_state += pr->throttling.state;
399
400 return sprintf(buf, "%d\n", cur_state);
401}
402
403static int
404processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
405{
406 struct acpi_device *device = cdev->devdata;
407 struct acpi_processor *pr = acpi_driver_data(device);
408 int result = 0;
409 int max_pstate;
410
411 if (!device || !pr)
412 return -EINVAL;
413
414 max_pstate = cpufreq_get_max_state(pr->id);
415
416 if (state > acpi_processor_max_state(pr))
417 return -EINVAL;
418
419 if (state <= max_pstate) {
420 if (pr->flags.throttling && pr->throttling.state)
421 result = acpi_processor_set_throttling(pr, 0);
422 cpufreq_set_cur_state(pr->id, state);
423 } else {
424 cpufreq_set_cur_state(pr->id, max_pstate);
425 result = acpi_processor_set_throttling(pr,
426 state - max_pstate);
427 }
428 return result;
429}
430
431struct thermal_cooling_device_ops processor_cooling_ops = {
432 .get_max_state = processor_get_max_state,
433 .get_cur_state = processor_get_cur_state,
434 .set_cur_state = processor_set_cur_state,
435};
436
313/* /proc interface */ 437/* /proc interface */
314 438
315static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) 439static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 1685b40abda7..1b8e592a8241 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -45,9 +45,229 @@
45#define _COMPONENT ACPI_PROCESSOR_COMPONENT 45#define _COMPONENT ACPI_PROCESSOR_COMPONENT
46ACPI_MODULE_NAME("processor_throttling"); 46ACPI_MODULE_NAME("processor_throttling");
47 47
48struct throttling_tstate {
49 unsigned int cpu; /* cpu nr */
50 int target_state; /* target T-state */
51};
52
53#define THROTTLING_PRECHANGE (1)
54#define THROTTLING_POSTCHANGE (2)
55
48static int acpi_processor_get_throttling(struct acpi_processor *pr); 56static int acpi_processor_get_throttling(struct acpi_processor *pr);
49int acpi_processor_set_throttling(struct acpi_processor *pr, int state); 57int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
50 58
59static int acpi_processor_update_tsd_coord(void)
60{
61 int count, count_target;
62 int retval = 0;
63 unsigned int i, j;
64 cpumask_t covered_cpus;
65 struct acpi_processor *pr, *match_pr;
66 struct acpi_tsd_package *pdomain, *match_pdomain;
67 struct acpi_processor_throttling *pthrottling, *match_pthrottling;
68
69 /*
70 * Now that we have _TSD data from all CPUs, lets setup T-state
71 * coordination between all CPUs.
72 */
73 for_each_possible_cpu(i) {
74 pr = processors[i];
75 if (!pr)
76 continue;
77
78 /* Basic validity check for domain info */
79 pthrottling = &(pr->throttling);
80
81 /*
82 * If tsd package for one cpu is invalid, the coordination
83 * among all CPUs is thought as invalid.
84 * Maybe it is ugly.
85 */
86 if (!pthrottling->tsd_valid_flag) {
87 retval = -EINVAL;
88 break;
89 }
90 }
91 if (retval)
92 goto err_ret;
93
94 cpus_clear(covered_cpus);
95 for_each_possible_cpu(i) {
96 pr = processors[i];
97 if (!pr)
98 continue;
99
100 if (cpu_isset(i, covered_cpus))
101 continue;
102 pthrottling = &pr->throttling;
103
104 pdomain = &(pthrottling->domain_info);
105 cpu_set(i, pthrottling->shared_cpu_map);
106 cpu_set(i, covered_cpus);
107 /*
108 * If the number of processor in the TSD domain is 1, it is
109 * unnecessary to parse the coordination for this CPU.
110 */
111 if (pdomain->num_processors <= 1)
112 continue;
113
114 /* Validate the Domain info */
115 count_target = pdomain->num_processors;
116 count = 1;
117
118 for_each_possible_cpu(j) {
119 if (i == j)
120 continue;
121
122 match_pr = processors[j];
123 if (!match_pr)
124 continue;
125
126 match_pthrottling = &(match_pr->throttling);
127 match_pdomain = &(match_pthrottling->domain_info);
128 if (match_pdomain->domain != pdomain->domain)
129 continue;
130
131 /* Here i and j are in the same domain.
132 * If two TSD packages have the same domain, they
133 * should have the same num_porcessors and
134 * coordination type. Otherwise it will be regarded
135 * as illegal.
136 */
137 if (match_pdomain->num_processors != count_target) {
138 retval = -EINVAL;
139 goto err_ret;
140 }
141
142 if (pdomain->coord_type != match_pdomain->coord_type) {
143 retval = -EINVAL;
144 goto err_ret;
145 }
146
147 cpu_set(j, covered_cpus);
148 cpu_set(j, pthrottling->shared_cpu_map);
149 count++;
150 }
151 for_each_possible_cpu(j) {
152 if (i == j)
153 continue;
154
155 match_pr = processors[j];
156 if (!match_pr)
157 continue;
158
159 match_pthrottling = &(match_pr->throttling);
160 match_pdomain = &(match_pthrottling->domain_info);
161 if (match_pdomain->domain != pdomain->domain)
162 continue;
163
164 /*
165 * If some CPUS have the same domain, they
166 * will have the same shared_cpu_map.
167 */
168 match_pthrottling->shared_cpu_map =
169 pthrottling->shared_cpu_map;
170 }
171 }
172
173err_ret:
174 for_each_possible_cpu(i) {
175 pr = processors[i];
176 if (!pr)
177 continue;
178
179 /*
180 * Assume no coordination on any error parsing domain info.
181 * The coordination type will be forced as SW_ALL.
182 */
183 if (retval) {
184 pthrottling = &(pr->throttling);
185 cpus_clear(pthrottling->shared_cpu_map);
186 cpu_set(i, pthrottling->shared_cpu_map);
187 pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
188 }
189 }
190
191 return retval;
192}
193
194/*
195 * Update the T-state coordination after the _TSD
196 * data for all cpus is obtained.
197 */
198void acpi_processor_throttling_init(void)
199{
200 if (acpi_processor_update_tsd_coord())
201 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
202 "Assume no T-state coordination\n"));
203
204 return;
205}
206
207static int acpi_processor_throttling_notifier(unsigned long event, void *data)
208{
209 struct throttling_tstate *p_tstate = data;
210 struct acpi_processor *pr;
211 unsigned int cpu ;
212 int target_state;
213 struct acpi_processor_limit *p_limit;
214 struct acpi_processor_throttling *p_throttling;
215
216 cpu = p_tstate->cpu;
217 pr = processors[cpu];
218 if (!pr) {
219 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid pr pointer\n"));
220 return 0;
221 }
222 if (!pr->flags.throttling) {
223 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling control is "
224 "unsupported on CPU %d\n", cpu));
225 return 0;
226 }
227 target_state = p_tstate->target_state;
228 p_throttling = &(pr->throttling);
229 switch (event) {
230 case THROTTLING_PRECHANGE:
231 /*
232 * Prechange event is used to choose one proper t-state,
233 * which meets the limits of thermal, user and _TPC.
234 */
235 p_limit = &pr->limit;
236 if (p_limit->thermal.tx > target_state)
237 target_state = p_limit->thermal.tx;
238 if (p_limit->user.tx > target_state)
239 target_state = p_limit->user.tx;
240 if (pr->throttling_platform_limit > target_state)
241 target_state = pr->throttling_platform_limit;
242 if (target_state >= p_throttling->state_count) {
243 printk(KERN_WARNING
244 "Exceed the limit of T-state \n");
245 target_state = p_throttling->state_count - 1;
246 }
247 p_tstate->target_state = target_state;
248 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PreChange Event:"
249 "target T-state of CPU %d is T%d\n",
250 cpu, target_state));
251 break;
252 case THROTTLING_POSTCHANGE:
253 /*
254 * Postchange event is only used to update the
255 * T-state flag of acpi_processor_throttling.
256 */
257 p_throttling->state = target_state;
258 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PostChange Event:"
259 "CPU %d is switched to T%d\n",
260 cpu, target_state));
261 break;
262 default:
263 printk(KERN_WARNING
264 "Unsupported Throttling notifier event\n");
265 break;
266 }
267
268 return 0;
269}
270
51/* 271/*
52 * _TPC - Throttling Present Capabilities 272 * _TPC - Throttling Present Capabilities
53 */ 273 */
@@ -293,6 +513,10 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
293 struct acpi_buffer state = { 0, NULL }; 513 struct acpi_buffer state = { 0, NULL };
294 union acpi_object *tsd = NULL; 514 union acpi_object *tsd = NULL;
295 struct acpi_tsd_package *pdomain; 515 struct acpi_tsd_package *pdomain;
516 struct acpi_processor_throttling *pthrottling;
517
518 pthrottling = &pr->throttling;
519 pthrottling->tsd_valid_flag = 0;
296 520
297 status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer); 521 status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
298 if (ACPI_FAILURE(status)) { 522 if (ACPI_FAILURE(status)) {
@@ -340,6 +564,22 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
340 goto end; 564 goto end;
341 } 565 }
342 566
567 pthrottling = &pr->throttling;
568 pthrottling->tsd_valid_flag = 1;
569 pthrottling->shared_type = pdomain->coord_type;
570 cpu_set(pr->id, pthrottling->shared_cpu_map);
571 /*
572 * If the coordination type is not defined in ACPI spec,
573 * the tsd_valid_flag will be clear and coordination type
574 * will be forecd as DOMAIN_COORD_TYPE_SW_ALL.
575 */
576 if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
577 pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
578 pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
579 pthrottling->tsd_valid_flag = 0;
580 pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
581 }
582
343 end: 583 end:
344 kfree(buffer.pointer); 584 kfree(buffer.pointer);
345 return result; 585 return result;
@@ -589,6 +829,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
589 cpumask_t saved_mask; 829 cpumask_t saved_mask;
590 int ret; 830 int ret;
591 831
832 if (!pr)
833 return -EINVAL;
834
835 if (!pr->flags.throttling)
836 return -ENODEV;
592 /* 837 /*
593 * Migrate task to the cpu pointed by pr. 838 * Migrate task to the cpu pointed by pr.
594 */ 839 */
@@ -742,13 +987,92 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
742int acpi_processor_set_throttling(struct acpi_processor *pr, int state) 987int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
743{ 988{
744 cpumask_t saved_mask; 989 cpumask_t saved_mask;
745 int ret; 990 int ret = 0;
991 unsigned int i;
992 struct acpi_processor *match_pr;
993 struct acpi_processor_throttling *p_throttling;
994 struct throttling_tstate t_state;
995 cpumask_t online_throttling_cpus;
996
997 if (!pr)
998 return -EINVAL;
999
1000 if (!pr->flags.throttling)
1001 return -ENODEV;
1002
1003 if ((state < 0) || (state > (pr->throttling.state_count - 1)))
1004 return -EINVAL;
1005
1006 saved_mask = current->cpus_allowed;
1007 t_state.target_state = state;
1008 p_throttling = &(pr->throttling);
1009 cpus_and(online_throttling_cpus, cpu_online_map,
1010 p_throttling->shared_cpu_map);
746 /* 1011 /*
747 * Migrate task to the cpu pointed by pr. 1012 * The throttling notifier will be called for every
1013 * affected cpu in order to get one proper T-state.
1014 * The notifier event is THROTTLING_PRECHANGE.
748 */ 1015 */
749 saved_mask = current->cpus_allowed; 1016 for_each_cpu_mask(i, online_throttling_cpus) {
750 set_cpus_allowed(current, cpumask_of_cpu(pr->id)); 1017 t_state.cpu = i;
751 ret = pr->throttling.acpi_processor_set_throttling(pr, state); 1018 acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
1019 &t_state);
1020 }
1021 /*
1022 * The function of acpi_processor_set_throttling will be called
1023 * to switch T-state. If the coordination type is SW_ALL or HW_ALL,
1024 * it is necessary to call it for every affected cpu. Otherwise
1025 * it can be called only for the cpu pointed by pr.
1026 */
1027 if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
1028 set_cpus_allowed(current, cpumask_of_cpu(pr->id));
1029 ret = p_throttling->acpi_processor_set_throttling(pr,
1030 t_state.target_state);
1031 } else {
1032 /*
1033 * When the T-state coordination is SW_ALL or HW_ALL,
1034 * it is necessary to set T-state for every affected
1035 * cpus.
1036 */
1037 for_each_cpu_mask(i, online_throttling_cpus) {
1038 match_pr = processors[i];
1039 /*
1040 * If the pointer is invalid, we will report the
1041 * error message and continue.
1042 */
1043 if (!match_pr) {
1044 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1045 "Invalid Pointer for CPU %d\n", i));
1046 continue;
1047 }
1048 /*
1049 * If the throttling control is unsupported on CPU i,
1050 * we will report the error message and continue.
1051 */
1052 if (!match_pr->flags.throttling) {
1053 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1054 "Throttling Controll is unsupported "
1055 "on CPU %d\n", i));
1056 continue;
1057 }
1058 t_state.cpu = i;
1059 set_cpus_allowed(current, cpumask_of_cpu(i));
1060 ret = match_pr->throttling.
1061 acpi_processor_set_throttling(
1062 match_pr, t_state.target_state);
1063 }
1064 }
1065 /*
1066 * After the set_throttling is called, the
1067 * throttling notifier is called for every
1068 * affected cpu to update the T-states.
1069 * The notifier event is THROTTLING_POSTCHANGE
1070 */
1071 for_each_cpu_mask(i, online_throttling_cpus) {
1072 t_state.cpu = i;
1073 acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
1074 &t_state);
1075 }
752 /* restore the previous state */ 1076 /* restore the previous state */
753 set_cpus_allowed(current, saved_mask); 1077 set_cpus_allowed(current, saved_mask);
754 return ret; 1078 return ret;
@@ -757,6 +1081,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
757int acpi_processor_get_throttling_info(struct acpi_processor *pr) 1081int acpi_processor_get_throttling_info(struct acpi_processor *pr)
758{ 1082{
759 int result = 0; 1083 int result = 0;
1084 struct acpi_processor_throttling *pthrottling;
760 1085
761 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1086 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
762 "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n", 1087 "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
@@ -788,7 +1113,16 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
788 &acpi_processor_set_throttling_ptc; 1113 &acpi_processor_set_throttling_ptc;
789 } 1114 }
790 1115
791 acpi_processor_get_tsd(pr); 1116 /*
1117 * If TSD package for one CPU can't be parsed successfully, it means
1118 * that this CPU will have no coordination with other CPUs.
1119 */
1120 if (acpi_processor_get_tsd(pr)) {
1121 pthrottling = &pr->throttling;
1122 pthrottling->tsd_valid_flag = 0;
1123 cpu_set(pr->id, pthrottling->shared_cpu_map);
1124 pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
1125 }
792 1126
793 /* 1127 /*
794 * PIIX4 Errata: We don't support throttling on the original PIIX4. 1128 * PIIX4 Errata: We don't support throttling on the original PIIX4.
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index f136c7d3b3c2..1194105cc3ca 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -888,7 +888,7 @@ static void acpi_charger_remove(struct acpi_sbs *sbs)
888#endif 888#endif
889} 889}
890 890
891void acpi_sbs_callback(void *context) 891static void acpi_sbs_callback(void *context)
892{ 892{
893 int id; 893 int id;
894 struct acpi_sbs *sbs = context; 894 struct acpi_sbs *sbs = context;
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index fd40b6a1d639..ae9a90438e2f 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -111,8 +111,8 @@ static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
111 return -ETIME; 111 return -ETIME;
112} 112}
113 113
114int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, u8 address, 114static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
115 u8 command, u8 *data, u8 length) 115 u8 address, u8 command, u8 *data, u8 length)
116{ 116{
117 int ret = -EFAULT, i; 117 int ret = -EFAULT, i;
118 u8 temp, sz = 0; 118 u8 temp, sz = 0;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index d9d531cce27f..3fac011f9cf9 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -59,7 +59,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
59 count = snprintf(&modalias[len], size, "%s:", 59 count = snprintf(&modalias[len], size, "%s:",
60 cid_list->id[i].value); 60 cid_list->id[i].value);
61 if (count < 0 || count >= size) { 61 if (count < 0 || count >= size) {
62 printk(KERN_ERR "acpi: %s cid[%i] exceeds event buffer size", 62 printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size",
63 acpi_dev->pnp.device_name, i); 63 acpi_dev->pnp.device_name, i);
64 break; 64 break;
65 } 65 }
@@ -453,7 +453,7 @@ static int acpi_device_register(struct acpi_device *device,
453 device->dev.release = &acpi_device_release; 453 device->dev.release = &acpi_device_release;
454 result = device_add(&device->dev); 454 result = device_add(&device->dev);
455 if(result) { 455 if(result) {
456 printk("Error adding device %s", device->dev.bus_id); 456 printk(KERN_ERR PREFIX "Error adding device %s", device->dev.bus_id);
457 goto end; 457 goto end;
458 } 458 }
459 459
@@ -941,6 +941,15 @@ static int acpi_bay_match(struct acpi_device *device){
941 return -ENODEV; 941 return -ENODEV;
942} 942}
943 943
944/*
945 * acpi_dock_match - see if a device has a _DCK method
946 */
947static int acpi_dock_match(struct acpi_device *device)
948{
949 acpi_handle tmp;
950 return acpi_get_handle(device->handle, "_DCK", &tmp);
951}
952
944static void acpi_device_set_id(struct acpi_device *device, 953static void acpi_device_set_id(struct acpi_device *device,
945 struct acpi_device *parent, acpi_handle handle, 954 struct acpi_device *parent, acpi_handle handle,
946 int type) 955 int type)
@@ -950,13 +959,14 @@ static void acpi_device_set_id(struct acpi_device *device,
950 char *hid = NULL; 959 char *hid = NULL;
951 char *uid = NULL; 960 char *uid = NULL;
952 struct acpi_compatible_id_list *cid_list = NULL; 961 struct acpi_compatible_id_list *cid_list = NULL;
962 const char *cid_add = NULL;
953 acpi_status status; 963 acpi_status status;
954 964
955 switch (type) { 965 switch (type) {
956 case ACPI_BUS_TYPE_DEVICE: 966 case ACPI_BUS_TYPE_DEVICE:
957 status = acpi_get_object_info(handle, &buffer); 967 status = acpi_get_object_info(handle, &buffer);
958 if (ACPI_FAILURE(status)) { 968 if (ACPI_FAILURE(status)) {
959 printk("%s: Error reading device info\n", __FUNCTION__); 969 printk(KERN_ERR PREFIX "%s: Error reading device info\n", __FUNCTION__);
960 return; 970 return;
961 } 971 }
962 972
@@ -972,15 +982,18 @@ static void acpi_device_set_id(struct acpi_device *device,
972 device->flags.bus_address = 1; 982 device->flags.bus_address = 1;
973 } 983 }
974 984
975 if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){ 985 /* If we have a video/bay/dock device, add our selfdefined
976 status = acpi_video_bus_match(device); 986 HID to the CID list. Like that the video/bay/dock drivers
977 if(ACPI_SUCCESS(status)) 987 will get autoloaded and the device might still match
978 hid = ACPI_VIDEO_HID; 988 against another driver.
989 */
990 if (ACPI_SUCCESS(acpi_video_bus_match(device)))
991 cid_add = ACPI_VIDEO_HID;
992 else if (ACPI_SUCCESS(acpi_bay_match(device)))
993 cid_add = ACPI_BAY_HID;
994 else if (ACPI_SUCCESS(acpi_dock_match(device)))
995 cid_add = ACPI_DOCK_HID;
979 996
980 status = acpi_bay_match(device);
981 if (ACPI_SUCCESS(status))
982 hid = ACPI_BAY_HID;
983 }
984 break; 997 break;
985 case ACPI_BUS_TYPE_POWER: 998 case ACPI_BUS_TYPE_POWER:
986 hid = ACPI_POWER_HID; 999 hid = ACPI_POWER_HID;
@@ -1021,12 +1034,45 @@ static void acpi_device_set_id(struct acpi_device *device,
1021 strcpy(device->pnp.unique_id, uid); 1034 strcpy(device->pnp.unique_id, uid);
1022 device->flags.unique_id = 1; 1035 device->flags.unique_id = 1;
1023 } 1036 }
1024 if (cid_list) { 1037 if (cid_list || cid_add) {
1025 device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL); 1038 struct acpi_compatible_id_list *list;
1026 if (device->pnp.cid_list) 1039 int size = 0;
1027 memcpy(device->pnp.cid_list, cid_list, cid_list->size); 1040 int count = 0;
1028 else 1041
1029 printk(KERN_ERR "Memory allocation error\n"); 1042 if (cid_list) {
1043 size = cid_list->size;
1044 } else if (cid_add) {
1045 size = sizeof(struct acpi_compatible_id_list);
1046 cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
1047 if (!cid_list) {
1048 printk(KERN_ERR "Memory allocation error\n");
1049 kfree(buffer.pointer);
1050 return;
1051 } else {
1052 cid_list->count = 0;
1053 cid_list->size = size;
1054 }
1055 }
1056 if (cid_add)
1057 size += sizeof(struct acpi_compatible_id);
1058 list = kmalloc(size, GFP_KERNEL);
1059
1060 if (list) {
1061 if (cid_list) {
1062 memcpy(list, cid_list, cid_list->size);
1063 count = cid_list->count;
1064 }
1065 if (cid_add) {
1066 strncpy(list->id[count].value, cid_add,
1067 ACPI_MAX_CID_LENGTH);
1068 count++;
1069 device->flags.compatible_ids = 1;
1070 }
1071 list->size = size;
1072 list->count = count;
1073 device->pnp.cid_list = list;
1074 } else
1075 printk(KERN_ERR PREFIX "Memory allocation error\n");
1030 } 1076 }
1031 1077
1032 kfree(buffer.pointer); 1078 kfree(buffer.pointer);
@@ -1050,7 +1096,7 @@ static int acpi_device_set_context(struct acpi_device *device, int type)
1050 acpi_bus_data_handler, device); 1096 acpi_bus_data_handler, device);
1051 1097
1052 if (ACPI_FAILURE(status)) { 1098 if (ACPI_FAILURE(status)) {
1053 printk("Error attaching device data\n"); 1099 printk(KERN_ERR PREFIX "Error attaching device data\n");
1054 result = -ENODEV; 1100 result = -ENODEV;
1055 } 1101 }
1056 } 1102 }
@@ -1081,6 +1127,20 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
1081} 1127}
1082 1128
1083static int 1129static int
1130acpi_is_child_device(struct acpi_device *device,
1131 int (*matcher)(struct acpi_device *))
1132{
1133 int result = -ENODEV;
1134
1135 do {
1136 if (ACPI_SUCCESS(matcher(device)))
1137 return AE_OK;
1138 } while ((device = device->parent));
1139
1140 return result;
1141}
1142
1143static int
1084acpi_add_single_object(struct acpi_device **child, 1144acpi_add_single_object(struct acpi_device **child,
1085 struct acpi_device *parent, acpi_handle handle, int type, 1145 struct acpi_device *parent, acpi_handle handle, int type,
1086 struct acpi_bus_ops *ops) 1146 struct acpi_bus_ops *ops)
@@ -1131,10 +1191,20 @@ acpi_add_single_object(struct acpi_device **child,
1131 case ACPI_BUS_TYPE_PROCESSOR: 1191 case ACPI_BUS_TYPE_PROCESSOR:
1132 case ACPI_BUS_TYPE_DEVICE: 1192 case ACPI_BUS_TYPE_DEVICE:
1133 result = acpi_bus_get_status(device); 1193 result = acpi_bus_get_status(device);
1134 if (ACPI_FAILURE(result) || !device->status.present) { 1194 if (ACPI_FAILURE(result)) {
1135 result = -ENOENT; 1195 result = -ENODEV;
1136 goto end; 1196 goto end;
1137 } 1197 }
1198 if (!device->status.present) {
1199 /* Bay and dock should be handled even if absent */
1200 if (!ACPI_SUCCESS(
1201 acpi_is_child_device(device, acpi_bay_match)) &&
1202 !ACPI_SUCCESS(
1203 acpi_is_child_device(device, acpi_dock_match))) {
1204 result = -ENODEV;
1205 goto end;
1206 }
1207 }
1138 break; 1208 break;
1139 default: 1209 default:
1140 STRUCT_TO_INT(device->status) = 1210 STRUCT_TO_INT(device->status) =
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 485de1347075..293a1cbb47c0 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -170,7 +170,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
170 /* Reprogram control registers and execute _BFS */ 170 /* Reprogram control registers and execute _BFS */
171 acpi_leave_sleep_state_prep(acpi_state); 171 acpi_leave_sleep_state_prep(acpi_state);
172 172
173 /* ACPI 3.0 specs (P62) says that it's the responsabilty 173 /* ACPI 3.0 specs (P62) says that it's the responsibility
174 * of the OSPM to clear the status bit [ implying that the 174 * of the OSPM to clear the status bit [ implying that the
175 * POWER_BUTTON event should not reach userspace ] 175 * POWER_BUTTON event should not reach userspace ]
176 */ 176 */
@@ -472,11 +472,20 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
472 if (acpi_target_sleep_state == ACPI_STATE_S0 || 472 if (acpi_target_sleep_state == ACPI_STATE_S0 ||
473 (wake && adev->wakeup.state.enabled && 473 (wake && adev->wakeup.state.enabled &&
474 adev->wakeup.sleep_state <= acpi_target_sleep_state)) { 474 adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
475 acpi_status status;
476
475 acpi_method[3] = 'W'; 477 acpi_method[3] = 'W';
476 acpi_evaluate_integer(handle, acpi_method, NULL, &d_max); 478 status = acpi_evaluate_integer(handle, acpi_method, NULL,
477 /* Sanity check */ 479 &d_max);
478 if (d_max < d_min) 480 if (ACPI_FAILURE(status)) {
481 d_max = d_min;
482 } else if (d_max < d_min) {
483 /* Warn the user of the broken DSDT */
484 printk(KERN_WARNING "ACPI: Wrong value from %s\n",
485 acpi_method);
486 /* Sanitize it */
479 d_min = d_max; 487 d_min = d_max;
488 }
480 } 489 }
481 490
482 if (d_min_p) 491 if (d_min_p)
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 1538355c266b..f8df5217d477 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -178,6 +178,9 @@ static int get_date_field(char **p, u32 * value)
178 * Try to find delimeter, only to insert null. The end of the 178 * Try to find delimeter, only to insert null. The end of the
179 * string won't have one, but is still valid. 179 * string won't have one, but is still valid.
180 */ 180 */
181 if (*p == NULL)
182 return result;
183
181 next = strpbrk(*p, "- :"); 184 next = strpbrk(*p, "- :");
182 if (next) 185 if (next)
183 *next++ = '\0'; 186 *next++ = '\0';
@@ -190,6 +193,8 @@ static int get_date_field(char **p, u32 * value)
190 193
191 if (next) 194 if (next)
192 *p = next; 195 *p = next;
196 else
197 *p = NULL;
193 198
194 return result; 199 return result;
195} 200}
@@ -251,27 +256,6 @@ acpi_system_write_alarm(struct file *file,
251 if ((result = get_date_field(&p, &sec))) 256 if ((result = get_date_field(&p, &sec)))
252 goto end; 257 goto end;
253 258
254 if (sec > 59) {
255 min += 1;
256 sec -= 60;
257 }
258 if (min > 59) {
259 hr += 1;
260 min -= 60;
261 }
262 if (hr > 23) {
263 day += 1;
264 hr -= 24;
265 }
266 if (day > 31) {
267 mo += 1;
268 day -= 31;
269 }
270 if (mo > 12) {
271 yr += 1;
272 mo -= 12;
273 }
274
275 spin_lock_irq(&rtc_lock); 259 spin_lock_irq(&rtc_lock);
276 260
277 rtc_control = CMOS_READ(RTC_CONTROL); 261 rtc_control = CMOS_READ(RTC_CONTROL);
@@ -288,24 +272,24 @@ acpi_system_write_alarm(struct file *file,
288 spin_unlock_irq(&rtc_lock); 272 spin_unlock_irq(&rtc_lock);
289 273
290 if (sec > 59) { 274 if (sec > 59) {
291 min++; 275 min += sec/60;
292 sec -= 60; 276 sec = sec%60;
293 } 277 }
294 if (min > 59) { 278 if (min > 59) {
295 hr++; 279 hr += min/60;
296 min -= 60; 280 min = min%60;
297 } 281 }
298 if (hr > 23) { 282 if (hr > 23) {
299 day++; 283 day += hr/24;
300 hr -= 24; 284 hr = hr%24;
301 } 285 }
302 if (day > 31) { 286 if (day > 31) {
303 mo++; 287 mo += day/32;
304 day -= 31; 288 day = day%32;
305 } 289 }
306 if (mo > 12) { 290 if (mo > 12) {
307 yr++; 291 yr += mo/13;
308 mo -= 12; 292 mo = mo%13;
309 } 293 }
310 294
311 spin_lock_irq(&rtc_lock); 295 spin_lock_irq(&rtc_lock);
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 5ffe0ea18967..55cf4c05bb74 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -40,6 +40,8 @@ ACPI_MODULE_NAME("system");
40#define ACPI_SYSTEM_CLASS "system" 40#define ACPI_SYSTEM_CLASS "system"
41#define ACPI_SYSTEM_DEVICE_NAME "System" 41#define ACPI_SYSTEM_DEVICE_NAME "System"
42 42
43u32 acpi_irq_handled;
44
43/* 45/*
44 * Make ACPICA version work as module param 46 * Make ACPICA version work as module param
45 */ 47 */
@@ -166,6 +168,212 @@ static int acpi_system_sysfs_init(void)
166 return 0; 168 return 0;
167} 169}
168 170
171/*
172 * Detailed ACPI IRQ counters in /sys/firmware/acpi/interrupts/
173 * See Documentation/ABI/testing/sysfs-firmware-acpi
174 */
175
176#define COUNT_GPE 0
177#define COUNT_SCI 1 /* acpi_irq_handled */
178#define COUNT_ERROR 2 /* other */
179#define NUM_COUNTERS_EXTRA 3
180
181static u32 *all_counters;
182static u32 num_gpes;
183static u32 num_counters;
184static struct attribute **all_attrs;
185static u32 acpi_gpe_count;
186
187static struct attribute_group interrupt_stats_attr_group = {
188 .name = "interrupts",
189};
190static struct kobj_attribute *counter_attrs;
191
192static int count_num_gpes(void)
193{
194 int count = 0;
195 struct acpi_gpe_xrupt_info *gpe_xrupt_info;
196 struct acpi_gpe_block_info *gpe_block;
197 acpi_cpu_flags flags;
198
199 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
200
201 gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
202 while (gpe_xrupt_info) {
203 gpe_block = gpe_xrupt_info->gpe_block_list_head;
204 while (gpe_block) {
205 count += gpe_block->register_count *
206 ACPI_GPE_REGISTER_WIDTH;
207 gpe_block = gpe_block->next;
208 }
209 gpe_xrupt_info = gpe_xrupt_info->next;
210 }
211 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
212
213 return count;
214}
215
216static void delete_gpe_attr_array(void)
217{
218 u32 *tmp = all_counters;
219
220 all_counters = NULL;
221 kfree(tmp);
222
223 if (counter_attrs) {
224 int i;
225
226 for (i = 0; i < num_gpes; i++)
227 kfree(counter_attrs[i].attr.name);
228
229 kfree(counter_attrs);
230 }
231 kfree(all_attrs);
232
233 return;
234}
235
236void acpi_os_gpe_count(u32 gpe_number)
237{
238 acpi_gpe_count++;
239
240 if (!all_counters)
241 return;
242
243 if (gpe_number < num_gpes)
244 all_counters[gpe_number]++;
245 else
246 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
247
248 return;
249}
250
251void acpi_os_fixed_event_count(u32 event_number)
252{
253 if (!all_counters)
254 return;
255
256 if (event_number < ACPI_NUM_FIXED_EVENTS)
257 all_counters[num_gpes + event_number]++;
258 else
259 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
260
261 return;
262}
263
264static ssize_t counter_show(struct kobject *kobj,
265 struct kobj_attribute *attr, char *buf)
266{
267 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI] =
268 acpi_irq_handled;
269 all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] =
270 acpi_gpe_count;
271
272 return sprintf(buf, "%d\n", all_counters[attr - counter_attrs]);
273}
274
275/*
276 * counter_set() sets the specified counter.
277 * setting the total "sci" file to any value clears all counters.
278 */
279static ssize_t counter_set(struct kobject *kobj,
280 struct kobj_attribute *attr, const char *buf, size_t size)
281{
282 int index = attr - counter_attrs;
283
284 if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
285 int i;
286 for (i = 0; i < num_counters; ++i)
287 all_counters[i] = 0;
288 acpi_gpe_count = 0;
289 acpi_irq_handled = 0;
290
291 } else
292 all_counters[index] = strtoul(buf, NULL, 0);
293
294 return size;
295}
296
297void acpi_irq_stats_init(void)
298{
299 int i;
300
301 if (all_counters)
302 return;
303
304 num_gpes = count_num_gpes();
305 num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA;
306
307 all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1),
308 GFP_KERNEL);
309 if (all_attrs == NULL)
310 return;
311
312 all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL);
313 if (all_counters == NULL)
314 goto fail;
315
316 counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters),
317 GFP_KERNEL);
318 if (counter_attrs == NULL)
319 goto fail;
320
321 for (i = 0; i < num_counters; ++i) {
322 char buffer[10];
323 char *name;
324
325 if (i < num_gpes)
326 sprintf(buffer, "gpe%02X", i);
327 else if (i == num_gpes + ACPI_EVENT_PMTIMER)
328 sprintf(buffer, "ff_pmtimer");
329 else if (i == num_gpes + ACPI_EVENT_GLOBAL)
330 sprintf(buffer, "ff_gbl_lock");
331 else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON)
332 sprintf(buffer, "ff_pwr_btn");
333 else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON)
334 sprintf(buffer, "ff_slp_btn");
335 else if (i == num_gpes + ACPI_EVENT_RTC)
336 sprintf(buffer, "ff_rt_clk");
337 else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE)
338 sprintf(buffer, "gpe_all");
339 else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI)
340 sprintf(buffer, "sci");
341 else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR)
342 sprintf(buffer, "error");
343 else
344 sprintf(buffer, "bug%02X", i);
345
346 name = kzalloc(strlen(buffer) + 1, GFP_KERNEL);
347 if (name == NULL)
348 goto fail;
349 strncpy(name, buffer, strlen(buffer) + 1);
350
351 counter_attrs[i].attr.name = name;
352 counter_attrs[i].attr.mode = 0644;
353 counter_attrs[i].show = counter_show;
354 counter_attrs[i].store = counter_set;
355
356 all_attrs[i] = &counter_attrs[i].attr;
357 }
358
359 interrupt_stats_attr_group.attrs = all_attrs;
360 if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group))
361 return;
362
363fail:
364 delete_gpe_attr_array();
365 return;
366}
367
368static void __exit interrupt_stats_exit(void)
369{
370 sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group);
371
372 delete_gpe_attr_array();
373
374 return;
375}
376
169/* -------------------------------------------------------------------------- 377/* --------------------------------------------------------------------------
170 FS Interface (/proc) 378 FS Interface (/proc)
171 -------------------------------------------------------------------------- */ 379 -------------------------------------------------------------------------- */
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
index 0a7d7afac255..7385efa61622 100644
--- a/drivers/acpi/tables/Makefile
+++ b/drivers/acpi/tables/Makefile
@@ -2,6 +2,6 @@
2# Makefile for all Linux ACPI interpreter subdirectories 2# Makefile for all Linux ACPI interpreter subdirectories
3# 3#
4 4
5obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o 5obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
6 6
7EXTRA_CFLAGS += $(ACPI_CFLAGS) 7EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index cf8fa514189f..9ecb4b6c1e7d 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -100,7 +100,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
100 100
101/******************************************************************************* 101/*******************************************************************************
102 * 102 *
103 * FUNCTION: acpi_tb_find_rsdp 103 * FUNCTION: acpi_find_root_pointer
104 * 104 *
105 * PARAMETERS: table_address - Where the table pointer is returned 105 * PARAMETERS: table_address - Where the table pointer is returned
106 * 106 *
@@ -219,8 +219,6 @@ acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
219 return_ACPI_STATUS(AE_NOT_FOUND); 219 return_ACPI_STATUS(AE_NOT_FOUND);
220} 220}
221 221
222ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
223
224/******************************************************************************* 222/*******************************************************************************
225 * 223 *
226 * FUNCTION: acpi_tb_scan_memory_for_rsdp 224 * FUNCTION: acpi_tb_scan_memory_for_rsdp
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 5f79b4451212..8d4b79b4f933 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -43,7 +43,7 @@
43#include <linux/seq_file.h> 43#include <linux/seq_file.h>
44#include <linux/reboot.h> 44#include <linux/reboot.h>
45#include <asm/uaccess.h> 45#include <asm/uaccess.h>
46 46#include <linux/thermal.h>
47#include <acpi/acpi_bus.h> 47#include <acpi/acpi_bus.h>
48#include <acpi/acpi_drivers.h> 48#include <acpi/acpi_drivers.h>
49 49
@@ -65,9 +65,6 @@
65#define ACPI_THERMAL_MAX_ACTIVE 10 65#define ACPI_THERMAL_MAX_ACTIVE 10
66#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65 66#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
67 67
68#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
69#define CELSIUS_TO_KELVIN(t) ((t+273)*10)
70
71#define _COMPONENT ACPI_THERMAL_COMPONENT 68#define _COMPONENT ACPI_THERMAL_COMPONENT
72ACPI_MODULE_NAME("thermal"); 69ACPI_MODULE_NAME("thermal");
73 70
@@ -195,6 +192,8 @@ struct acpi_thermal {
195 struct acpi_thermal_trips trips; 192 struct acpi_thermal_trips trips;
196 struct acpi_handle_list devices; 193 struct acpi_handle_list devices;
197 struct timer_list timer; 194 struct timer_list timer;
195 struct thermal_zone_device *thermal_zone;
196 int tz_enabled;
198 struct mutex lock; 197 struct mutex lock;
199}; 198};
200 199
@@ -321,178 +320,226 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
321 return 0; 320 return 0;
322} 321}
323 322
324static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) 323#define ACPI_TRIPS_CRITICAL 0x01
325{ 324#define ACPI_TRIPS_HOT 0x02
326 acpi_status status = AE_OK; 325#define ACPI_TRIPS_PASSIVE 0x04
327 int i = 0; 326#define ACPI_TRIPS_ACTIVE 0x08
327#define ACPI_TRIPS_DEVICES 0x10
328 328
329#define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
330#define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES
329 331
330 if (!tz) 332#define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
331 return -EINVAL; 333 ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \
334 ACPI_TRIPS_DEVICES)
332 335
333 /* Critical Shutdown (required) */ 336/*
334 337 * This exception is thrown out in two cases:
335 status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, 338 * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
336 &tz->trips.critical.temperature); 339 * when re-evaluating the AML code.
337 if (ACPI_FAILURE(status)) { 340 * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
338 tz->trips.critical.flags.valid = 0; 341 * We need to re-bind the cooling devices of a thermal zone when this occurs.
339 ACPI_EXCEPTION((AE_INFO, status, "No critical threshold")); 342 */
340 return -ENODEV; 343#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \
341 } else { 344do { \
342 tz->trips.critical.flags.valid = 1; 345 if (flags != ACPI_TRIPS_INIT) \
343 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 346 ACPI_EXCEPTION((AE_INFO, AE_ERROR, \
344 "Found critical threshold [%lu]\n", 347 "ACPI thermal trip point %s changed\n" \
345 tz->trips.critical.temperature)); 348 "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
346 } 349} while (0)
350
351static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
352{
353 acpi_status status = AE_OK;
354 struct acpi_handle_list devices;
355 int valid = 0;
356 int i;
347 357
348 if (tz->trips.critical.flags.valid == 1) { 358 /* Critical Shutdown (required) */
349 if (crt == -1) { 359 if (flag & ACPI_TRIPS_CRITICAL) {
360 status = acpi_evaluate_integer(tz->device->handle,
361 "_CRT", NULL, &tz->trips.critical.temperature);
362 if (ACPI_FAILURE(status)) {
350 tz->trips.critical.flags.valid = 0; 363 tz->trips.critical.flags.valid = 0;
351 } else if (crt > 0) { 364 ACPI_EXCEPTION((AE_INFO, status,
352 unsigned long crt_k = CELSIUS_TO_KELVIN(crt); 365 "No critical threshold"));
353 366 return -ENODEV;
354 /* 367 } else {
355 * Allow override to lower critical threshold 368 tz->trips.critical.flags.valid = 1;
356 */ 369 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
357 if (crt_k < tz->trips.critical.temperature) 370 "Found critical threshold [%lu]\n",
358 tz->trips.critical.temperature = crt_k; 371 tz->trips.critical.temperature));
372 }
373 if (tz->trips.critical.flags.valid == 1) {
374 if (crt == -1) {
375 tz->trips.critical.flags.valid = 0;
376 } else if (crt > 0) {
377 unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
378 /*
379 * Allow override to lower critical threshold
380 */
381 if (crt_k < tz->trips.critical.temperature)
382 tz->trips.critical.temperature = crt_k;
383 }
359 } 384 }
360 } 385 }
361 386
362 /* Critical Sleep (optional) */ 387 /* Critical Sleep (optional) */
363 388 if (flag & ACPI_TRIPS_HOT) {
364 status =
365 acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,
366 &tz->trips.hot.temperature);
367 if (ACPI_FAILURE(status)) {
368 tz->trips.hot.flags.valid = 0;
369 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
370 } else {
371 tz->trips.hot.flags.valid = 1;
372 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n",
373 tz->trips.hot.temperature));
374 }
375
376 /* Passive: Processors (optional) */
377
378 if (psv == -1) {
379 status = AE_SUPPORT;
380 } else if (psv > 0) {
381 tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
382 status = AE_OK;
383 } else {
384 status = acpi_evaluate_integer(tz->device->handle, 389 status = acpi_evaluate_integer(tz->device->handle,
385 "_PSV", NULL, &tz->trips.passive.temperature); 390 "_HOT", NULL, &tz->trips.hot.temperature);
391 if (ACPI_FAILURE(status)) {
392 tz->trips.hot.flags.valid = 0;
393 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
394 "No hot threshold\n"));
395 } else {
396 tz->trips.hot.flags.valid = 1;
397 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
398 "Found hot threshold [%lu]\n",
399 tz->trips.critical.temperature));
400 }
386 } 401 }
387 402
388 if (ACPI_FAILURE(status)) { 403 /* Passive (optional) */
389 tz->trips.passive.flags.valid = 0; 404 if (flag & ACPI_TRIPS_PASSIVE) {
390 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n")); 405 valid = tz->trips.passive.flags.valid;
391 } else { 406 if (psv == -1) {
392 tz->trips.passive.flags.valid = 1; 407 status = AE_SUPPORT;
393 408 } else if (psv > 0) {
394 status = 409 tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
395 acpi_evaluate_integer(tz->device->handle, "_TC1", NULL, 410 status = AE_OK;
396 &tz->trips.passive.tc1); 411 } else {
397 if (ACPI_FAILURE(status)) 412 status = acpi_evaluate_integer(tz->device->handle,
398 tz->trips.passive.flags.valid = 0; 413 "_PSV", NULL, &tz->trips.passive.temperature);
399 414 }
400 status =
401 acpi_evaluate_integer(tz->device->handle, "_TC2", NULL,
402 &tz->trips.passive.tc2);
403 if (ACPI_FAILURE(status))
404 tz->trips.passive.flags.valid = 0;
405 415
406 status =
407 acpi_evaluate_integer(tz->device->handle, "_TSP", NULL,
408 &tz->trips.passive.tsp);
409 if (ACPI_FAILURE(status)) 416 if (ACPI_FAILURE(status))
410 tz->trips.passive.flags.valid = 0; 417 tz->trips.passive.flags.valid = 0;
411 418 else {
412 status = 419 tz->trips.passive.flags.valid = 1;
413 acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, 420 if (flag == ACPI_TRIPS_INIT) {
414 &tz->trips.passive.devices); 421 status = acpi_evaluate_integer(
422 tz->device->handle, "_TC1",
423 NULL, &tz->trips.passive.tc1);
424 if (ACPI_FAILURE(status))
425 tz->trips.passive.flags.valid = 0;
426 status = acpi_evaluate_integer(
427 tz->device->handle, "_TC2",
428 NULL, &tz->trips.passive.tc2);
429 if (ACPI_FAILURE(status))
430 tz->trips.passive.flags.valid = 0;
431 status = acpi_evaluate_integer(
432 tz->device->handle, "_TSP",
433 NULL, &tz->trips.passive.tsp);
434 if (ACPI_FAILURE(status))
435 tz->trips.passive.flags.valid = 0;
436 }
437 }
438 }
439 if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
440 memset(&devices, 0, sizeof(struct acpi_handle_list));
441 status = acpi_evaluate_reference(tz->device->handle, "_PSL",
442 NULL, &devices);
415 if (ACPI_FAILURE(status)) 443 if (ACPI_FAILURE(status))
416 tz->trips.passive.flags.valid = 0; 444 tz->trips.passive.flags.valid = 0;
417
418 if (!tz->trips.passive.flags.valid)
419 printk(KERN_WARNING PREFIX "Invalid passive threshold\n");
420 else 445 else
421 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 446 tz->trips.passive.flags.valid = 1;
422 "Found passive threshold [%lu]\n",
423 tz->trips.passive.temperature));
424 }
425 447
426 /* Active: Fans, etc. (optional) */ 448 if (memcmp(&tz->trips.passive.devices, &devices,
449 sizeof(struct acpi_handle_list))) {
450 memcpy(&tz->trips.passive.devices, &devices,
451 sizeof(struct acpi_handle_list));
452 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
453 }
454 }
455 if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
456 if (valid != tz->trips.passive.flags.valid)
457 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
458 }
427 459
460 /* Active (optional) */
428 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { 461 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
429
430 char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; 462 char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
463 valid = tz->trips.active[i].flags.valid;
431 464
432 if (act == -1) 465 if (act == -1)
433 break; /* disable all active trip points */ 466 break; /* disable all active trip points */
434 467
435 status = acpi_evaluate_integer(tz->device->handle, 468 if (flag & ACPI_TRIPS_ACTIVE) {
436 name, NULL, &tz->trips.active[i].temperature); 469 status = acpi_evaluate_integer(tz->device->handle,
437 470 name, NULL, &tz->trips.active[i].temperature);
438 if (ACPI_FAILURE(status)) { 471 if (ACPI_FAILURE(status)) {
439 if (i == 0) /* no active trip points */ 472 tz->trips.active[i].flags.valid = 0;
473 if (i == 0)
474 break;
475 if (act <= 0)
476 break;
477 if (i == 1)
478 tz->trips.active[0].temperature =
479 CELSIUS_TO_KELVIN(act);
480 else
481 /*
482 * Don't allow override higher than
483 * the next higher trip point
484 */
485 tz->trips.active[i - 1].temperature =
486 (tz->trips.active[i - 2].temperature <
487 CELSIUS_TO_KELVIN(act) ?
488 tz->trips.active[i - 2].temperature :
489 CELSIUS_TO_KELVIN(act));
440 break; 490 break;
441 if (act <= 0) /* no override requested */ 491 } else
442 break; 492 tz->trips.active[i].flags.valid = 1;
443 if (i == 1) { /* 1 trip point */
444 tz->trips.active[0].temperature =
445 CELSIUS_TO_KELVIN(act);
446 } else { /* multiple trips */
447 /*
448 * Don't allow override higher than
449 * the next higher trip point
450 */
451 tz->trips.active[i - 1].temperature =
452 (tz->trips.active[i - 2].temperature <
453 CELSIUS_TO_KELVIN(act) ?
454 tz->trips.active[i - 2].temperature :
455 CELSIUS_TO_KELVIN(act));
456 }
457 break;
458 } 493 }
459 494
460 name[2] = 'L'; 495 name[2] = 'L';
461 status = 496 if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
462 acpi_evaluate_reference(tz->device->handle, name, NULL, 497 memset(&devices, 0, sizeof(struct acpi_handle_list));
463 &tz->trips.active[i].devices); 498 status = acpi_evaluate_reference(tz->device->handle,
464 if (ACPI_SUCCESS(status)) { 499 name, NULL, &devices);
465 tz->trips.active[i].flags.valid = 1; 500 if (ACPI_FAILURE(status))
466 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 501 tz->trips.active[i].flags.valid = 0;
467 "Found active threshold [%d]:[%lu]\n", 502 else
468 i, tz->trips.active[i].temperature)); 503 tz->trips.active[i].flags.valid = 1;
469 } else 504
470 ACPI_EXCEPTION((AE_INFO, status, 505 if (memcmp(&tz->trips.active[i].devices, &devices,
471 "Invalid active threshold [%d]", i)); 506 sizeof(struct acpi_handle_list))) {
507 memcpy(&tz->trips.active[i].devices, &devices,
508 sizeof(struct acpi_handle_list));
509 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
510 }
511 }
512 if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
513 if (valid != tz->trips.active[i].flags.valid)
514 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
515
516 if (!tz->trips.active[i].flags.valid)
517 break;
518 }
519
520 if (flag & ACPI_TRIPS_DEVICES) {
521 memset(&devices, 0, sizeof(struct acpi_handle_list));
522 status = acpi_evaluate_reference(tz->device->handle, "_TZD",
523 NULL, &devices);
524 if (memcmp(&tz->devices, &devices,
525 sizeof(struct acpi_handle_list))) {
526 memcpy(&tz->devices, &devices,
527 sizeof(struct acpi_handle_list));
528 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
529 }
472 } 530 }
473 531
474 return 0; 532 return 0;
475} 533}
476 534
477static int acpi_thermal_get_devices(struct acpi_thermal *tz) 535static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
478{ 536{
479 acpi_status status = AE_OK; 537 return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
480
481
482 if (!tz)
483 return -EINVAL;
484
485 status =
486 acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
487 if (ACPI_FAILURE(status))
488 return -ENODEV;
489
490 return 0;
491} 538}
492 539
493static int acpi_thermal_critical(struct acpi_thermal *tz) 540static int acpi_thermal_critical(struct acpi_thermal *tz)
494{ 541{
495 if (!tz || !tz->trips.critical.flags.valid || nocrt) 542 if (!tz || !tz->trips.critical.flags.valid)
496 return -EINVAL; 543 return -EINVAL;
497 544
498 if (tz->temperature >= tz->trips.critical.temperature) { 545 if (tz->temperature >= tz->trips.critical.temperature) {
@@ -501,9 +548,6 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
501 } else if (tz->trips.critical.flags.enabled) 548 } else if (tz->trips.critical.flags.enabled)
502 tz->trips.critical.flags.enabled = 0; 549 tz->trips.critical.flags.enabled = 0;
503 550
504 printk(KERN_EMERG
505 "Critical temperature reached (%ld C), shutting down.\n",
506 KELVIN_TO_CELSIUS(tz->temperature));
507 acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL, 551 acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
508 tz->trips.critical.flags.enabled); 552 tz->trips.critical.flags.enabled);
509 acpi_bus_generate_netlink_event(tz->device->pnp.device_class, 553 acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
@@ -511,14 +555,20 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
511 ACPI_THERMAL_NOTIFY_CRITICAL, 555 ACPI_THERMAL_NOTIFY_CRITICAL,
512 tz->trips.critical.flags.enabled); 556 tz->trips.critical.flags.enabled);
513 557
514 orderly_poweroff(true); 558 /* take no action if nocrt is set */
559 if(!nocrt) {
560 printk(KERN_EMERG
561 "Critical temperature reached (%ld C), shutting down.\n",
562 KELVIN_TO_CELSIUS(tz->temperature));
563 orderly_poweroff(true);
564 }
515 565
516 return 0; 566 return 0;
517} 567}
518 568
519static int acpi_thermal_hot(struct acpi_thermal *tz) 569static int acpi_thermal_hot(struct acpi_thermal *tz)
520{ 570{
521 if (!tz || !tz->trips.hot.flags.valid || nocrt) 571 if (!tz || !tz->trips.hot.flags.valid)
522 return -EINVAL; 572 return -EINVAL;
523 573
524 if (tz->temperature >= tz->trips.hot.temperature) { 574 if (tz->temperature >= tz->trips.hot.temperature) {
@@ -534,7 +584,7 @@ static int acpi_thermal_hot(struct acpi_thermal *tz)
534 ACPI_THERMAL_NOTIFY_HOT, 584 ACPI_THERMAL_NOTIFY_HOT,
535 tz->trips.hot.flags.enabled); 585 tz->trips.hot.flags.enabled);
536 586
537 /* TBD: Call user-mode "sleep(S4)" function */ 587 /* TBD: Call user-mode "sleep(S4)" function if nocrt is cleared */
538 588
539 return 0; 589 return 0;
540} 590}
@@ -732,6 +782,9 @@ static void acpi_thermal_check(void *data)
732 if (result) 782 if (result)
733 goto unlock; 783 goto unlock;
734 784
785 if (!tz->tz_enabled)
786 goto unlock;
787
735 memset(&tz->state, 0, sizeof(tz->state)); 788 memset(&tz->state, 0, sizeof(tz->state));
736 789
737 /* 790 /*
@@ -825,6 +878,290 @@ static void acpi_thermal_check(void *data)
825 mutex_unlock(&tz->lock); 878 mutex_unlock(&tz->lock);
826} 879}
827 880
881/* sys I/F for generic thermal sysfs support */
882static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
883{
884 struct acpi_thermal *tz = thermal->devdata;
885
886 if (!tz)
887 return -EINVAL;
888
889 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature));
890}
891
892static const char enabled[] = "kernel";
893static const char disabled[] = "user";
894static int thermal_get_mode(struct thermal_zone_device *thermal,
895 char *buf)
896{
897 struct acpi_thermal *tz = thermal->devdata;
898
899 if (!tz)
900 return -EINVAL;
901
902 return sprintf(buf, "%s\n", tz->tz_enabled ?
903 enabled : disabled);
904}
905
906static int thermal_set_mode(struct thermal_zone_device *thermal,
907 const char *buf)
908{
909 struct acpi_thermal *tz = thermal->devdata;
910 int enable;
911
912 if (!tz)
913 return -EINVAL;
914
915 /*
916 * enable/disable thermal management from ACPI thermal driver
917 */
918 if (!strncmp(buf, enabled, sizeof enabled - 1))
919 enable = 1;
920 else if (!strncmp(buf, disabled, sizeof disabled - 1))
921 enable = 0;
922 else
923 return -EINVAL;
924
925 if (enable != tz->tz_enabled) {
926 tz->tz_enabled = enable;
927 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
928 "%s ACPI thermal control\n",
929 tz->tz_enabled ? enabled : disabled));
930 acpi_thermal_check(tz);
931 }
932 return 0;
933}
934
935static int thermal_get_trip_type(struct thermal_zone_device *thermal,
936 int trip, char *buf)
937{
938 struct acpi_thermal *tz = thermal->devdata;
939 int i;
940
941 if (!tz || trip < 0)
942 return -EINVAL;
943
944 if (tz->trips.critical.flags.valid) {
945 if (!trip)
946 return sprintf(buf, "critical\n");
947 trip--;
948 }
949
950 if (tz->trips.hot.flags.valid) {
951 if (!trip)
952 return sprintf(buf, "hot\n");
953 trip--;
954 }
955
956 if (tz->trips.passive.flags.valid) {
957 if (!trip)
958 return sprintf(buf, "passive\n");
959 trip--;
960 }
961
962 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
963 tz->trips.active[i].flags.valid; i++) {
964 if (!trip)
965 return sprintf(buf, "active%d\n", i);
966 trip--;
967 }
968
969 return -EINVAL;
970}
971
972static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
973 int trip, char *buf)
974{
975 struct acpi_thermal *tz = thermal->devdata;
976 int i;
977
978 if (!tz || trip < 0)
979 return -EINVAL;
980
981 if (tz->trips.critical.flags.valid) {
982 if (!trip)
983 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
984 tz->trips.critical.temperature));
985 trip--;
986 }
987
988 if (tz->trips.hot.flags.valid) {
989 if (!trip)
990 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
991 tz->trips.hot.temperature));
992 trip--;
993 }
994
995 if (tz->trips.passive.flags.valid) {
996 if (!trip)
997 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
998 tz->trips.passive.temperature));
999 trip--;
1000 }
1001
1002 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
1003 tz->trips.active[i].flags.valid; i++) {
1004 if (!trip)
1005 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
1006 tz->trips.active[i].temperature));
1007 trip--;
1008 }
1009
1010 return -EINVAL;
1011}
1012
1013typedef int (*cb)(struct thermal_zone_device *, int,
1014 struct thermal_cooling_device *);
1015static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
1016 struct thermal_cooling_device *cdev,
1017 cb action)
1018{
1019 struct acpi_device *device = cdev->devdata;
1020 struct acpi_thermal *tz = thermal->devdata;
1021 struct acpi_device *dev;
1022 acpi_status status;
1023 acpi_handle handle;
1024 int i;
1025 int j;
1026 int trip = -1;
1027 int result = 0;
1028
1029 if (tz->trips.critical.flags.valid)
1030 trip++;
1031
1032 if (tz->trips.hot.flags.valid)
1033 trip++;
1034
1035 if (tz->trips.passive.flags.valid) {
1036 trip++;
1037 for (i = 0; i < tz->trips.passive.devices.count;
1038 i++) {
1039 handle = tz->trips.passive.devices.handles[i];
1040 status = acpi_bus_get_device(handle, &dev);
1041 if (ACPI_SUCCESS(status) && (dev == device)) {
1042 result = action(thermal, trip, cdev);
1043 if (result)
1044 goto failed;
1045 }
1046 }
1047 }
1048
1049 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
1050 if (!tz->trips.active[i].flags.valid)
1051 break;
1052 trip++;
1053 for (j = 0;
1054 j < tz->trips.active[i].devices.count;
1055 j++) {
1056 handle = tz->trips.active[i].devices.handles[j];
1057 status = acpi_bus_get_device(handle, &dev);
1058 if (ACPI_SUCCESS(status) && (dev == device)) {
1059 result = action(thermal, trip, cdev);
1060 if (result)
1061 goto failed;
1062 }
1063 }
1064 }
1065
1066 for (i = 0; i < tz->devices.count; i++) {
1067 handle = tz->devices.handles[i];
1068 status = acpi_bus_get_device(handle, &dev);
1069 if (ACPI_SUCCESS(status) && (dev == device)) {
1070 result = action(thermal, -1, cdev);
1071 if (result)
1072 goto failed;
1073 }
1074 }
1075
1076failed:
1077 return result;
1078}
1079
1080static int
1081acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
1082 struct thermal_cooling_device *cdev)
1083{
1084 return acpi_thermal_cooling_device_cb(thermal, cdev,
1085 thermal_zone_bind_cooling_device);
1086}
1087
1088static int
1089acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
1090 struct thermal_cooling_device *cdev)
1091{
1092 return acpi_thermal_cooling_device_cb(thermal, cdev,
1093 thermal_zone_unbind_cooling_device);
1094}
1095
1096static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
1097 .bind = acpi_thermal_bind_cooling_device,
1098 .unbind = acpi_thermal_unbind_cooling_device,
1099 .get_temp = thermal_get_temp,
1100 .get_mode = thermal_get_mode,
1101 .set_mode = thermal_set_mode,
1102 .get_trip_type = thermal_get_trip_type,
1103 .get_trip_temp = thermal_get_trip_temp,
1104};
1105
1106static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
1107{
1108 int trips = 0;
1109 int result;
1110 acpi_status status;
1111 int i;
1112
1113 if (tz->trips.critical.flags.valid)
1114 trips++;
1115
1116 if (tz->trips.hot.flags.valid)
1117 trips++;
1118
1119 if (tz->trips.passive.flags.valid)
1120 trips++;
1121
1122 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
1123 tz->trips.active[i].flags.valid; i++, trips++);
1124 tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
1125 trips, tz, &acpi_thermal_zone_ops);
1126 if (!tz->thermal_zone)
1127 return -ENODEV;
1128
1129 result = sysfs_create_link(&tz->device->dev.kobj,
1130 &tz->thermal_zone->device.kobj, "thermal_zone");
1131 if (result)
1132 return result;
1133
1134 result = sysfs_create_link(&tz->thermal_zone->device.kobj,
1135 &tz->device->dev.kobj, "device");
1136 if (result)
1137 return result;
1138
1139 status = acpi_attach_data(tz->device->handle,
1140 acpi_bus_private_data_handler,
1141 tz->thermal_zone);
1142 if (ACPI_FAILURE(status)) {
1143 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1144 "Error attaching device data\n"));
1145 return -ENODEV;
1146 }
1147
1148 tz->tz_enabled = 1;
1149
1150 printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n",
1151 tz->device->dev.bus_id, tz->thermal_zone->id);
1152 return 0;
1153}
1154
1155static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
1156{
1157 sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
1158 sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
1159 thermal_zone_device_unregister(tz->thermal_zone);
1160 tz->thermal_zone = NULL;
1161 acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler);
1162}
1163
1164
828/* -------------------------------------------------------------------------- 1165/* --------------------------------------------------------------------------
829 FS Interface (/proc) 1166 FS Interface (/proc)
830 -------------------------------------------------------------------------- */ 1167 -------------------------------------------------------------------------- */
@@ -1181,15 +1518,15 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
1181 acpi_thermal_check(tz); 1518 acpi_thermal_check(tz);
1182 break; 1519 break;
1183 case ACPI_THERMAL_NOTIFY_THRESHOLDS: 1520 case ACPI_THERMAL_NOTIFY_THRESHOLDS:
1184 acpi_thermal_get_trip_points(tz); 1521 acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
1185 acpi_thermal_check(tz); 1522 acpi_thermal_check(tz);
1186 acpi_bus_generate_proc_event(device, event, 0); 1523 acpi_bus_generate_proc_event(device, event, 0);
1187 acpi_bus_generate_netlink_event(device->pnp.device_class, 1524 acpi_bus_generate_netlink_event(device->pnp.device_class,
1188 device->dev.bus_id, event, 0); 1525 device->dev.bus_id, event, 0);
1189 break; 1526 break;
1190 case ACPI_THERMAL_NOTIFY_DEVICES: 1527 case ACPI_THERMAL_NOTIFY_DEVICES:
1191 if (tz->flags.devices) 1528 acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
1192 acpi_thermal_get_devices(tz); 1529 acpi_thermal_check(tz);
1193 acpi_bus_generate_proc_event(device, event, 0); 1530 acpi_bus_generate_proc_event(device, event, 0);
1194 acpi_bus_generate_netlink_event(device->pnp.device_class, 1531 acpi_bus_generate_netlink_event(device->pnp.device_class,
1195 device->dev.bus_id, event, 0); 1532 device->dev.bus_id, event, 0);
@@ -1232,11 +1569,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
1232 else 1569 else
1233 acpi_thermal_get_polling_frequency(tz); 1570 acpi_thermal_get_polling_frequency(tz);
1234 1571
1235 /* Get devices in this thermal zone [_TZD] (optional) */
1236 result = acpi_thermal_get_devices(tz);
1237 if (!result)
1238 tz->flags.devices = 1;
1239
1240 return 0; 1572 return 0;
1241} 1573}
1242 1574
@@ -1260,13 +1592,19 @@ static int acpi_thermal_add(struct acpi_device *device)
1260 strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); 1592 strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1261 acpi_driver_data(device) = tz; 1593 acpi_driver_data(device) = tz;
1262 mutex_init(&tz->lock); 1594 mutex_init(&tz->lock);
1595
1596
1263 result = acpi_thermal_get_info(tz); 1597 result = acpi_thermal_get_info(tz);
1264 if (result) 1598 if (result)
1265 goto end; 1599 goto free_memory;
1600
1601 result = acpi_thermal_register_thermal_zone(tz);
1602 if (result)
1603 goto free_memory;
1266 1604
1267 result = acpi_thermal_add_fs(device); 1605 result = acpi_thermal_add_fs(device);
1268 if (result) 1606 if (result)
1269 goto end; 1607 goto unregister_thermal_zone;
1270 1608
1271 init_timer(&tz->timer); 1609 init_timer(&tz->timer);
1272 1610
@@ -1277,19 +1615,21 @@ static int acpi_thermal_add(struct acpi_device *device)
1277 acpi_thermal_notify, tz); 1615 acpi_thermal_notify, tz);
1278 if (ACPI_FAILURE(status)) { 1616 if (ACPI_FAILURE(status)) {
1279 result = -ENODEV; 1617 result = -ENODEV;
1280 goto end; 1618 goto remove_fs;
1281 } 1619 }
1282 1620
1283 printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n", 1621 printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
1284 acpi_device_name(device), acpi_device_bid(device), 1622 acpi_device_name(device), acpi_device_bid(device),
1285 KELVIN_TO_CELSIUS(tz->temperature)); 1623 KELVIN_TO_CELSIUS(tz->temperature));
1624 goto end;
1286 1625
1287 end: 1626remove_fs:
1288 if (result) { 1627 acpi_thermal_remove_fs(device);
1289 acpi_thermal_remove_fs(device); 1628unregister_thermal_zone:
1290 kfree(tz); 1629 thermal_zone_device_unregister(tz->thermal_zone);
1291 } 1630free_memory:
1292 1631 kfree(tz);
1632end:
1293 return result; 1633 return result;
1294} 1634}
1295 1635
@@ -1329,6 +1669,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
1329 } 1669 }
1330 1670
1331 acpi_thermal_remove_fs(device); 1671 acpi_thermal_remove_fs(device);
1672 acpi_thermal_unregister_thermal_zone(tz);
1332 mutex_destroy(&tz->lock); 1673 mutex_destroy(&tz->lock);
1333 kfree(tz); 1674 kfree(tz);
1334 return 0; 1675 return 0;
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 93ea8290b4f7..630c9a2c5b7b 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -671,7 +671,6 @@ void acpi_ut_init_globals(void)
671 671
672 /* GPE support */ 672 /* GPE support */
673 673
674 acpi_gpe_count = 0;
675 acpi_gbl_gpe_xrupt_list_head = NULL; 674 acpi_gbl_gpe_xrupt_list_head = NULL;
676 acpi_gbl_gpe_fadt_blocks[0] = NULL; 675 acpi_gbl_gpe_fadt_blocks[0] = NULL;
677 acpi_gbl_gpe_fadt_blocks[1] = NULL; 676 acpi_gbl_gpe_fadt_blocks[1] = NULL;
@@ -735,4 +734,3 @@ void acpi_ut_init_globals(void)
735 734
736ACPI_EXPORT_SYMBOL(acpi_dbg_level) 735ACPI_EXPORT_SYMBOL(acpi_dbg_level)
737 ACPI_EXPORT_SYMBOL(acpi_dbg_layer) 736 ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
738 ACPI_EXPORT_SYMBOL(acpi_gpe_count)
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index bd77e81e81c1..7f714fa2a454 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -34,6 +34,7 @@
34#include <linux/seq_file.h> 34#include <linux/seq_file.h>
35#include <linux/input.h> 35#include <linux/input.h>
36#include <linux/backlight.h> 36#include <linux/backlight.h>
37#include <linux/thermal.h>
37#include <linux/video_output.h> 38#include <linux/video_output.h>
38#include <asm/uaccess.h> 39#include <asm/uaccess.h>
39 40
@@ -72,8 +73,12 @@ MODULE_AUTHOR("Bruno Ducrot");
72MODULE_DESCRIPTION("ACPI Video Driver"); 73MODULE_DESCRIPTION("ACPI Video Driver");
73MODULE_LICENSE("GPL"); 74MODULE_LICENSE("GPL");
74 75
76static int brightness_switch_enabled = 1;
77module_param(brightness_switch_enabled, bool, 0644);
78
75static int acpi_video_bus_add(struct acpi_device *device); 79static int acpi_video_bus_add(struct acpi_device *device);
76static int acpi_video_bus_remove(struct acpi_device *device, int type); 80static int acpi_video_bus_remove(struct acpi_device *device, int type);
81static int acpi_video_resume(struct acpi_device *device);
77 82
78static const struct acpi_device_id video_device_ids[] = { 83static const struct acpi_device_id video_device_ids[] = {
79 {ACPI_VIDEO_HID, 0}, 84 {ACPI_VIDEO_HID, 0},
@@ -88,6 +93,7 @@ static struct acpi_driver acpi_video_bus = {
88 .ops = { 93 .ops = {
89 .add = acpi_video_bus_add, 94 .add = acpi_video_bus_add,
90 .remove = acpi_video_bus_remove, 95 .remove = acpi_video_bus_remove,
96 .resume = acpi_video_resume,
91 }, 97 },
92}; 98};
93 99
@@ -179,6 +185,7 @@ struct acpi_video_device {
179 struct acpi_device *dev; 185 struct acpi_device *dev;
180 struct acpi_video_device_brightness *brightness; 186 struct acpi_video_device_brightness *brightness;
181 struct backlight_device *backlight; 187 struct backlight_device *backlight;
188 struct thermal_cooling_device *cdev;
182 struct output_device *output_dev; 189 struct output_device *output_dev;
183}; 190};
184 191
@@ -273,7 +280,6 @@ static void acpi_video_device_rebind(struct acpi_video_bus *video);
273static void acpi_video_device_bind(struct acpi_video_bus *video, 280static void acpi_video_device_bind(struct acpi_video_bus *video,
274 struct acpi_video_device *device); 281 struct acpi_video_device *device);
275static int acpi_video_device_enumerate(struct acpi_video_bus *video); 282static int acpi_video_device_enumerate(struct acpi_video_bus *video);
276static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
277static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, 283static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
278 int level); 284 int level);
279static int acpi_video_device_lcd_get_level_current( 285static int acpi_video_device_lcd_get_level_current(
@@ -292,18 +298,26 @@ static int acpi_video_device_set_state(struct acpi_video_device *device, int sta
292static int acpi_video_get_brightness(struct backlight_device *bd) 298static int acpi_video_get_brightness(struct backlight_device *bd)
293{ 299{
294 unsigned long cur_level; 300 unsigned long cur_level;
301 int i;
295 struct acpi_video_device *vd = 302 struct acpi_video_device *vd =
296 (struct acpi_video_device *)bl_get_data(bd); 303 (struct acpi_video_device *)bl_get_data(bd);
297 acpi_video_device_lcd_get_level_current(vd, &cur_level); 304 acpi_video_device_lcd_get_level_current(vd, &cur_level);
298 return (int) cur_level; 305 for (i = 2; i < vd->brightness->count; i++) {
306 if (vd->brightness->levels[i] == cur_level)
307 /* The first two entries are special - see page 575
308 of the ACPI spec 3.0 */
309 return i-2;
310 }
311 return 0;
299} 312}
300 313
301static int acpi_video_set_brightness(struct backlight_device *bd) 314static int acpi_video_set_brightness(struct backlight_device *bd)
302{ 315{
303 int request_level = bd->props.brightness; 316 int request_level = bd->props.brightness+2;
304 struct acpi_video_device *vd = 317 struct acpi_video_device *vd =
305 (struct acpi_video_device *)bl_get_data(bd); 318 (struct acpi_video_device *)bl_get_data(bd);
306 acpi_video_device_lcd_set_level(vd, request_level); 319 acpi_video_device_lcd_set_level(vd,
320 vd->brightness->levels[request_level]);
307 return 0; 321 return 0;
308} 322}
309 323
@@ -334,6 +348,54 @@ static struct output_properties acpi_output_properties = {
334 .set_state = acpi_video_output_set, 348 .set_state = acpi_video_output_set,
335 .get_status = acpi_video_output_get, 349 .get_status = acpi_video_output_get,
336}; 350};
351
352
353/* thermal cooling device callbacks */
354static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf)
355{
356 struct acpi_device *device = cdev->devdata;
357 struct acpi_video_device *video = acpi_driver_data(device);
358
359 return sprintf(buf, "%d\n", video->brightness->count - 3);
360}
361
362static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
363{
364 struct acpi_device *device = cdev->devdata;
365 struct acpi_video_device *video = acpi_driver_data(device);
366 unsigned long level;
367 int state;
368
369 acpi_video_device_lcd_get_level_current(video, &level);
370 for (state = 2; state < video->brightness->count; state++)
371 if (level == video->brightness->levels[state])
372 return sprintf(buf, "%d\n",
373 video->brightness->count - state - 1);
374
375 return -EINVAL;
376}
377
378static int
379video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
380{
381 struct acpi_device *device = cdev->devdata;
382 struct acpi_video_device *video = acpi_driver_data(device);
383 int level;
384
385 if ( state >= video->brightness->count - 2)
386 return -EINVAL;
387
388 state = video->brightness->count - state;
389 level = video->brightness->levels[state -1];
390 return acpi_video_device_lcd_set_level(video, level);
391}
392
393static struct thermal_cooling_device_ops video_cooling_ops = {
394 .get_max_state = video_get_max_state,
395 .get_cur_state = video_get_cur_state,
396 .set_cur_state = video_set_cur_state,
397};
398
337/* -------------------------------------------------------------------------- 399/* --------------------------------------------------------------------------
338 Video Management 400 Video Management
339 -------------------------------------------------------------------------- */ 401 -------------------------------------------------------------------------- */
@@ -652,7 +714,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
652 kfree(obj); 714 kfree(obj);
653 715
654 if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ 716 if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
655 unsigned long tmp; 717 int result;
656 static int count = 0; 718 static int count = 0;
657 char *name; 719 char *name;
658 name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); 720 name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
@@ -660,14 +722,30 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
660 return; 722 return;
661 723
662 sprintf(name, "acpi_video%d", count++); 724 sprintf(name, "acpi_video%d", count++);
663 acpi_video_device_lcd_get_level_current(device, &tmp);
664 device->backlight = backlight_device_register(name, 725 device->backlight = backlight_device_register(name,
665 NULL, device, &acpi_backlight_ops); 726 NULL, device, &acpi_backlight_ops);
666 device->backlight->props.max_brightness = max_level; 727 device->backlight->props.max_brightness = device->brightness->count-3;
667 device->backlight->props.brightness = (int)tmp; 728 device->backlight->props.brightness = acpi_video_get_brightness(device->backlight);
668 backlight_update_status(device->backlight); 729 backlight_update_status(device->backlight);
669
670 kfree(name); 730 kfree(name);
731
732 device->cdev = thermal_cooling_device_register("LCD",
733 device->dev, &video_cooling_ops);
734 if (device->cdev) {
735 printk(KERN_INFO PREFIX
736 "%s is registered as cooling_device%d\n",
737 device->dev->dev.bus_id, device->cdev->id);
738 result = sysfs_create_link(&device->dev->dev.kobj,
739 &device->cdev->device.kobj,
740 "thermal_cooling");
741 if (result)
742 printk(KERN_ERR PREFIX "Create sysfs link\n");
743 result = sysfs_create_link(&device->cdev->device.kobj,
744 &device->dev->dev.kobj,
745 "device");
746 if (result)
747 printk(KERN_ERR PREFIX "Create sysfs link\n");
748 }
671 } 749 }
672 if (device->cap._DCS && device->cap._DSS){ 750 if (device->cap._DCS && device->cap._DSS){
673 static int count = 0; 751 static int count = 0;
@@ -726,11 +804,40 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
726static int acpi_video_bus_check(struct acpi_video_bus *video) 804static int acpi_video_bus_check(struct acpi_video_bus *video)
727{ 805{
728 acpi_status status = -ENOENT; 806 acpi_status status = -ENOENT;
729 807 long device_id;
808 struct device *dev;
809 struct acpi_device *device;
730 810
731 if (!video) 811 if (!video)
732 return -EINVAL; 812 return -EINVAL;
733 813
814 device = video->device;
815
816 status =
817 acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
818
819 if (!ACPI_SUCCESS(status))
820 return -ENODEV;
821
822 /* We need to attempt to determine whether the _ADR refers to a
823 PCI device or not. There's no terribly good way to do this,
824 so the best we can hope for is to assume that there'll never
825 be a video device in the host bridge */
826 if (device_id >= 0x10000) {
827 /* It looks like a PCI device. Does it exist? */
828 dev = acpi_get_physical_device(device->handle);
829 } else {
830 /* It doesn't look like a PCI device. Does its parent
831 exist? */
832 acpi_handle phandle;
833 if (acpi_get_parent(device->handle, &phandle))
834 return -ENODEV;
835 dev = acpi_get_physical_device(phandle);
836 }
837 if (!dev)
838 return -ENODEV;
839 put_device(dev);
840
734 /* Since there is no HID, CID and so on for VGA driver, we have 841 /* Since there is no HID, CID and so on for VGA driver, we have
735 * to check well known required nodes. 842 * to check well known required nodes.
736 */ 843 */
@@ -1256,8 +1363,37 @@ acpi_video_bus_write_DOS(struct file *file,
1256 1363
1257static int acpi_video_bus_add_fs(struct acpi_device *device) 1364static int acpi_video_bus_add_fs(struct acpi_device *device)
1258{ 1365{
1366 long device_id;
1367 int status;
1259 struct proc_dir_entry *entry = NULL; 1368 struct proc_dir_entry *entry = NULL;
1260 struct acpi_video_bus *video; 1369 struct acpi_video_bus *video;
1370 struct device *dev;
1371
1372 status =
1373 acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
1374
1375 if (!ACPI_SUCCESS(status))
1376 return -ENODEV;
1377
1378 /* We need to attempt to determine whether the _ADR refers to a
1379 PCI device or not. There's no terribly good way to do this,
1380 so the best we can hope for is to assume that there'll never
1381 be a video device in the host bridge */
1382 if (device_id >= 0x10000) {
1383 /* It looks like a PCI device. Does it exist? */
1384 dev = acpi_get_physical_device(device->handle);
1385 } else {
1386 /* It doesn't look like a PCI device. Does its parent
1387 exist? */
1388 acpi_handle phandle;
1389 if (acpi_get_parent(device->handle, &phandle))
1390 return -ENODEV;
1391 dev = acpi_get_physical_device(phandle);
1392 }
1393 if (!dev)
1394 return -ENODEV;
1395 put_device(dev);
1396
1261 1397
1262 1398
1263 video = acpi_driver_data(device); 1399 video = acpi_driver_data(device);
@@ -1580,64 +1716,6 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
1580 return status; 1716 return status;
1581} 1717}
1582 1718
1583/*
1584 * Arg:
1585 * video : video bus device
1586 * event : notify event
1587 *
1588 * Return:
1589 * < 0 : error
1590 *
1591 * 1. Find out the current active output device.
1592 * 2. Identify the next output device to switch to.
1593 * 3. call _DSS to do actual switch.
1594 */
1595
1596static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
1597{
1598 struct list_head *node;
1599 struct acpi_video_device *dev = NULL;
1600 struct acpi_video_device *dev_next = NULL;
1601 struct acpi_video_device *dev_prev = NULL;
1602 unsigned long state;
1603 int status = 0;
1604
1605 mutex_lock(&video->device_list_lock);
1606
1607 list_for_each(node, &video->video_device_list) {
1608 dev = container_of(node, struct acpi_video_device, entry);
1609 status = acpi_video_device_get_state(dev, &state);
1610 if (state & 0x2) {
1611 dev_next = container_of(node->next,
1612 struct acpi_video_device, entry);
1613 dev_prev = container_of(node->prev,
1614 struct acpi_video_device, entry);
1615 goto out;
1616 }
1617 }
1618
1619 dev_next = container_of(node->next, struct acpi_video_device, entry);
1620 dev_prev = container_of(node->prev, struct acpi_video_device, entry);
1621
1622 out:
1623 mutex_unlock(&video->device_list_lock);
1624
1625 switch (event) {
1626 case ACPI_VIDEO_NOTIFY_CYCLE:
1627 case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
1628 acpi_video_device_set_state(dev, 0);
1629 acpi_video_device_set_state(dev_next, 0x80000001);
1630 break;
1631 case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
1632 acpi_video_device_set_state(dev, 0);
1633 acpi_video_device_set_state(dev_prev, 0x80000001);
1634 default:
1635 break;
1636 }
1637
1638 return status;
1639}
1640
1641static int 1719static int
1642acpi_video_get_next_level(struct acpi_video_device *device, 1720acpi_video_get_next_level(struct acpi_video_device *device,
1643 u32 level_current, u32 event) 1721 u32 level_current, u32 event)
@@ -1729,6 +1807,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
1729 ACPI_DEVICE_NOTIFY, 1807 ACPI_DEVICE_NOTIFY,
1730 acpi_video_device_notify); 1808 acpi_video_device_notify);
1731 backlight_device_unregister(device->backlight); 1809 backlight_device_unregister(device->backlight);
1810 if (device->cdev) {
1811 sysfs_remove_link(&device->dev->dev.kobj,
1812 "thermal_cooling");
1813 sysfs_remove_link(&device->cdev->device.kobj,
1814 "device");
1815 thermal_cooling_device_unregister(device->cdev);
1816 device->cdev = NULL;
1817 }
1732 video_output_unregister(device->output_dev); 1818 video_output_unregister(device->output_dev);
1733 1819
1734 return 0; 1820 return 0;
@@ -1797,23 +1883,19 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
1797 * connector. */ 1883 * connector. */
1798 acpi_video_device_enumerate(video); 1884 acpi_video_device_enumerate(video);
1799 acpi_video_device_rebind(video); 1885 acpi_video_device_rebind(video);
1800 acpi_video_switch_output(video, event);
1801 acpi_bus_generate_proc_event(device, event, 0); 1886 acpi_bus_generate_proc_event(device, event, 0);
1802 keycode = KEY_SWITCHVIDEOMODE; 1887 keycode = KEY_SWITCHVIDEOMODE;
1803 break; 1888 break;
1804 1889
1805 case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ 1890 case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */
1806 acpi_video_switch_output(video, event);
1807 acpi_bus_generate_proc_event(device, event, 0); 1891 acpi_bus_generate_proc_event(device, event, 0);
1808 keycode = KEY_SWITCHVIDEOMODE; 1892 keycode = KEY_SWITCHVIDEOMODE;
1809 break; 1893 break;
1810 case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ 1894 case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
1811 acpi_video_switch_output(video, event);
1812 acpi_bus_generate_proc_event(device, event, 0); 1895 acpi_bus_generate_proc_event(device, event, 0);
1813 keycode = KEY_VIDEO_NEXT; 1896 keycode = KEY_VIDEO_NEXT;
1814 break; 1897 break;
1815 case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */ 1898 case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
1816 acpi_video_switch_output(video, event);
1817 acpi_bus_generate_proc_event(device, event, 0); 1899 acpi_bus_generate_proc_event(device, event, 0);
1818 keycode = KEY_VIDEO_PREV; 1900 keycode = KEY_VIDEO_PREV;
1819 break; 1901 break;
@@ -1825,6 +1907,7 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
1825 break; 1907 break;
1826 } 1908 }
1827 1909
1910 acpi_notifier_call_chain(device, event, 0);
1828 input_report_key(input, keycode, 1); 1911 input_report_key(input, keycode, 1);
1829 input_sync(input); 1912 input_sync(input);
1830 input_report_key(input, keycode, 0); 1913 input_report_key(input, keycode, 0);
@@ -1850,27 +1933,32 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
1850 1933
1851 switch (event) { 1934 switch (event) {
1852 case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ 1935 case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
1853 acpi_video_switch_brightness(video_device, event); 1936 if (brightness_switch_enabled)
1937 acpi_video_switch_brightness(video_device, event);
1854 acpi_bus_generate_proc_event(device, event, 0); 1938 acpi_bus_generate_proc_event(device, event, 0);
1855 keycode = KEY_BRIGHTNESS_CYCLE; 1939 keycode = KEY_BRIGHTNESS_CYCLE;
1856 break; 1940 break;
1857 case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ 1941 case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
1858 acpi_video_switch_brightness(video_device, event); 1942 if (brightness_switch_enabled)
1943 acpi_video_switch_brightness(video_device, event);
1859 acpi_bus_generate_proc_event(device, event, 0); 1944 acpi_bus_generate_proc_event(device, event, 0);
1860 keycode = KEY_BRIGHTNESSUP; 1945 keycode = KEY_BRIGHTNESSUP;
1861 break; 1946 break;
1862 case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ 1947 case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
1863 acpi_video_switch_brightness(video_device, event); 1948 if (brightness_switch_enabled)
1949 acpi_video_switch_brightness(video_device, event);
1864 acpi_bus_generate_proc_event(device, event, 0); 1950 acpi_bus_generate_proc_event(device, event, 0);
1865 keycode = KEY_BRIGHTNESSDOWN; 1951 keycode = KEY_BRIGHTNESSDOWN;
1866 break; 1952 break;
1867 case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */ 1953 case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
1868 acpi_video_switch_brightness(video_device, event); 1954 if (brightness_switch_enabled)
1955 acpi_video_switch_brightness(video_device, event);
1869 acpi_bus_generate_proc_event(device, event, 0); 1956 acpi_bus_generate_proc_event(device, event, 0);
1870 keycode = KEY_BRIGHTNESS_ZERO; 1957 keycode = KEY_BRIGHTNESS_ZERO;
1871 break; 1958 break;
1872 case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ 1959 case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
1873 acpi_video_switch_brightness(video_device, event); 1960 if (brightness_switch_enabled)
1961 acpi_video_switch_brightness(video_device, event);
1874 acpi_bus_generate_proc_event(device, event, 0); 1962 acpi_bus_generate_proc_event(device, event, 0);
1875 keycode = KEY_DISPLAY_OFF; 1963 keycode = KEY_DISPLAY_OFF;
1876 break; 1964 break;
@@ -1881,6 +1969,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
1881 break; 1969 break;
1882 } 1970 }
1883 1971
1972 acpi_notifier_call_chain(device, event, 0);
1884 input_report_key(input, keycode, 1); 1973 input_report_key(input, keycode, 1);
1885 input_sync(input); 1974 input_sync(input);
1886 input_report_key(input, keycode, 0); 1975 input_report_key(input, keycode, 0);
@@ -1890,6 +1979,25 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
1890} 1979}
1891 1980
1892static int instance; 1981static int instance;
1982static int acpi_video_resume(struct acpi_device *device)
1983{
1984 struct acpi_video_bus *video;
1985 struct acpi_video_device *video_device;
1986 int i;
1987
1988 if (!device || !acpi_driver_data(device))
1989 return -EINVAL;
1990
1991 video = acpi_driver_data(device);
1992
1993 for (i = 0; i < video->attached_count; i++) {
1994 video_device = video->attached_array[i].bind_info;
1995 if (video_device && video_device->backlight)
1996 acpi_video_set_brightness(video_device->backlight);
1997 }
1998 return AE_OK;
1999}
2000
1893static int acpi_video_bus_add(struct acpi_device *device) 2001static int acpi_video_bus_add(struct acpi_device *device)
1894{ 2002{
1895 acpi_status status; 2003 acpi_status status;
diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c
new file mode 100644
index 000000000000..36b84ab418dd
--- /dev/null
+++ b/drivers/acpi/wmi.c
@@ -0,0 +1,710 @@
1/*
2 * ACPI-WMI mapping driver
3 *
4 * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
5 *
6 * GUID parsing code from ldm.c is:
7 * Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
8 * Copyright (c) 2001-2007 Anton Altaparmakov
9 * Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
10 *
11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or (at
16 * your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 *
27 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28 */
29
30#include <linux/kernel.h>
31#include <linux/init.h>
32#include <linux/types.h>
33#include <linux/list.h>
34#include <linux/acpi.h>
35#include <acpi/acpi_bus.h>
36#include <acpi/acpi_drivers.h>
37
38ACPI_MODULE_NAME("wmi");
39MODULE_AUTHOR("Carlos Corbacho");
40MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
41MODULE_LICENSE("GPL");
42
43#define ACPI_WMI_CLASS "wmi"
44
45#undef PREFIX
46#define PREFIX "ACPI: WMI: "
47
48static DEFINE_MUTEX(wmi_data_lock);
49
50struct guid_block {
51 char guid[16];
52 union {
53 char object_id[2];
54 struct {
55 unsigned char notify_id;
56 unsigned char reserved;
57 };
58 };
59 u8 instance_count;
60 u8 flags;
61};
62
63struct wmi_block {
64 struct list_head list;
65 struct guid_block gblock;
66 acpi_handle handle;
67 wmi_notify_handler handler;
68 void *handler_data;
69};
70
71static struct wmi_block wmi_blocks;
72
73/*
74 * If the GUID data block is marked as expensive, we must enable and
75 * explicitily disable data collection.
76 */
77#define ACPI_WMI_EXPENSIVE 0x1
78#define ACPI_WMI_METHOD 0x2 /* GUID is a method */
79#define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */
80#define ACPI_WMI_EVENT 0x8 /* GUID is an event */
81
82static int acpi_wmi_remove(struct acpi_device *device, int type);
83static int acpi_wmi_add(struct acpi_device *device);
84
85static const struct acpi_device_id wmi_device_ids[] = {
86 {"PNP0C14", 0},
87 {"pnp0c14", 0},
88 {"", 0},
89};
90MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
91
92static struct acpi_driver acpi_wmi_driver = {
93 .name = "wmi",
94 .class = ACPI_WMI_CLASS,
95 .ids = wmi_device_ids,
96 .ops = {
97 .add = acpi_wmi_add,
98 .remove = acpi_wmi_remove,
99 },
100};
101
102/*
103 * GUID parsing functions
104 */
105
106/**
107 * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
108 * @src: Pointer to at least 2 characters to convert.
109 *
110 * Convert a two character ASCII hex string to a number.
111 *
112 * Return: 0-255 Success, the byte was parsed correctly
113 * -1 Error, an invalid character was supplied
114 */
115static int wmi_parse_hexbyte(const u8 *src)
116{
117 unsigned int x; /* For correct wrapping */
118 int h;
119
120 /* high part */
121 x = src[0];
122 if (x - '0' <= '9' - '0') {
123 h = x - '0';
124 } else if (x - 'a' <= 'f' - 'a') {
125 h = x - 'a' + 10;
126 } else if (x - 'A' <= 'F' - 'A') {
127 h = x - 'A' + 10;
128 } else {
129 return -1;
130 }
131 h <<= 4;
132
133 /* low part */
134 x = src[1];
135 if (x - '0' <= '9' - '0')
136 return h | (x - '0');
137 if (x - 'a' <= 'f' - 'a')
138 return h | (x - 'a' + 10);
139 if (x - 'A' <= 'F' - 'A')
140 return h | (x - 'A' + 10);
141 return -1;
142}
143
144/**
145 * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
146 * @src: Memory block holding binary GUID (16 bytes)
147 * @dest: Memory block to hold byte swapped binary GUID (16 bytes)
148 *
149 * Byte swap a binary GUID to match it's real GUID value
150 */
151static void wmi_swap_bytes(u8 *src, u8 *dest)
152{
153 int i;
154
155 for (i = 0; i <= 3; i++)
156 memcpy(dest + i, src + (3 - i), 1);
157
158 for (i = 0; i <= 1; i++)
159 memcpy(dest + 4 + i, src + (5 - i), 1);
160
161 for (i = 0; i <= 1; i++)
162 memcpy(dest + 6 + i, src + (7 - i), 1);
163
164 memcpy(dest + 8, src + 8, 8);
165}
166
167/**
168 * wmi_parse_guid - Convert GUID from ASCII to binary
169 * @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
170 * @dest: Memory block to hold binary GUID (16 bytes)
171 *
172 * N.B. The GUID need not be NULL terminated.
173 *
174 * Return: 'true' @dest contains binary GUID
175 * 'false' @dest contents are undefined
176 */
177static bool wmi_parse_guid(const u8 *src, u8 *dest)
178{
179 static const int size[] = { 4, 2, 2, 2, 6 };
180 int i, j, v;
181
182 if (src[8] != '-' || src[13] != '-' ||
183 src[18] != '-' || src[23] != '-')
184 return false;
185
186 for (j = 0; j < 5; j++, src++) {
187 for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
188 v = wmi_parse_hexbyte(src);
189 if (v < 0)
190 return false;
191 }
192 }
193
194 return true;
195}
196
197static bool find_guid(const char *guid_string, struct wmi_block **out)
198{
199 char tmp[16], guid_input[16];
200 struct wmi_block *wblock;
201 struct guid_block *block;
202 struct list_head *p;
203
204 wmi_parse_guid(guid_string, tmp);
205 wmi_swap_bytes(tmp, guid_input);
206
207 list_for_each(p, &wmi_blocks.list) {
208 wblock = list_entry(p, struct wmi_block, list);
209 block = &wblock->gblock;
210
211 if (memcmp(block->guid, guid_input, 16) == 0) {
212 if (out)
213 *out = wblock;
214 return 1;
215 }
216 }
217 return 0;
218}
219
220/*
221 * Exported WMI functions
222 */
223/**
224 * wmi_evaluate_method - Evaluate a WMI method
225 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
226 * @instance: Instance index
227 * @method_id: Method ID to call
228 * &in: Buffer containing input for the method call
229 * &out: Empty buffer to return the method results
230 *
231 * Call an ACPI-WMI method
232 */
233acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
234u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
235{
236 struct guid_block *block = NULL;
237 struct wmi_block *wblock = NULL;
238 acpi_handle handle;
239 acpi_status status;
240 struct acpi_object_list input;
241 union acpi_object params[3];
242 char method[4] = "WM";
243
244 if (!find_guid(guid_string, &wblock))
245 return AE_BAD_ADDRESS;
246
247 block = &wblock->gblock;
248 handle = wblock->handle;
249
250 if (!block->flags & ACPI_WMI_METHOD)
251 return AE_BAD_DATA;
252
253 if (block->instance_count < instance)
254 return AE_BAD_PARAMETER;
255
256 input.count = 2;
257 input.pointer = params;
258 params[0].type = ACPI_TYPE_INTEGER;
259 params[0].integer.value = instance;
260 params[1].type = ACPI_TYPE_INTEGER;
261 params[1].integer.value = method_id;
262
263 if (in) {
264 input.count = 3;
265
266 if (block->flags & ACPI_WMI_STRING) {
267 params[2].type = ACPI_TYPE_STRING;
268 } else {
269 params[2].type = ACPI_TYPE_BUFFER;
270 }
271 params[2].buffer.length = in->length;
272 params[2].buffer.pointer = in->pointer;
273 }
274
275 strncat(method, block->object_id, 2);
276
277 status = acpi_evaluate_object(handle, method, &input, out);
278
279 return status;
280}
281EXPORT_SYMBOL_GPL(wmi_evaluate_method);
282
283/**
284 * wmi_query_block - Return contents of a WMI block
285 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
286 * @instance: Instance index
287 * &out: Empty buffer to return the contents of the data block to
288 *
289 * Return the contents of an ACPI-WMI data block to a buffer
290 */
291acpi_status wmi_query_block(const char *guid_string, u8 instance,
292struct acpi_buffer *out)
293{
294 struct guid_block *block = NULL;
295 struct wmi_block *wblock = NULL;
296 acpi_handle handle;
297 acpi_status status, wc_status = AE_ERROR;
298 struct acpi_object_list input, wc_input;
299 union acpi_object wc_params[1], wq_params[1];
300 char method[4];
301 char wc_method[4] = "WC";
302
303 if (!guid_string || !out)
304 return AE_BAD_PARAMETER;
305
306 if (!find_guid(guid_string, &wblock))
307 return AE_BAD_ADDRESS;
308
309 block = &wblock->gblock;
310 handle = wblock->handle;
311
312 if (block->instance_count < instance)
313 return AE_BAD_PARAMETER;
314
315 /* Check GUID is a data block */
316 if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
317 return AE_BAD_ADDRESS;
318
319 input.count = 1;
320 input.pointer = wq_params;
321 wq_params[0].type = ACPI_TYPE_INTEGER;
322 wq_params[0].integer.value = instance;
323
324 /*
325 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
326 * enable collection.
327 */
328 if (block->flags & ACPI_WMI_EXPENSIVE) {
329 wc_input.count = 1;
330 wc_input.pointer = wc_params;
331 wc_params[0].type = ACPI_TYPE_INTEGER;
332 wc_params[0].integer.value = 1;
333
334 strncat(wc_method, block->object_id, 2);
335
336 /*
337 * Some GUIDs break the specification by declaring themselves
338 * expensive, but have no corresponding WCxx method. So we
339 * should not fail if this happens.
340 */
341 wc_status = acpi_evaluate_object(handle, wc_method,
342 &wc_input, NULL);
343 }
344
345 strcpy(method, "WQ");
346 strncat(method, block->object_id, 2);
347
348 status = acpi_evaluate_object(handle, method, NULL, out);
349
350 /*
351 * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
352 * the WQxx method failed - we should disable collection anyway.
353 */
354 if ((block->flags & ACPI_WMI_EXPENSIVE) && wc_status) {
355 wc_params[0].integer.value = 0;
356 status = acpi_evaluate_object(handle,
357 wc_method, &wc_input, NULL);
358 }
359
360 return status;
361}
362EXPORT_SYMBOL_GPL(wmi_query_block);
363
364/**
365 * wmi_set_block - Write to a WMI block
366 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
367 * @instance: Instance index
368 * &in: Buffer containing new values for the data block
369 *
370 * Write the contents of the input buffer to an ACPI-WMI data block
371 */
372acpi_status wmi_set_block(const char *guid_string, u8 instance,
373const struct acpi_buffer *in)
374{
375 struct guid_block *block = NULL;
376 struct wmi_block *wblock = NULL;
377 acpi_handle handle;
378 struct acpi_object_list input;
379 union acpi_object params[2];
380 char method[4] = "WS";
381
382 if (!guid_string || !in)
383 return AE_BAD_DATA;
384
385 if (!find_guid(guid_string, &wblock))
386 return AE_BAD_ADDRESS;
387
388 block = &wblock->gblock;
389 handle = wblock->handle;
390
391 if (block->instance_count < instance)
392 return AE_BAD_PARAMETER;
393
394 /* Check GUID is a data block */
395 if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
396 return AE_BAD_ADDRESS;
397
398 input.count = 2;
399 input.pointer = params;
400 params[0].type = ACPI_TYPE_INTEGER;
401 params[0].integer.value = instance;
402
403 if (block->flags & ACPI_WMI_STRING) {
404 params[1].type = ACPI_TYPE_STRING;
405 } else {
406 params[1].type = ACPI_TYPE_BUFFER;
407 }
408 params[1].buffer.length = in->length;
409 params[1].buffer.pointer = in->pointer;
410
411 strncat(method, block->object_id, 2);
412
413 return acpi_evaluate_object(handle, method, &input, NULL);
414}
415EXPORT_SYMBOL_GPL(wmi_set_block);
416
417/**
418 * wmi_install_notify_handler - Register handler for WMI events
419 * @handler: Function to handle notifications
420 * @data: Data to be returned to handler when event is fired
421 *
422 * Register a handler for events sent to the ACPI-WMI mapper device.
423 */
424acpi_status wmi_install_notify_handler(const char *guid,
425wmi_notify_handler handler, void *data)
426{
427 struct wmi_block *block;
428
429 if (!guid || !handler)
430 return AE_BAD_PARAMETER;
431
432 find_guid(guid, &block);
433 if (!block)
434 return AE_NOT_EXIST;
435
436 if (block->handler)
437 return AE_ALREADY_ACQUIRED;
438
439 block->handler = handler;
440 block->handler_data = data;
441
442 return AE_OK;
443}
444EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
445
446/**
447 * wmi_uninstall_notify_handler - Unregister handler for WMI events
448 *
449 * Unregister handler for events sent to the ACPI-WMI mapper device.
450 */
451acpi_status wmi_remove_notify_handler(const char *guid)
452{
453 struct wmi_block *block;
454
455 if (!guid)
456 return AE_BAD_PARAMETER;
457
458 find_guid(guid, &block);
459 if (!block)
460 return AE_NOT_EXIST;
461
462 if (!block->handler)
463 return AE_NULL_ENTRY;
464
465 block->handler = NULL;
466 block->handler_data = NULL;
467
468 return AE_OK;
469}
470EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
471
472/**
473 * wmi_get_event_data - Get WMI data associated with an event
474 *
475 * @event - Event to find
476 * &out - Buffer to hold event data
477 *
478 * Returns extra data associated with an event in WMI.
479 */
480acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
481{
482 struct acpi_object_list input;
483 union acpi_object params[1];
484 struct guid_block *gblock;
485 struct wmi_block *wblock;
486 struct list_head *p;
487
488 input.count = 1;
489 input.pointer = params;
490 params[0].type = ACPI_TYPE_INTEGER;
491 params[0].integer.value = event;
492
493 list_for_each(p, &wmi_blocks.list) {
494 wblock = list_entry(p, struct wmi_block, list);
495 gblock = &wblock->gblock;
496
497 if ((gblock->flags & ACPI_WMI_EVENT) &&
498 (gblock->notify_id == event))
499 return acpi_evaluate_object(wblock->handle, "_WED",
500 &input, out);
501 }
502
503 return AE_NOT_FOUND;
504}
505EXPORT_SYMBOL_GPL(wmi_get_event_data);
506
507/**
508 * wmi_has_guid - Check if a GUID is available
509 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
510 *
511 * Check if a given GUID is defined by _WDG
512 */
513bool wmi_has_guid(const char *guid_string)
514{
515 return find_guid(guid_string, NULL);
516}
517EXPORT_SYMBOL_GPL(wmi_has_guid);
518
519/*
520 * Parse the _WDG method for the GUID data blocks
521 */
522static __init acpi_status parse_wdg(acpi_handle handle)
523{
524 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
525 union acpi_object *obj;
526 struct guid_block *gblock;
527 struct wmi_block *wblock;
528 acpi_status status;
529 u32 i, total;
530
531 status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
532
533 if (ACPI_FAILURE(status))
534 return status;
535
536 obj = (union acpi_object *) out.pointer;
537
538 if (obj->type != ACPI_TYPE_BUFFER)
539 return AE_ERROR;
540
541 total = obj->buffer.length / sizeof(struct guid_block);
542
543 gblock = kzalloc(obj->buffer.length, GFP_KERNEL);
544 if (!gblock)
545 return AE_NO_MEMORY;
546
547 memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
548
549 for (i = 0; i < total; i++) {
550 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
551 if (!wblock)
552 return AE_NO_MEMORY;
553
554 wblock->gblock = gblock[i];
555 wblock->handle = handle;
556 list_add_tail(&wblock->list, &wmi_blocks.list);
557 }
558
559 kfree(out.pointer);
560 kfree(gblock);
561
562 return status;
563}
564
565/*
566 * WMI can have EmbeddedControl access regions. In which case, we just want to
567 * hand these off to the EC driver.
568 */
569static acpi_status
570acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
571 u32 bits, acpi_integer * value,
572 void *handler_context, void *region_context)
573{
574 int result = 0, i = 0;
575 u8 temp = 0;
576
577 if ((address > 0xFF) || !value)
578 return AE_BAD_PARAMETER;
579
580 if (function != ACPI_READ && function != ACPI_WRITE)
581 return AE_BAD_PARAMETER;
582
583 if (bits != 8)
584 return AE_BAD_PARAMETER;
585
586 if (function == ACPI_READ) {
587 result = ec_read(address, &temp);
588 (*value) |= ((acpi_integer)temp) << i;
589 } else {
590 temp = 0xff & ((*value) >> i);
591 result = ec_write(address, temp);
592 }
593
594 switch (result) {
595 case -EINVAL:
596 return AE_BAD_PARAMETER;
597 break;
598 case -ENODEV:
599 return AE_NOT_FOUND;
600 break;
601 case -ETIME:
602 return AE_TIME;
603 break;
604 default:
605 return AE_OK;
606 }
607}
608
609static void acpi_wmi_notify(acpi_handle handle, u32 event, void *data)
610{
611 struct guid_block *block;
612 struct wmi_block *wblock;
613 struct list_head *p;
614 struct acpi_device *device = data;
615
616 list_for_each(p, &wmi_blocks.list) {
617 wblock = list_entry(p, struct wmi_block, list);
618 block = &wblock->gblock;
619
620 if ((block->flags & ACPI_WMI_EVENT) &&
621 (block->notify_id == event)) {
622 if (wblock->handler)
623 wblock->handler(event, wblock->handler_data);
624
625 acpi_bus_generate_netlink_event(
626 device->pnp.device_class, device->dev.bus_id,
627 event, 0);
628 break;
629 }
630 }
631}
632
633static int acpi_wmi_remove(struct acpi_device *device, int type)
634{
635 acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
636 acpi_wmi_notify);
637
638 acpi_remove_address_space_handler(device->handle,
639 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
640
641 return 0;
642}
643
644static int __init acpi_wmi_add(struct acpi_device *device)
645{
646 acpi_status status;
647 int result = 0;
648
649 status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
650 acpi_wmi_notify, device);
651 if (ACPI_FAILURE(status)) {
652 printk(KERN_ERR PREFIX "Error installing notify handler\n");
653 return -ENODEV;
654 }
655
656 status = acpi_install_address_space_handler(device->handle,
657 ACPI_ADR_SPACE_EC,
658 &acpi_wmi_ec_space_handler,
659 NULL, NULL);
660 if (ACPI_FAILURE(status))
661 return -ENODEV;
662
663 status = parse_wdg(device->handle);
664 if (ACPI_FAILURE(status)) {
665 printk(KERN_ERR PREFIX "Error installing EC region handler\n");
666 return -ENODEV;
667 }
668
669 return result;
670}
671
672static int __init acpi_wmi_init(void)
673{
674 acpi_status result;
675
676 if (acpi_disabled)
677 return -ENODEV;
678
679 INIT_LIST_HEAD(&wmi_blocks.list);
680
681 result = acpi_bus_register_driver(&acpi_wmi_driver);
682
683 if (result < 0) {
684 printk(KERN_INFO PREFIX "Error loading mapper\n");
685 } else {
686 printk(KERN_INFO PREFIX "Mapper loaded\n");
687 }
688
689 return result;
690}
691
692static void __exit acpi_wmi_exit(void)
693{
694 struct list_head *p, *tmp;
695 struct wmi_block *wblock;
696
697 acpi_bus_unregister_driver(&acpi_wmi_driver);
698
699 list_for_each_safe(p, tmp, &wmi_blocks.list) {
700 wblock = list_entry(p, struct wmi_block, list);
701
702 list_del(p);
703 kfree(wblock);
704 }
705
706 printk(KERN_INFO PREFIX "Mapper unloaded\n");
707}
708
709subsys_initcall(acpi_wmi_init);
710module_exit(acpi_wmi_exit);
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 3bed4127d4ad..7dbc4a83c45c 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -1,13 +1,13 @@
1 1
2config CPU_IDLE 2config CPU_IDLE
3 bool "CPU idle PM support" 3 bool "CPU idle PM support"
4 default ACPI
4 help 5 help
5 CPU idle is a generic framework for supporting software-controlled 6 CPU idle is a generic framework for supporting software-controlled
6 idle processor power management. It includes modular cross-platform 7 idle processor power management. It includes modular cross-platform
7 governors that can be swapped during runtime. 8 governors that can be swapped during runtime.
8 9
9 If you're using a mobile platform that supports CPU idle PM (e.g. 10 If you're using an ACPI-enabled platform, you should say Y here.
10 an ACPI-capable notebook), you should say Y here.
11 11
12config CPU_IDLE_GOV_LADDER 12config CPU_IDLE_GOV_LADDER
13 bool 13 bool
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 2a98d99cbd46..2c4b2d47973e 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -15,6 +15,7 @@
15#include <linux/pm_qos_params.h> 15#include <linux/pm_qos_params.h>
16#include <linux/cpu.h> 16#include <linux/cpu.h>
17#include <linux/cpuidle.h> 17#include <linux/cpuidle.h>
18#include <linux/ktime.h>
18 19
19#include "cpuidle.h" 20#include "cpuidle.h"
20 21
@@ -180,6 +181,44 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
180 181
181EXPORT_SYMBOL_GPL(cpuidle_disable_device); 182EXPORT_SYMBOL_GPL(cpuidle_disable_device);
182 183
184#ifdef CONFIG_ARCH_HAS_CPU_RELAX
185static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
186{
187 ktime_t t1, t2;
188 s64 diff;
189 int ret;
190
191 t1 = ktime_get();
192 local_irq_enable();
193 while (!need_resched())
194 cpu_relax();
195
196 t2 = ktime_get();
197 diff = ktime_to_us(ktime_sub(t2, t1));
198 if (diff > INT_MAX)
199 diff = INT_MAX;
200
201 ret = (int) diff;
202 return ret;
203}
204
205static void poll_idle_init(struct cpuidle_device *dev)
206{
207 struct cpuidle_state *state = &dev->states[0];
208
209 cpuidle_set_statedata(state, NULL);
210
211 snprintf(state->name, CPUIDLE_NAME_LEN, "C0 (poll idle)");
212 state->exit_latency = 0;
213 state->target_residency = 0;
214 state->power_usage = -1;
215 state->flags = CPUIDLE_FLAG_POLL | CPUIDLE_FLAG_TIME_VALID;
216 state->enter = poll_idle;
217}
218#else
219static void poll_idle_init(struct cpuidle_device *dev) {}
220#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
221
183/** 222/**
184 * cpuidle_register_device - registers a CPU's idle PM feature 223 * cpuidle_register_device - registers a CPU's idle PM feature
185 * @dev: the cpu 224 * @dev: the cpu
@@ -198,6 +237,8 @@ int cpuidle_register_device(struct cpuidle_device *dev)
198 237
199 mutex_lock(&cpuidle_lock); 238 mutex_lock(&cpuidle_lock);
200 239
240 poll_idle_init(dev);
241
201 per_cpu(cpuidle_devices, dev->cpu) = dev; 242 per_cpu(cpuidle_devices, dev->cpu) = dev;
202 list_add(&dev->device_list, &cpuidle_detected_devices); 243 list_add(&dev->device_list, &cpuidle_detected_devices);
203 if ((ret = cpuidle_add_sysfs(sys_dev))) { 244 if ((ret = cpuidle_add_sysfs(sys_dev))) {
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 9008ed5ef4ce..e0bade732376 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -489,12 +489,3 @@ int dmi_get_year(int field)
489 489
490 return year; 490 return year;
491} 491}
492
493/**
494 * dmi_get_slot - return dmi_ident[slot]
495 * @slot: index into dmi_ident[]
496 */
497char *dmi_get_slot(int slot)
498{
499 return(dmi_ident[slot]);
500}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b5e67c0ff433..78cd33861766 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -92,6 +92,22 @@ config TIFM_7XX1
92 To compile this driver as a module, choose M here: the module will 92 To compile this driver as a module, choose M here: the module will
93 be called tifm_7xx1. 93 be called tifm_7xx1.
94 94
95config ACER_WMI
96 tristate "Acer WMI Laptop Extras (EXPERIMENTAL)"
97 depends on X86
98 depends on EXPERIMENTAL
99 depends on ACPI
100 depends on ACPI_WMI
101 depends on LEDS_CLASS
102 depends on BACKLIGHT_CLASS_DEVICE
103 ---help---
104 This is a driver for newer Acer (and Wistron) laptops. It adds
105 wireless radio and bluetooth control, and on some laptops,
106 exposes the mail LED and LCD backlight.
107
108 If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
109 here.
110
95config ASUS_LAPTOP 111config ASUS_LAPTOP
96 tristate "Asus Laptop Extras (EXPERIMENTAL)" 112 tristate "Asus Laptop Extras (EXPERIMENTAL)"
97 depends on X86 113 depends on X86
@@ -126,6 +142,15 @@ config FUJITSU_LAPTOP
126 142
127 If you have a Fujitsu laptop, say Y or M here. 143 If you have a Fujitsu laptop, say Y or M here.
128 144
145config TC1100_WMI
146 tristate "HP Compaq TC1100 Tablet WMI Extras"
147 depends on X86 && !X86_64
148 depends on ACPI
149 depends on ACPI_WMI
150 ---help---
151 This is a driver for the WMI extensions (wireless and bluetooth power
152 control) of the HP Compaq TC1100 tablet.
153
129config MSI_LAPTOP 154config MSI_LAPTOP
130 tristate "MSI Laptop Extras" 155 tristate "MSI Laptop Extras"
131 depends on X86 156 depends on X86
@@ -219,6 +244,25 @@ config THINKPAD_ACPI_BAY
219 244
220 If you are not sure, say Y here. 245 If you are not sure, say Y here.
221 246
247config THINKPAD_ACPI_HOTKEY_POLL
248 bool "Suport NVRAM polling for hot keys"
249 depends on THINKPAD_ACPI
250 default y
251 ---help---
252 Some thinkpad models benefit from NVRAM polling to detect a few of
253 the hot key press events. If you know your ThinkPad model does not
254 need to do NVRAM polling to support any of the hot keys you use,
255 unselecting this option will save about 1kB of memory.
256
257 ThinkPads T40 and newer, R52 and newer, and X31 and newer are
258 unlikely to need NVRAM polling in their latest BIOS versions.
259
260 NVRAM polling can detect at most the following keys: ThinkPad/Access
261 IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute,
262 Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12).
263
264 If you are not sure, say Y here. The driver enables polling only if
265 it is strictly necessary to do so.
222 266
223config ATMEL_SSC 267config ATMEL_SSC
224 tristate "Device driver for Atmel SSC peripheral" 268 tristate "Device driver for Atmel SSC peripheral"
@@ -232,4 +276,13 @@ config ATMEL_SSC
232 276
233 If unsure, say N. 277 If unsure, say N.
234 278
279config INTEL_MENLOW
280 tristate "Thermal Management driver for Intel menlow platform"
281 depends on ACPI_THERMAL
282 ---help---
283 ACPI thermal management enhancement driver on
284 Intel Menlow platform.
285
286 If unsure, say N.
287
235endif # MISC_DEVICES 288endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 87f2685d728f..1f41654aae4d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,8 +6,10 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
6obj-$(CONFIG_IBM_ASM) += ibmasm/ 6obj-$(CONFIG_IBM_ASM) += ibmasm/
7obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ 7obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o 8obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
9obj-$(CONFIG_ACER_WMI) += acer-wmi.o
9obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 10obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
10obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o 11obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
12obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
11obj-$(CONFIG_LKDTM) += lkdtm.o 13obj-$(CONFIG_LKDTM) += lkdtm.o
12obj-$(CONFIG_TIFM_CORE) += tifm_core.o 14obj-$(CONFIG_TIFM_CORE) += tifm_core.o
13obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o 15obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
@@ -17,3 +19,4 @@ obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
17obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o 19obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
18obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o 20obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
19obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o 21obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
22obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
new file mode 100644
index 000000000000..a4d677504250
--- /dev/null
+++ b/drivers/misc/acer-wmi.c
@@ -0,0 +1,1109 @@
1/*
2 * Acer WMI Laptop Extras
3 *
4 * Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
5 *
6 * Based on acer_acpi:
7 * Copyright (C) 2005-2007 E.M. Smith
8 * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25#define ACER_WMI_VERSION "0.1"
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/types.h>
31#include <linux/dmi.h>
32#include <linux/backlight.h>
33#include <linux/leds.h>
34#include <linux/platform_device.h>
35#include <linux/acpi.h>
36#include <linux/i8042.h>
37
38#include <acpi/acpi_drivers.h>
39
40MODULE_AUTHOR("Carlos Corbacho");
41MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
42MODULE_LICENSE("GPL");
43
44#define ACER_LOGPREFIX "acer-wmi: "
45#define ACER_ERR KERN_ERR ACER_LOGPREFIX
46#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
47#define ACER_INFO KERN_INFO ACER_LOGPREFIX
48
49/*
50 * The following defines quirks to get some specific functions to work
51 * which are known to not be supported over ACPI-WMI (such as the mail LED
52 * on WMID based Acer's)
53 */
54struct acer_quirks {
55 const char *vendor;
56 const char *model;
57 u16 quirks;
58};
59
60/*
61 * Magic Number
62 * Meaning is unknown - this number is required for writing to ACPI for AMW0
63 * (it's also used in acerhk when directly accessing the BIOS)
64 */
65#define ACER_AMW0_WRITE 0x9610
66
67/*
68 * Bit masks for the AMW0 interface
69 */
70#define ACER_AMW0_WIRELESS_MASK 0x35
71#define ACER_AMW0_BLUETOOTH_MASK 0x34
72#define ACER_AMW0_MAILLED_MASK 0x31
73
74/*
75 * Method IDs for WMID interface
76 */
77#define ACER_WMID_GET_WIRELESS_METHODID 1
78#define ACER_WMID_GET_BLUETOOTH_METHODID 2
79#define ACER_WMID_GET_BRIGHTNESS_METHODID 3
80#define ACER_WMID_SET_WIRELESS_METHODID 4
81#define ACER_WMID_SET_BLUETOOTH_METHODID 5
82#define ACER_WMID_SET_BRIGHTNESS_METHODID 6
83#define ACER_WMID_GET_THREEG_METHODID 10
84#define ACER_WMID_SET_THREEG_METHODID 11
85
86/*
87 * Acer ACPI method GUIDs
88 */
89#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
90#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
91#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
92
93MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
94MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
95
96/* Temporary workaround until the WMI sysfs interface goes in */
97MODULE_ALIAS("dmi:*:*Acer*:*:");
98
99/*
100 * Interface capability flags
101 */
102#define ACER_CAP_MAILLED (1<<0)
103#define ACER_CAP_WIRELESS (1<<1)
104#define ACER_CAP_BLUETOOTH (1<<2)
105#define ACER_CAP_BRIGHTNESS (1<<3)
106#define ACER_CAP_THREEG (1<<4)
107#define ACER_CAP_ANY (0xFFFFFFFF)
108
109/*
110 * Interface type flags
111 */
112enum interface_flags {
113 ACER_AMW0,
114 ACER_AMW0_V2,
115 ACER_WMID,
116};
117
118#define ACER_DEFAULT_WIRELESS 0
119#define ACER_DEFAULT_BLUETOOTH 0
120#define ACER_DEFAULT_MAILLED 0
121#define ACER_DEFAULT_THREEG 0
122
123static int max_brightness = 0xF;
124
125static int wireless = -1;
126static int bluetooth = -1;
127static int mailled = -1;
128static int brightness = -1;
129static int threeg = -1;
130static int force_series;
131
132module_param(mailled, int, 0444);
133module_param(wireless, int, 0444);
134module_param(bluetooth, int, 0444);
135module_param(brightness, int, 0444);
136module_param(threeg, int, 0444);
137module_param(force_series, int, 0444);
138MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
139MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
140MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
141MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
142MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
143MODULE_PARM_DESC(force_series, "Force a different laptop series");
144
145struct acer_data {
146 int mailled;
147 int wireless;
148 int bluetooth;
149 int threeg;
150 int brightness;
151};
152
153/* Each low-level interface must define at least some of the following */
154struct wmi_interface {
155 /* The WMI device type */
156 u32 type;
157
158 /* The capabilities this interface provides */
159 u32 capability;
160
161 /* Private data for the current interface */
162 struct acer_data data;
163};
164
165/* The static interface pointer, points to the currently detected interface */
166static struct wmi_interface *interface;
167
168/*
169 * Embedded Controller quirks
170 * Some laptops require us to directly access the EC to either enable or query
171 * features that are not available through WMI.
172 */
173
174struct quirk_entry {
175 u8 wireless;
176 u8 mailled;
177 u8 brightness;
178 u8 bluetooth;
179};
180
181static struct quirk_entry *quirks;
182
183static void set_quirks(void)
184{
185 if (quirks->mailled)
186 interface->capability |= ACER_CAP_MAILLED;
187
188 if (quirks->brightness)
189 interface->capability |= ACER_CAP_BRIGHTNESS;
190}
191
192static int dmi_matched(const struct dmi_system_id *dmi)
193{
194 quirks = dmi->driver_data;
195 return 0;
196}
197
198static struct quirk_entry quirk_unknown = {
199};
200
201static struct quirk_entry quirk_acer_travelmate_2490 = {
202 .mailled = 1,
203};
204
205/* This AMW0 laptop has no bluetooth */
206static struct quirk_entry quirk_medion_md_98300 = {
207 .wireless = 1,
208};
209
210static struct dmi_system_id acer_quirks[] = {
211 {
212 .callback = dmi_matched,
213 .ident = "Acer Aspire 3100",
214 .matches = {
215 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
216 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
217 },
218 .driver_data = &quirk_acer_travelmate_2490,
219 },
220 {
221 .callback = dmi_matched,
222 .ident = "Acer Aspire 5100",
223 .matches = {
224 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
225 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
226 },
227 .driver_data = &quirk_acer_travelmate_2490,
228 },
229 {
230 .callback = dmi_matched,
231 .ident = "Acer Aspire 5630",
232 .matches = {
233 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
234 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
235 },
236 .driver_data = &quirk_acer_travelmate_2490,
237 },
238 {
239 .callback = dmi_matched,
240 .ident = "Acer Aspire 5650",
241 .matches = {
242 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
243 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
244 },
245 .driver_data = &quirk_acer_travelmate_2490,
246 },
247 {
248 .callback = dmi_matched,
249 .ident = "Acer Aspire 5680",
250 .matches = {
251 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
252 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
253 },
254 .driver_data = &quirk_acer_travelmate_2490,
255 },
256 {
257 .callback = dmi_matched,
258 .ident = "Acer Aspire 9110",
259 .matches = {
260 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
261 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
262 },
263 .driver_data = &quirk_acer_travelmate_2490,
264 },
265 {
266 .callback = dmi_matched,
267 .ident = "Acer TravelMate 2490",
268 .matches = {
269 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
270 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
271 },
272 .driver_data = &quirk_acer_travelmate_2490,
273 },
274 {
275 .callback = dmi_matched,
276 .ident = "Medion MD 98300",
277 .matches = {
278 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
279 DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
280 },
281 .driver_data = &quirk_medion_md_98300,
282 },
283 {}
284};
285
286/* Find which quirks are needed for a particular vendor/ model pair */
287static void find_quirks(void)
288{
289 if (!force_series) {
290 dmi_check_system(acer_quirks);
291 } else if (force_series == 2490) {
292 quirks = &quirk_acer_travelmate_2490;
293 }
294
295 if (quirks == NULL)
296 quirks = &quirk_unknown;
297
298 set_quirks();
299}
300
301/*
302 * General interface convenience methods
303 */
304
305static bool has_cap(u32 cap)
306{
307 if ((interface->capability & cap) != 0)
308 return 1;
309
310 return 0;
311}
312
313/*
314 * AMW0 (V1) interface
315 */
316struct wmab_args {
317 u32 eax;
318 u32 ebx;
319 u32 ecx;
320 u32 edx;
321};
322
323struct wmab_ret {
324 u32 eax;
325 u32 ebx;
326 u32 ecx;
327 u32 edx;
328 u32 eex;
329};
330
331static acpi_status wmab_execute(struct wmab_args *regbuf,
332struct acpi_buffer *result)
333{
334 struct acpi_buffer input;
335 acpi_status status;
336 input.length = sizeof(struct wmab_args);
337 input.pointer = (u8 *)regbuf;
338
339 status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
340
341 return status;
342}
343
344static acpi_status AMW0_get_u32(u32 *value, u32 cap,
345struct wmi_interface *iface)
346{
347 int err;
348 u8 result;
349
350 switch (cap) {
351 case ACER_CAP_MAILLED:
352 switch (quirks->mailled) {
353 default:
354 err = ec_read(0xA, &result);
355 if (err)
356 return AE_ERROR;
357 *value = (result >> 7) & 0x1;
358 return AE_OK;
359 }
360 break;
361 case ACER_CAP_WIRELESS:
362 switch (quirks->wireless) {
363 case 1:
364 err = ec_read(0x7B, &result);
365 if (err)
366 return AE_ERROR;
367 *value = result & 0x1;
368 return AE_OK;
369 default:
370 err = ec_read(0xA, &result);
371 if (err)
372 return AE_ERROR;
373 *value = (result >> 2) & 0x1;
374 return AE_OK;
375 }
376 break;
377 case ACER_CAP_BLUETOOTH:
378 switch (quirks->bluetooth) {
379 default:
380 err = ec_read(0xA, &result);
381 if (err)
382 return AE_ERROR;
383 *value = (result >> 4) & 0x1;
384 return AE_OK;
385 }
386 break;
387 case ACER_CAP_BRIGHTNESS:
388 switch (quirks->brightness) {
389 default:
390 err = ec_read(0x83, &result);
391 if (err)
392 return AE_ERROR;
393 *value = result;
394 return AE_OK;
395 }
396 break;
397 default:
398 return AE_BAD_ADDRESS;
399 }
400 return AE_OK;
401}
402
403static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
404{
405 struct wmab_args args;
406
407 args.eax = ACER_AMW0_WRITE;
408 args.ebx = value ? (1<<8) : 0;
409 args.ecx = args.edx = 0;
410
411 switch (cap) {
412 case ACER_CAP_MAILLED:
413 if (value > 1)
414 return AE_BAD_PARAMETER;
415 args.ebx |= ACER_AMW0_MAILLED_MASK;
416 break;
417 case ACER_CAP_WIRELESS:
418 if (value > 1)
419 return AE_BAD_PARAMETER;
420 args.ebx |= ACER_AMW0_WIRELESS_MASK;
421 break;
422 case ACER_CAP_BLUETOOTH:
423 if (value > 1)
424 return AE_BAD_PARAMETER;
425 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
426 break;
427 case ACER_CAP_BRIGHTNESS:
428 if (value > max_brightness)
429 return AE_BAD_PARAMETER;
430 switch (quirks->brightness) {
431 case 1:
432 return ec_write(0x83, value);
433 default:
434 return AE_BAD_ADDRESS;
435 break;
436 }
437 default:
438 return AE_BAD_ADDRESS;
439 }
440
441 /* Actually do the set */
442 return wmab_execute(&args, NULL);
443}
444
445static acpi_status AMW0_find_mailled(void)
446{
447 struct wmab_args args;
448 struct wmab_ret ret;
449 acpi_status status = AE_OK;
450 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
451 union acpi_object *obj;
452
453 args.eax = 0x86;
454 args.ebx = args.ecx = args.edx = 0;
455
456 status = wmab_execute(&args, &out);
457 if (ACPI_FAILURE(status))
458 return status;
459
460 obj = (union acpi_object *) out.pointer;
461 if (obj && obj->type == ACPI_TYPE_BUFFER &&
462 obj->buffer.length == sizeof(struct wmab_ret)) {
463 ret = *((struct wmab_ret *) obj->buffer.pointer);
464 } else {
465 return AE_ERROR;
466 }
467
468 if (ret.eex & 0x1)
469 interface->capability |= ACER_CAP_MAILLED;
470
471 kfree(out.pointer);
472
473 return AE_OK;
474}
475
476static acpi_status AMW0_set_capabilities(void)
477{
478 struct wmab_args args;
479 struct wmab_ret ret;
480 acpi_status status = AE_OK;
481 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
482 union acpi_object *obj;
483
484 args.eax = ACER_AMW0_WRITE;
485 args.ecx = args.edx = 0;
486
487 args.ebx = 0xa2 << 8;
488 args.ebx |= ACER_AMW0_WIRELESS_MASK;
489
490 status = wmab_execute(&args, &out);
491 if (ACPI_FAILURE(status))
492 return status;
493
494 obj = (union acpi_object *) out.pointer;
495 if (obj && obj->type == ACPI_TYPE_BUFFER &&
496 obj->buffer.length == sizeof(struct wmab_ret)) {
497 ret = *((struct wmab_ret *) obj->buffer.pointer);
498 } else {
499 return AE_ERROR;
500 }
501
502 if (ret.eax & 0x1)
503 interface->capability |= ACER_CAP_WIRELESS;
504
505 args.ebx = 2 << 8;
506 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
507
508 status = wmab_execute(&args, &out);
509 if (ACPI_FAILURE(status))
510 return status;
511
512 obj = (union acpi_object *) out.pointer;
513 if (obj && obj->type == ACPI_TYPE_BUFFER
514 && obj->buffer.length == sizeof(struct wmab_ret)) {
515 ret = *((struct wmab_ret *) obj->buffer.pointer);
516 } else {
517 return AE_ERROR;
518 }
519
520 if (ret.eax & 0x1)
521 interface->capability |= ACER_CAP_BLUETOOTH;
522
523 kfree(out.pointer);
524
525 /*
526 * This appears to be safe to enable, since all Wistron based laptops
527 * appear to use the same EC register for brightness, even if they
528 * differ for wireless, etc
529 */
530 interface->capability |= ACER_CAP_BRIGHTNESS;
531
532 return AE_OK;
533}
534
535static struct wmi_interface AMW0_interface = {
536 .type = ACER_AMW0,
537};
538
539static struct wmi_interface AMW0_V2_interface = {
540 .type = ACER_AMW0_V2,
541};
542
543/*
544 * New interface (The WMID interface)
545 */
546static acpi_status
547WMI_execute_u32(u32 method_id, u32 in, u32 *out)
548{
549 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
550 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
551 union acpi_object *obj;
552 u32 tmp;
553 acpi_status status;
554
555 status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
556
557 if (ACPI_FAILURE(status))
558 return status;
559
560 obj = (union acpi_object *) result.pointer;
561 if (obj && obj->type == ACPI_TYPE_BUFFER &&
562 obj->buffer.length == sizeof(u32)) {
563 tmp = *((u32 *) obj->buffer.pointer);
564 } else {
565 tmp = 0;
566 }
567
568 if (out)
569 *out = tmp;
570
571 kfree(result.pointer);
572
573 return status;
574}
575
576static acpi_status WMID_get_u32(u32 *value, u32 cap,
577struct wmi_interface *iface)
578{
579 acpi_status status;
580 u8 tmp;
581 u32 result, method_id = 0;
582
583 switch (cap) {
584 case ACER_CAP_WIRELESS:
585 method_id = ACER_WMID_GET_WIRELESS_METHODID;
586 break;
587 case ACER_CAP_BLUETOOTH:
588 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
589 break;
590 case ACER_CAP_BRIGHTNESS:
591 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
592 break;
593 case ACER_CAP_THREEG:
594 method_id = ACER_WMID_GET_THREEG_METHODID;
595 break;
596 case ACER_CAP_MAILLED:
597 if (quirks->mailled == 1) {
598 ec_read(0x9f, &tmp);
599 *value = tmp & 0x1;
600 return 0;
601 }
602 default:
603 return AE_BAD_ADDRESS;
604 }
605 status = WMI_execute_u32(method_id, 0, &result);
606
607 if (ACPI_SUCCESS(status))
608 *value = (u8)result;
609
610 return status;
611}
612
613static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
614{
615 u32 method_id = 0;
616 char param;
617
618 switch (cap) {
619 case ACER_CAP_BRIGHTNESS:
620 if (value > max_brightness)
621 return AE_BAD_PARAMETER;
622 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
623 break;
624 case ACER_CAP_WIRELESS:
625 if (value > 1)
626 return AE_BAD_PARAMETER;
627 method_id = ACER_WMID_SET_WIRELESS_METHODID;
628 break;
629 case ACER_CAP_BLUETOOTH:
630 if (value > 1)
631 return AE_BAD_PARAMETER;
632 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
633 break;
634 case ACER_CAP_THREEG:
635 if (value > 1)
636 return AE_BAD_PARAMETER;
637 method_id = ACER_WMID_SET_THREEG_METHODID;
638 break;
639 case ACER_CAP_MAILLED:
640 if (value > 1)
641 return AE_BAD_PARAMETER;
642 if (quirks->mailled == 1) {
643 param = value ? 0x92 : 0x93;
644 i8042_command(&param, 0x1059);
645 return 0;
646 }
647 break;
648 default:
649 return AE_BAD_ADDRESS;
650 }
651 return WMI_execute_u32(method_id, (u32)value, NULL);
652}
653
654static acpi_status WMID_set_capabilities(void)
655{
656 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
657 union acpi_object *obj;
658 acpi_status status;
659 u32 devices;
660
661 status = wmi_query_block(WMID_GUID2, 1, &out);
662 if (ACPI_FAILURE(status))
663 return status;
664
665 obj = (union acpi_object *) out.pointer;
666 if (obj && obj->type == ACPI_TYPE_BUFFER &&
667 obj->buffer.length == sizeof(u32)) {
668 devices = *((u32 *) obj->buffer.pointer);
669 } else {
670 return AE_ERROR;
671 }
672
673 /* Not sure on the meaning of the relevant bits yet to detect these */
674 interface->capability |= ACER_CAP_WIRELESS;
675 interface->capability |= ACER_CAP_THREEG;
676
677 /* WMID always provides brightness methods */
678 interface->capability |= ACER_CAP_BRIGHTNESS;
679
680 if (devices & 0x10)
681 interface->capability |= ACER_CAP_BLUETOOTH;
682
683 if (!(devices & 0x20))
684 max_brightness = 0x9;
685
686 return status;
687}
688
689static struct wmi_interface wmid_interface = {
690 .type = ACER_WMID,
691};
692
693/*
694 * Generic Device (interface-independent)
695 */
696
697static acpi_status get_u32(u32 *value, u32 cap)
698{
699 acpi_status status = AE_BAD_ADDRESS;
700
701 switch (interface->type) {
702 case ACER_AMW0:
703 status = AMW0_get_u32(value, cap, interface);
704 break;
705 case ACER_AMW0_V2:
706 if (cap == ACER_CAP_MAILLED) {
707 status = AMW0_get_u32(value, cap, interface);
708 break;
709 }
710 case ACER_WMID:
711 status = WMID_get_u32(value, cap, interface);
712 break;
713 }
714
715 return status;
716}
717
718static acpi_status set_u32(u32 value, u32 cap)
719{
720 if (interface->capability & cap) {
721 switch (interface->type) {
722 case ACER_AMW0:
723 return AMW0_set_u32(value, cap, interface);
724 case ACER_AMW0_V2:
725 case ACER_WMID:
726 return WMID_set_u32(value, cap, interface);
727 default:
728 return AE_BAD_PARAMETER;
729 }
730 }
731 return AE_BAD_PARAMETER;
732}
733
734static void __init acer_commandline_init(void)
735{
736 /*
737 * These will all fail silently if the value given is invalid, or the
738 * capability isn't available on the given interface
739 */
740 set_u32(mailled, ACER_CAP_MAILLED);
741 set_u32(wireless, ACER_CAP_WIRELESS);
742 set_u32(bluetooth, ACER_CAP_BLUETOOTH);
743 set_u32(threeg, ACER_CAP_THREEG);
744 set_u32(brightness, ACER_CAP_BRIGHTNESS);
745}
746
747/*
748 * LED device (Mail LED only, no other LEDs known yet)
749 */
750static void mail_led_set(struct led_classdev *led_cdev,
751enum led_brightness value)
752{
753 set_u32(value, ACER_CAP_MAILLED);
754}
755
756static struct led_classdev mail_led = {
757 .name = "acer-mail:green",
758 .brightness_set = mail_led_set,
759};
760
761static int __init acer_led_init(struct device *dev)
762{
763 return led_classdev_register(dev, &mail_led);
764}
765
766static void acer_led_exit(void)
767{
768 led_classdev_unregister(&mail_led);
769}
770
771/*
772 * Backlight device
773 */
774static struct backlight_device *acer_backlight_device;
775
776static int read_brightness(struct backlight_device *bd)
777{
778 u32 value;
779 get_u32(&value, ACER_CAP_BRIGHTNESS);
780 return value;
781}
782
783static int update_bl_status(struct backlight_device *bd)
784{
785 set_u32(bd->props.brightness, ACER_CAP_BRIGHTNESS);
786 return 0;
787}
788
789static struct backlight_ops acer_bl_ops = {
790 .get_brightness = read_brightness,
791 .update_status = update_bl_status,
792};
793
794static int __init acer_backlight_init(struct device *dev)
795{
796 struct backlight_device *bd;
797
798 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops);
799 if (IS_ERR(bd)) {
800 printk(ACER_ERR "Could not register Acer backlight device\n");
801 acer_backlight_device = NULL;
802 return PTR_ERR(bd);
803 }
804
805 acer_backlight_device = bd;
806
807 bd->props.max_brightness = max_brightness;
808 bd->props.brightness = read_brightness(NULL);
809 backlight_update_status(bd);
810 return 0;
811}
812
813static void __exit acer_backlight_exit(void)
814{
815 backlight_device_unregister(acer_backlight_device);
816}
817
818/*
819 * Read/ write bool sysfs macro
820 */
821#define show_set_bool(value, cap) \
822static ssize_t \
823show_bool_##value(struct device *dev, struct device_attribute *attr, \
824 char *buf) \
825{ \
826 u32 result; \
827 acpi_status status = get_u32(&result, cap); \
828 if (ACPI_SUCCESS(status)) \
829 return sprintf(buf, "%u\n", result); \
830 return sprintf(buf, "Read error\n"); \
831} \
832\
833static ssize_t \
834set_bool_##value(struct device *dev, struct device_attribute *attr, \
835 const char *buf, size_t count) \
836{ \
837 u32 tmp = simple_strtoul(buf, NULL, 10); \
838 acpi_status status = set_u32(tmp, cap); \
839 if (ACPI_FAILURE(status)) \
840 return -EINVAL; \
841 return count; \
842} \
843static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
844 show_bool_##value, set_bool_##value);
845
846show_set_bool(wireless, ACER_CAP_WIRELESS);
847show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
848show_set_bool(threeg, ACER_CAP_THREEG);
849
850/*
851 * Read interface sysfs macro
852 */
853static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
854 char *buf)
855{
856 switch (interface->type) {
857 case ACER_AMW0:
858 return sprintf(buf, "AMW0\n");
859 case ACER_AMW0_V2:
860 return sprintf(buf, "AMW0 v2\n");
861 case ACER_WMID:
862 return sprintf(buf, "WMID\n");
863 default:
864 return sprintf(buf, "Error!\n");
865 }
866}
867
868static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR,
869 show_interface, NULL);
870
871/*
872 * Platform device
873 */
874static int __devinit acer_platform_probe(struct platform_device *device)
875{
876 int err;
877
878 if (has_cap(ACER_CAP_MAILLED)) {
879 err = acer_led_init(&device->dev);
880 if (err)
881 goto error_mailled;
882 }
883
884 if (has_cap(ACER_CAP_BRIGHTNESS)) {
885 err = acer_backlight_init(&device->dev);
886 if (err)
887 goto error_brightness;
888 }
889
890 return 0;
891
892error_brightness:
893 acer_led_exit();
894error_mailled:
895 return err;
896}
897
898static int acer_platform_remove(struct platform_device *device)
899{
900 if (has_cap(ACER_CAP_MAILLED))
901 acer_led_exit();
902 if (has_cap(ACER_CAP_BRIGHTNESS))
903 acer_backlight_exit();
904 return 0;
905}
906
907static int acer_platform_suspend(struct platform_device *dev,
908pm_message_t state)
909{
910 u32 value;
911 struct acer_data *data = &interface->data;
912
913 if (!data)
914 return -ENOMEM;
915
916 if (has_cap(ACER_CAP_WIRELESS)) {
917 get_u32(&value, ACER_CAP_WIRELESS);
918 data->wireless = value;
919 }
920
921 if (has_cap(ACER_CAP_BLUETOOTH)) {
922 get_u32(&value, ACER_CAP_BLUETOOTH);
923 data->bluetooth = value;
924 }
925
926 if (has_cap(ACER_CAP_MAILLED)) {
927 get_u32(&value, ACER_CAP_MAILLED);
928 data->mailled = value;
929 }
930
931 if (has_cap(ACER_CAP_BRIGHTNESS)) {
932 get_u32(&value, ACER_CAP_BRIGHTNESS);
933 data->brightness = value;
934 }
935
936 return 0;
937}
938
939static int acer_platform_resume(struct platform_device *device)
940{
941 struct acer_data *data = &interface->data;
942
943 if (!data)
944 return -ENOMEM;
945
946 if (has_cap(ACER_CAP_WIRELESS))
947 set_u32(data->wireless, ACER_CAP_WIRELESS);
948
949 if (has_cap(ACER_CAP_BLUETOOTH))
950 set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
951
952 if (has_cap(ACER_CAP_THREEG))
953 set_u32(data->threeg, ACER_CAP_THREEG);
954
955 if (has_cap(ACER_CAP_MAILLED))
956 set_u32(data->mailled, ACER_CAP_MAILLED);
957
958 if (has_cap(ACER_CAP_BRIGHTNESS))
959 set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
960
961 return 0;
962}
963
964static struct platform_driver acer_platform_driver = {
965 .driver = {
966 .name = "acer-wmi",
967 .owner = THIS_MODULE,
968 },
969 .probe = acer_platform_probe,
970 .remove = acer_platform_remove,
971 .suspend = acer_platform_suspend,
972 .resume = acer_platform_resume,
973};
974
975static struct platform_device *acer_platform_device;
976
977static int remove_sysfs(struct platform_device *device)
978{
979 if (has_cap(ACER_CAP_WIRELESS))
980 device_remove_file(&device->dev, &dev_attr_wireless);
981
982 if (has_cap(ACER_CAP_BLUETOOTH))
983 device_remove_file(&device->dev, &dev_attr_bluetooth);
984
985 if (has_cap(ACER_CAP_THREEG))
986 device_remove_file(&device->dev, &dev_attr_threeg);
987
988 device_remove_file(&device->dev, &dev_attr_interface);
989
990 return 0;
991}
992
993static int create_sysfs(void)
994{
995 int retval = -ENOMEM;
996
997 if (has_cap(ACER_CAP_WIRELESS)) {
998 retval = device_create_file(&acer_platform_device->dev,
999 &dev_attr_wireless);
1000 if (retval)
1001 goto error_sysfs;
1002 }
1003
1004 if (has_cap(ACER_CAP_BLUETOOTH)) {
1005 retval = device_create_file(&acer_platform_device->dev,
1006 &dev_attr_bluetooth);
1007 if (retval)
1008 goto error_sysfs;
1009 }
1010
1011 if (has_cap(ACER_CAP_THREEG)) {
1012 retval = device_create_file(&acer_platform_device->dev,
1013 &dev_attr_threeg);
1014 if (retval)
1015 goto error_sysfs;
1016 }
1017
1018 retval = device_create_file(&acer_platform_device->dev,
1019 &dev_attr_interface);
1020 if (retval)
1021 goto error_sysfs;
1022
1023 return 0;
1024
1025error_sysfs:
1026 remove_sysfs(acer_platform_device);
1027 return retval;
1028}
1029
1030static int __init acer_wmi_init(void)
1031{
1032 int err;
1033
1034 printk(ACER_INFO "Acer Laptop ACPI-WMI Extras version %s\n",
1035 ACER_WMI_VERSION);
1036
1037 /*
1038 * Detect which ACPI-WMI interface we're using.
1039 */
1040 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
1041 interface = &AMW0_V2_interface;
1042
1043 if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
1044 interface = &wmid_interface;
1045
1046 if (wmi_has_guid(WMID_GUID2) && interface) {
1047 if (ACPI_FAILURE(WMID_set_capabilities())) {
1048 printk(ACER_ERR "Unable to detect available devices\n");
1049 return -ENODEV;
1050 }
1051 } else if (!wmi_has_guid(WMID_GUID2) && interface) {
1052 printk(ACER_ERR "Unable to detect available devices\n");
1053 return -ENODEV;
1054 }
1055
1056 if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
1057 interface = &AMW0_interface;
1058
1059 if (ACPI_FAILURE(AMW0_set_capabilities())) {
1060 printk(ACER_ERR "Unable to detect available devices\n");
1061 return -ENODEV;
1062 }
1063 }
1064
1065 if (wmi_has_guid(AMW0_GUID1)) {
1066 if (ACPI_FAILURE(AMW0_find_mailled()))
1067 printk(ACER_ERR "Unable to detect mail LED\n");
1068 }
1069
1070 find_quirks();
1071
1072 if (!interface) {
1073 printk(ACER_ERR "No or unsupported WMI interface, unable to ");
1074 printk(KERN_CONT "load.\n");
1075 return -ENODEV;
1076 }
1077
1078 if (platform_driver_register(&acer_platform_driver)) {
1079 printk(ACER_ERR "Unable to register platform driver.\n");
1080 goto error_platform_register;
1081 }
1082 acer_platform_device = platform_device_alloc("acer-wmi", -1);
1083 platform_device_add(acer_platform_device);
1084
1085 err = create_sysfs();
1086 if (err)
1087 return err;
1088
1089 /* Override any initial settings with values from the commandline */
1090 acer_commandline_init();
1091
1092 return 0;
1093
1094error_platform_register:
1095 return -ENODEV;
1096}
1097
1098static void __exit acer_wmi_exit(void)
1099{
1100 remove_sysfs(acer_platform_device);
1101 platform_device_del(acer_platform_device);
1102 platform_driver_unregister(&acer_platform_driver);
1103
1104 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
1105 return;
1106}
1107
1108module_init(acer_wmi_init);
1109module_exit(acer_wmi_exit);
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 3a36a294e91b..7c6dfd03de9f 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -254,7 +254,7 @@ ASUS_LED(gled, "gaming");
254 * method is searched within the scope of the handle, can be NULL. The output 254 * method is searched within the scope of the handle, can be NULL. The output
255 * of the method is written is output, which can also be NULL 255 * of the method is written is output, which can also be NULL
256 * 256 *
257 * returns 1 if write is successful, 0 else. 257 * returns 0 if write is successful, -1 else.
258 */ 258 */
259static int write_acpi_int(acpi_handle handle, const char *method, int val, 259static int write_acpi_int(acpi_handle handle, const char *method, int val,
260 struct acpi_buffer *output) 260 struct acpi_buffer *output)
@@ -263,13 +263,19 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
263 union acpi_object in_obj; //the only param we use 263 union acpi_object in_obj; //the only param we use
264 acpi_status status; 264 acpi_status status;
265 265
266 if (!handle)
267 return 0;
268
266 params.count = 1; 269 params.count = 1;
267 params.pointer = &in_obj; 270 params.pointer = &in_obj;
268 in_obj.type = ACPI_TYPE_INTEGER; 271 in_obj.type = ACPI_TYPE_INTEGER;
269 in_obj.integer.value = val; 272 in_obj.integer.value = val;
270 273
271 status = acpi_evaluate_object(handle, (char *)method, &params, output); 274 status = acpi_evaluate_object(handle, (char *)method, &params, output);
272 return (status == AE_OK); 275 if (status == AE_OK)
276 return 0;
277 else
278 return -1;
273} 279}
274 280
275static int read_wireless_status(int mask) 281static int read_wireless_status(int mask)
@@ -321,7 +327,7 @@ static void write_status(acpi_handle handle, int out, int mask)
321 327
322 switch (mask) { 328 switch (mask) {
323 case MLED_ON: 329 case MLED_ON:
324 out = !out & 0x1; 330 out = !(out & 0x1);
325 break; 331 break;
326 case GLED_ON: 332 case GLED_ON:
327 out = (out & 0x1) + 1; 333 out = (out & 0x1) + 1;
@@ -335,7 +341,7 @@ static void write_status(acpi_handle handle, int out, int mask)
335 break; 341 break;
336 } 342 }
337 343
338 if (handle && !write_acpi_int(handle, NULL, out, NULL)) 344 if (write_acpi_int(handle, NULL, out, NULL))
339 printk(ASUS_WARNING " write failed %x\n", mask); 345 printk(ASUS_WARNING " write failed %x\n", mask);
340} 346}
341 347
@@ -415,7 +421,7 @@ static int set_brightness(struct backlight_device *bd, int value)
415 value = (0 < value) ? ((15 < value) ? 15 : value) : 0; 421 value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
416 /* 0 <= value <= 15 */ 422 /* 0 <= value <= 15 */
417 423
418 if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) { 424 if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
419 printk(ASUS_WARNING "Error changing brightness\n"); 425 printk(ASUS_WARNING "Error changing brightness\n");
420 ret = -EIO; 426 ret = -EIO;
421 } 427 }
@@ -545,7 +551,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
545 551
546 rv = parse_arg(buf, count, &value); 552 rv = parse_arg(buf, count, &value);
547 if (rv > 0) { 553 if (rv > 0) {
548 if (!write_acpi_int(ledd_set_handle, NULL, value, NULL)) 554 if (write_acpi_int(ledd_set_handle, NULL, value, NULL))
549 printk(ASUS_WARNING "LED display write failed\n"); 555 printk(ASUS_WARNING "LED display write failed\n");
550 else 556 else
551 hotk->ledd_status = (u32) value; 557 hotk->ledd_status = (u32) value;
@@ -590,7 +596,7 @@ static ssize_t store_bluetooth(struct device *dev,
590static void set_display(int value) 596static void set_display(int value)
591{ 597{
592 /* no sanity check needed for now */ 598 /* no sanity check needed for now */
593 if (!write_acpi_int(display_set_handle, NULL, value, NULL)) 599 if (write_acpi_int(display_set_handle, NULL, value, NULL))
594 printk(ASUS_WARNING "Error setting display\n"); 600 printk(ASUS_WARNING "Error setting display\n");
595 return; 601 return;
596} 602}
@@ -647,7 +653,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
647 */ 653 */
648static void set_light_sens_switch(int value) 654static void set_light_sens_switch(int value)
649{ 655{
650 if (!write_acpi_int(ls_switch_handle, NULL, value, NULL)) 656 if (write_acpi_int(ls_switch_handle, NULL, value, NULL))
651 printk(ASUS_WARNING "Error setting light sensor switch\n"); 657 printk(ASUS_WARNING "Error setting light sensor switch\n");
652 hotk->light_switch = value; 658 hotk->light_switch = value;
653} 659}
@@ -672,7 +678,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
672 678
673static void set_light_sens_level(int value) 679static void set_light_sens_level(int value)
674{ 680{
675 if (!write_acpi_int(ls_level_handle, NULL, value, NULL)) 681 if (write_acpi_int(ls_level_handle, NULL, value, NULL))
676 printk(ASUS_WARNING "Error setting light sensor level\n"); 682 printk(ASUS_WARNING "Error setting light sensor level\n");
677 hotk->light_level = value; 683 hotk->light_level = value;
678} 684}
@@ -860,7 +866,7 @@ static int asus_hotk_get_info(void)
860 printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); 866 printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
861 867
862 /* We have to write 0 on init this far for all ASUS models */ 868 /* We have to write 0 on init this far for all ASUS models */
863 if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { 869 if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
864 printk(ASUS_ERR "Hotkey initialization failed\n"); 870 printk(ASUS_ERR "Hotkey initialization failed\n");
865 return -ENODEV; 871 return -ENODEV;
866 } 872 }
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
new file mode 100644
index 000000000000..f70984ab1e1b
--- /dev/null
+++ b/drivers/misc/intel_menlow.c
@@ -0,0 +1,526 @@
1/*
2 * intel_menlow.c - Intel menlow Driver for thermal management extension
3 *
4 * Copyright (C) 2008 Intel Corp
5 * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
6 * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 *
24 * This driver creates the sys I/F for programming the sensors.
25 * It also implements the driver for intel menlow memory controller (hardware
26 * id is INT0002) which makes use of the platform specific ACPI methods
27 * to get/set bandwidth.
28 */
29
30#include <linux/kernel.h>
31#include <linux/module.h>
32#include <linux/init.h>
33#include <linux/types.h>
34#include <linux/pci.h>
35#include <linux/pm.h>
36
37#include <linux/thermal.h>
38#include <acpi/acpi_bus.h>
39#include <acpi/acpi_drivers.h>
40
41MODULE_AUTHOR("Thomas Sujith");
42MODULE_AUTHOR("Zhang Rui");
43MODULE_DESCRIPTION("Intel Menlow platform specific driver");
44MODULE_LICENSE("GPL");
45
46/*
47 * Memory controller device control
48 */
49
50#define MEMORY_GET_BANDWIDTH "GTHS"
51#define MEMORY_SET_BANDWIDTH "STHS"
52#define MEMORY_ARG_CUR_BANDWIDTH 1
53#define MEMORY_ARG_MAX_BANDWIDTH 0
54
55static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
56 unsigned long *max_state)
57{
58 struct acpi_device *device = cdev->devdata;
59 acpi_handle handle = device->handle;
60 unsigned long value;
61 struct acpi_object_list arg_list;
62 union acpi_object arg;
63 acpi_status status = AE_OK;
64
65 arg_list.count = 1;
66 arg_list.pointer = &arg;
67 arg.type = ACPI_TYPE_INTEGER;
68 arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH;
69 status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
70 &arg_list, &value);
71 if (ACPI_FAILURE(status))
72 return -EFAULT;
73
74 *max_state = value - 1;
75 return 0;
76}
77
78static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
79 char *buf)
80{
81 unsigned long value;
82 if (memory_get_int_max_bandwidth(cdev, &value))
83 return -EINVAL;
84
85 return sprintf(buf, "%ld\n", value);
86}
87
88static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
89 char *buf)
90{
91 struct acpi_device *device = cdev->devdata;
92 acpi_handle handle = device->handle;
93 unsigned long value;
94 struct acpi_object_list arg_list;
95 union acpi_object arg;
96 acpi_status status = AE_OK;
97
98 arg_list.count = 1;
99 arg_list.pointer = &arg;
100 arg.type = ACPI_TYPE_INTEGER;
101 arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
102 status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
103 &arg_list, &value);
104 if (ACPI_FAILURE(status))
105 return -EFAULT;
106
107 return sprintf(buf, "%ld\n", value);
108}
109
110static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
111 unsigned int state)
112{
113 struct acpi_device *device = cdev->devdata;
114 acpi_handle handle = device->handle;
115 struct acpi_object_list arg_list;
116 union acpi_object arg;
117 acpi_status status;
118 int temp;
119 unsigned long max_state;
120
121 if (memory_get_int_max_bandwidth(cdev, &max_state))
122 return -EFAULT;
123
124 if (max_state < 0 || state > max_state)
125 return -EINVAL;
126
127 arg_list.count = 1;
128 arg_list.pointer = &arg;
129 arg.type = ACPI_TYPE_INTEGER;
130 arg.integer.value = state;
131
132 status =
133 acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
134 (unsigned long *)&temp);
135
136 printk(KERN_INFO
137 "Bandwidth value was %d: status is %d\n", state, status);
138 if (ACPI_FAILURE(status))
139 return -EFAULT;
140
141 return 0;
142}
143
144static struct thermal_cooling_device_ops memory_cooling_ops = {
145 .get_max_state = memory_get_max_bandwidth,
146 .get_cur_state = memory_get_cur_bandwidth,
147 .set_cur_state = memory_set_cur_bandwidth,
148};
149
150/*
151 * Memory Device Management
152 */
153static int intel_menlow_memory_add(struct acpi_device *device)
154{
155 int result = -ENODEV;
156 acpi_status status = AE_OK;
157 acpi_handle dummy;
158 struct thermal_cooling_device *cdev;
159
160 if (!device)
161 return -EINVAL;
162
163 status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy);
164 if (ACPI_FAILURE(status))
165 goto end;
166
167 status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy);
168 if (ACPI_FAILURE(status))
169 goto end;
170
171 cdev = thermal_cooling_device_register("Memory controller", device,
172 &memory_cooling_ops);
173 acpi_driver_data(device) = cdev;
174 if (!cdev)
175 result = -ENODEV;
176 else {
177 result = sysfs_create_link(&device->dev.kobj,
178 &cdev->device.kobj, "thermal_cooling");
179 if (result)
180 goto unregister;
181
182 result = sysfs_create_link(&cdev->device.kobj,
183 &device->dev.kobj, "device");
184 if (result) {
185 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
186 goto unregister;
187 }
188 }
189
190 end:
191 return result;
192
193 unregister:
194 thermal_cooling_device_unregister(cdev);
195 return result;
196
197}
198
199static int intel_menlow_memory_remove(struct acpi_device *device, int type)
200{
201 struct thermal_cooling_device *cdev = acpi_driver_data(device);
202
203 if (!device || !cdev)
204 return -EINVAL;
205
206 sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
207 sysfs_remove_link(&cdev->device.kobj, "device");
208 thermal_cooling_device_unregister(cdev);
209
210 return 0;
211}
212
213const static struct acpi_device_id intel_menlow_memory_ids[] = {
214 {"INT0002", 0},
215 {"", 0},
216};
217
218static struct acpi_driver intel_menlow_memory_driver = {
219 .name = "intel_menlow_thermal_control",
220 .ids = intel_menlow_memory_ids,
221 .ops = {
222 .add = intel_menlow_memory_add,
223 .remove = intel_menlow_memory_remove,
224 },
225};
226
227/*
228 * Sensor control on menlow platform
229 */
230
231#define THERMAL_AUX0 0
232#define THERMAL_AUX1 1
233#define GET_AUX0 "GAX0"
234#define GET_AUX1 "GAX1"
235#define SET_AUX0 "SAX0"
236#define SET_AUX1 "SAX1"
237
238struct intel_menlow_attribute {
239 struct device_attribute attr;
240 struct device *device;
241 acpi_handle handle;
242 struct list_head node;
243};
244
245static LIST_HEAD(intel_menlow_attr_list);
246static DEFINE_MUTEX(intel_menlow_attr_lock);
247
248/*
249 * sensor_get_auxtrip - get the current auxtrip value from sensor
250 * @name: Thermalzone name
251 * @auxtype : AUX0/AUX1
252 * @buf: syfs buffer
253 */
254static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
255{
256 acpi_status status;
257
258 if ((index != 0 && index != 1) || !value)
259 return -EINVAL;
260
261 status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
262 NULL, (unsigned long *)value);
263 if (ACPI_FAILURE(status))
264 return -EIO;
265
266 return 0;
267}
268
269/*
270 * sensor_set_auxtrip - set the new auxtrip value to sensor
271 * @name: Thermalzone name
272 * @auxtype : AUX0/AUX1
273 * @buf: syfs buffer
274 */
275static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
276{
277 acpi_status status;
278 union acpi_object arg = {
279 ACPI_TYPE_INTEGER
280 };
281 struct acpi_object_list args = {
282 1, &arg
283 };
284 int temp;
285
286 if (index != 0 && index != 1)
287 return -EINVAL;
288
289 status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
290 NULL, (unsigned long *)&temp);
291 if (ACPI_FAILURE(status))
292 return -EIO;
293 if ((index && value < temp) || (!index && value > temp))
294 return -EINVAL;
295
296 arg.integer.value = value;
297 status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
298 &args, (unsigned long *)&temp);
299 if (ACPI_FAILURE(status))
300 return -EIO;
301
302 /* do we need to check the return value of SAX0/SAX1 ? */
303
304 return 0;
305}
306
307#define to_intel_menlow_attr(_attr) \
308 container_of(_attr, struct intel_menlow_attribute, attr)
309
310static ssize_t aux0_show(struct device *dev,
311 struct device_attribute *dev_attr, char *buf)
312{
313 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
314 int value;
315 int result;
316
317 result = sensor_get_auxtrip(attr->handle, 0, &value);
318
319 return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
320}
321
322static ssize_t aux1_show(struct device *dev,
323 struct device_attribute *dev_attr, char *buf)
324{
325 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
326 int value;
327 int result;
328
329 result = sensor_get_auxtrip(attr->handle, 1, &value);
330
331 return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
332}
333
334static ssize_t aux0_store(struct device *dev,
335 struct device_attribute *dev_attr,
336 const char *buf, size_t count)
337{
338 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
339 int value;
340 int result;
341
342 /*Sanity check; should be a positive integer */
343 if (!sscanf(buf, "%d", &value))
344 return -EINVAL;
345
346 if (value < 0)
347 return -EINVAL;
348
349 result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value));
350 return result ? result : count;
351}
352
353static ssize_t aux1_store(struct device *dev,
354 struct device_attribute *dev_attr,
355 const char *buf, size_t count)
356{
357 struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
358 int value;
359 int result;
360
361 /*Sanity check; should be a positive integer */
362 if (!sscanf(buf, "%d", &value))
363 return -EINVAL;
364
365 if (value < 0)
366 return -EINVAL;
367
368 result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value));
369 return result ? result : count;
370}
371
372/* BIOS can enable/disable the thermal user application in dabney platform */
373#define BIOS_ENABLED "\\_TZ.GSTS"
374static ssize_t bios_enabled_show(struct device *dev,
375 struct device_attribute *attr, char *buf)
376{
377 acpi_status status;
378 unsigned long bios_enabled;
379
380 status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
381 if (ACPI_FAILURE(status))
382 return -ENODEV;
383
384 return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled");
385}
386
387static int intel_menlow_add_one_attribute(char *name, int mode, void *show,
388 void *store, struct device *dev,
389 acpi_handle handle)
390{
391 struct intel_menlow_attribute *attr;
392 int result;
393
394 attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL);
395 if (!attr)
396 return -ENOMEM;
397
398 attr->attr.attr.name = name;
399 attr->attr.attr.mode = mode;
400 attr->attr.show = show;
401 attr->attr.store = store;
402 attr->device = dev;
403 attr->handle = handle;
404
405 result = device_create_file(dev, &attr->attr);
406 if (result)
407 return result;
408
409 mutex_lock(&intel_menlow_attr_lock);
410 list_add_tail(&attr->node, &intel_menlow_attr_list);
411 mutex_unlock(&intel_menlow_attr_lock);
412
413 return 0;
414}
415
416static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
417 void *context, void **rv)
418{
419 acpi_status status;
420 acpi_handle dummy;
421 struct thermal_zone_device *thermal;
422 int result;
423
424 result = acpi_bus_get_private_data(handle, (void **)&thermal);
425 if (result)
426 return 0;
427
428 /* _TZ must have the AUX0/1 methods */
429 status = acpi_get_handle(handle, GET_AUX0, &dummy);
430 if (ACPI_FAILURE(status))
431 goto not_found;
432
433 status = acpi_get_handle(handle, SET_AUX0, &dummy);
434 if (ACPI_FAILURE(status))
435 goto not_found;
436
437 result = intel_menlow_add_one_attribute("aux0", 0644,
438 aux0_show, aux0_store,
439 &thermal->device, handle);
440 if (result)
441 return AE_ERROR;
442
443 status = acpi_get_handle(handle, GET_AUX1, &dummy);
444 if (ACPI_FAILURE(status))
445 goto not_found;
446
447 status = acpi_get_handle(handle, SET_AUX1, &dummy);
448 if (ACPI_FAILURE(status))
449 goto not_found;
450
451 result = intel_menlow_add_one_attribute("aux1", 0644,
452 aux1_show, aux1_store,
453 &thermal->device, handle);
454 if (result)
455 return AE_ERROR;
456
457 /*
458 * create the "dabney_enabled" attribute which means the user app
459 * should be loaded or not
460 */
461
462 result = intel_menlow_add_one_attribute("bios_enabled", 0444,
463 bios_enabled_show, NULL,
464 &thermal->device, handle);
465 if (result)
466 return AE_ERROR;
467
468 not_found:
469 if (status == AE_NOT_FOUND)
470 return AE_OK;
471 else
472 return status;
473}
474
475static void intel_menlow_unregister_sensor(void)
476{
477 struct intel_menlow_attribute *pos, *next;
478
479 mutex_lock(&intel_menlow_attr_lock);
480 list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) {
481 list_del(&pos->node);
482 device_remove_file(pos->device, &pos->attr);
483 kfree(pos);
484 }
485 mutex_unlock(&intel_menlow_attr_lock);
486
487 return;
488}
489
490static int __init intel_menlow_module_init(void)
491{
492 int result = -ENODEV;
493 acpi_status status;
494 unsigned long enable;
495
496 if (acpi_disabled)
497 return result;
498
499 /* Looking for the \_TZ.GSTS method */
500 status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable);
501 if (ACPI_FAILURE(status) || !enable)
502 return -ENODEV;
503
504 /* Looking for ACPI device MEM0 with hardware id INT0002 */
505 result = acpi_bus_register_driver(&intel_menlow_memory_driver);
506 if (result)
507 return result;
508
509 /* Looking for sensors in each ACPI thermal zone */
510 status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
511 ACPI_UINT32_MAX,
512 intel_menlow_register_sensor, NULL, NULL);
513 if (ACPI_FAILURE(status))
514 return -ENODEV;
515
516 return 0;
517}
518
519static void __exit intel_menlow_module_exit(void)
520{
521 acpi_bus_unregister_driver(&intel_menlow_memory_driver);
522 intel_menlow_unregister_sensor();
523}
524
525module_init(intel_menlow_module_init);
526module_exit(intel_menlow_module_exit);
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index b0f68031b49d..899e3f75f288 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -73,7 +73,7 @@
73 if (debug) printk(KERN_WARNING DRV_PFX msg); \ 73 if (debug) printk(KERN_WARNING DRV_PFX msg); \
74} while (0) 74} while (0)
75 75
76#define SONY_LAPTOP_DRIVER_VERSION "0.5" 76#define SONY_LAPTOP_DRIVER_VERSION "0.6"
77 77
78#define SONY_NC_CLASS "sony-nc" 78#define SONY_NC_CLASS "sony-nc"
79#define SONY_NC_HID "SNY5001" 79#define SONY_NC_HID "SNY5001"
@@ -146,68 +146,70 @@ struct sony_laptop_keypress {
146 * and input layer indexes in the keymap 146 * and input layer indexes in the keymap
147 */ 147 */
148static int sony_laptop_input_index[] = { 148static int sony_laptop_input_index[] = {
149 -1, /* no event */ 149 -1, /* 0 no event */
150 -1, /* SONYPI_EVENT_JOGDIAL_DOWN */ 150 -1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */
151 -1, /* SONYPI_EVENT_JOGDIAL_UP */ 151 -1, /* 2 SONYPI_EVENT_JOGDIAL_UP */
152 -1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */ 152 -1, /* 3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
153 -1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */ 153 -1, /* 4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
154 -1, /* SONYPI_EVENT_JOGDIAL_PRESSED */ 154 -1, /* 5 SONYPI_EVENT_JOGDIAL_PRESSED */
155 -1, /* SONYPI_EVENT_JOGDIAL_RELEASED */ 155 -1, /* 6 SONYPI_EVENT_JOGDIAL_RELEASED */
156 0, /* SONYPI_EVENT_CAPTURE_PRESSED */ 156 0, /* 7 SONYPI_EVENT_CAPTURE_PRESSED */
157 1, /* SONYPI_EVENT_CAPTURE_RELEASED */ 157 1, /* 8 SONYPI_EVENT_CAPTURE_RELEASED */
158 2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ 158 2, /* 9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
159 3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ 159 3, /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
160 4, /* SONYPI_EVENT_FNKEY_ESC */ 160 4, /* 11 SONYPI_EVENT_FNKEY_ESC */
161 5, /* SONYPI_EVENT_FNKEY_F1 */ 161 5, /* 12 SONYPI_EVENT_FNKEY_F1 */
162 6, /* SONYPI_EVENT_FNKEY_F2 */ 162 6, /* 13 SONYPI_EVENT_FNKEY_F2 */
163 7, /* SONYPI_EVENT_FNKEY_F3 */ 163 7, /* 14 SONYPI_EVENT_FNKEY_F3 */
164 8, /* SONYPI_EVENT_FNKEY_F4 */ 164 8, /* 15 SONYPI_EVENT_FNKEY_F4 */
165 9, /* SONYPI_EVENT_FNKEY_F5 */ 165 9, /* 16 SONYPI_EVENT_FNKEY_F5 */
166 10, /* SONYPI_EVENT_FNKEY_F6 */ 166 10, /* 17 SONYPI_EVENT_FNKEY_F6 */
167 11, /* SONYPI_EVENT_FNKEY_F7 */ 167 11, /* 18 SONYPI_EVENT_FNKEY_F7 */
168 12, /* SONYPI_EVENT_FNKEY_F8 */ 168 12, /* 19 SONYPI_EVENT_FNKEY_F8 */
169 13, /* SONYPI_EVENT_FNKEY_F9 */ 169 13, /* 20 SONYPI_EVENT_FNKEY_F9 */
170 14, /* SONYPI_EVENT_FNKEY_F10 */ 170 14, /* 21 SONYPI_EVENT_FNKEY_F10 */
171 15, /* SONYPI_EVENT_FNKEY_F11 */ 171 15, /* 22 SONYPI_EVENT_FNKEY_F11 */
172 16, /* SONYPI_EVENT_FNKEY_F12 */ 172 16, /* 23 SONYPI_EVENT_FNKEY_F12 */
173 17, /* SONYPI_EVENT_FNKEY_1 */ 173 17, /* 24 SONYPI_EVENT_FNKEY_1 */
174 18, /* SONYPI_EVENT_FNKEY_2 */ 174 18, /* 25 SONYPI_EVENT_FNKEY_2 */
175 19, /* SONYPI_EVENT_FNKEY_D */ 175 19, /* 26 SONYPI_EVENT_FNKEY_D */
176 20, /* SONYPI_EVENT_FNKEY_E */ 176 20, /* 27 SONYPI_EVENT_FNKEY_E */
177 21, /* SONYPI_EVENT_FNKEY_F */ 177 21, /* 28 SONYPI_EVENT_FNKEY_F */
178 22, /* SONYPI_EVENT_FNKEY_S */ 178 22, /* 29 SONYPI_EVENT_FNKEY_S */
179 23, /* SONYPI_EVENT_FNKEY_B */ 179 23, /* 30 SONYPI_EVENT_FNKEY_B */
180 24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */ 180 24, /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
181 25, /* SONYPI_EVENT_PKEY_P1 */ 181 25, /* 32 SONYPI_EVENT_PKEY_P1 */
182 26, /* SONYPI_EVENT_PKEY_P2 */ 182 26, /* 33 SONYPI_EVENT_PKEY_P2 */
183 27, /* SONYPI_EVENT_PKEY_P3 */ 183 27, /* 34 SONYPI_EVENT_PKEY_P3 */
184 28, /* SONYPI_EVENT_BACK_PRESSED */ 184 28, /* 35 SONYPI_EVENT_BACK_PRESSED */
185 -1, /* SONYPI_EVENT_LID_CLOSED */ 185 -1, /* 36 SONYPI_EVENT_LID_CLOSED */
186 -1, /* SONYPI_EVENT_LID_OPENED */ 186 -1, /* 37 SONYPI_EVENT_LID_OPENED */
187 29, /* SONYPI_EVENT_BLUETOOTH_ON */ 187 29, /* 38 SONYPI_EVENT_BLUETOOTH_ON */
188 30, /* SONYPI_EVENT_BLUETOOTH_OFF */ 188 30, /* 39 SONYPI_EVENT_BLUETOOTH_OFF */
189 31, /* SONYPI_EVENT_HELP_PRESSED */ 189 31, /* 40 SONYPI_EVENT_HELP_PRESSED */
190 32, /* SONYPI_EVENT_FNKEY_ONLY */ 190 32, /* 41 SONYPI_EVENT_FNKEY_ONLY */
191 33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */ 191 33, /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
192 34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */ 192 34, /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
193 35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ 193 35, /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
194 36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ 194 36, /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
195 37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ 195 37, /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
196 38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */ 196 38, /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
197 39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ 197 39, /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
198 40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ 198 40, /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
199 41, /* SONYPI_EVENT_ZOOM_PRESSED */ 199 41, /* 50 SONYPI_EVENT_ZOOM_PRESSED */
200 42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */ 200 42, /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
201 43, /* SONYPI_EVENT_MEYE_FACE */ 201 43, /* 52 SONYPI_EVENT_MEYE_FACE */
202 44, /* SONYPI_EVENT_MEYE_OPPOSITE */ 202 44, /* 53 SONYPI_EVENT_MEYE_OPPOSITE */
203 45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */ 203 45, /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
204 46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */ 204 46, /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
205 -1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */ 205 -1, /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
206 -1, /* SONYPI_EVENT_BATTERY_INSERT */ 206 -1, /* 57 SONYPI_EVENT_BATTERY_INSERT */
207 -1, /* SONYPI_EVENT_BATTERY_REMOVE */ 207 -1, /* 58 SONYPI_EVENT_BATTERY_REMOVE */
208 -1, /* SONYPI_EVENT_FNKEY_RELEASED */ 208 -1, /* 59 SONYPI_EVENT_FNKEY_RELEASED */
209 47, /* SONYPI_EVENT_WIRELESS_ON */ 209 47, /* 60 SONYPI_EVENT_WIRELESS_ON */
210 48, /* SONYPI_EVENT_WIRELESS_OFF */ 210 48, /* 61 SONYPI_EVENT_WIRELESS_OFF */
211 49, /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */
212 50, /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */
211}; 213};
212 214
213static int sony_laptop_input_keycode_map[] = { 215static int sony_laptop_input_keycode_map[] = {
@@ -260,6 +262,8 @@ static int sony_laptop_input_keycode_map[] = {
260 KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */ 262 KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
261 KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */ 263 KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */
262 KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */ 264 KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */
265 KEY_ZOOMIN, /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */
266 KEY_ZOOMOUT /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */
263}; 267};
264 268
265/* release buttons after a short delay if pressed */ 269/* release buttons after a short delay if pressed */
@@ -311,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event)
311 break; 315 break;
312 316
313 default: 317 default:
314 if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) { 318 if (event > ARRAY_SIZE(sony_laptop_input_index)) {
315 dprintk("sony_laptop_report_input_event, event not known: %d\n", event); 319 dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
316 break; 320 break;
317 } 321 }
@@ -875,6 +879,15 @@ static const struct dmi_system_id sony_nc_ids[] = {
875 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), 879 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
876 }, 880 },
877 }, 881 },
882 {
883 .ident = "Sony Vaio N Series",
884 .callback = sony_nc_C_enable,
885 .driver_data = sony_C_events,
886 .matches = {
887 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
888 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"),
889 },
890 },
878 { } 891 { }
879}; 892};
880 893
@@ -1169,10 +1182,12 @@ static struct acpi_driver sony_nc_driver = {
1169#define SONYPI_DEVICE_TYPE1 0x00000001 1182#define SONYPI_DEVICE_TYPE1 0x00000001
1170#define SONYPI_DEVICE_TYPE2 0x00000002 1183#define SONYPI_DEVICE_TYPE2 0x00000002
1171#define SONYPI_DEVICE_TYPE3 0x00000004 1184#define SONYPI_DEVICE_TYPE3 0x00000004
1185#define SONYPI_DEVICE_TYPE4 0x00000008
1172 1186
1173#define SONYPI_TYPE1_OFFSET 0x04 1187#define SONYPI_TYPE1_OFFSET 0x04
1174#define SONYPI_TYPE2_OFFSET 0x12 1188#define SONYPI_TYPE2_OFFSET 0x12
1175#define SONYPI_TYPE3_OFFSET 0x12 1189#define SONYPI_TYPE3_OFFSET 0x12
1190#define SONYPI_TYPE4_OFFSET 0x12
1176 1191
1177struct sony_pic_ioport { 1192struct sony_pic_ioport {
1178 struct acpi_resource_io io1; 1193 struct acpi_resource_io io1;
@@ -1185,18 +1200,33 @@ struct sony_pic_irq {
1185 struct list_head list; 1200 struct list_head list;
1186}; 1201};
1187 1202
1203struct sonypi_eventtypes {
1204 u8 data;
1205 unsigned long mask;
1206 struct sonypi_event *events;
1207};
1208
1209struct device_ctrl {
1210 int model;
1211 int (*handle_irq)(const u8, const u8);
1212 u16 evport_offset;
1213 u8 has_camera;
1214 u8 has_bluetooth;
1215 u8 has_wwan;
1216 struct sonypi_eventtypes *event_types;
1217};
1218
1188struct sony_pic_dev { 1219struct sony_pic_dev {
1189 int model; 1220 struct device_ctrl *control;
1190 u16 evport_offset;
1191 u8 camera_power;
1192 u8 bluetooth_power;
1193 u8 wwan_power;
1194 struct acpi_device *acpi_dev; 1221 struct acpi_device *acpi_dev;
1195 struct sony_pic_irq *cur_irq; 1222 struct sony_pic_irq *cur_irq;
1196 struct sony_pic_ioport *cur_ioport; 1223 struct sony_pic_ioport *cur_ioport;
1197 struct list_head interrupts; 1224 struct list_head interrupts;
1198 struct list_head ioports; 1225 struct list_head ioports;
1199 struct mutex lock; 1226 struct mutex lock;
1227 u8 camera_power;
1228 u8 bluetooth_power;
1229 u8 wwan_power;
1200}; 1230};
1201 1231
1202static struct sony_pic_dev spic_dev = { 1232static struct sony_pic_dev spic_dev = {
@@ -1253,6 +1283,7 @@ static struct sonypi_event sonypi_joggerev[] = {
1253static struct sonypi_event sonypi_captureev[] = { 1283static struct sonypi_event sonypi_captureev[] = {
1254 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, 1284 { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
1255 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, 1285 { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
1286 { 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
1256 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, 1287 { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
1257 { 0, 0 } 1288 { 0, 0 }
1258}; 1289};
@@ -1289,7 +1320,6 @@ static struct sonypi_event sonypi_pkeyev[] = {
1289 { 0x01, SONYPI_EVENT_PKEY_P1 }, 1320 { 0x01, SONYPI_EVENT_PKEY_P1 },
1290 { 0x02, SONYPI_EVENT_PKEY_P2 }, 1321 { 0x02, SONYPI_EVENT_PKEY_P2 },
1291 { 0x04, SONYPI_EVENT_PKEY_P3 }, 1322 { 0x04, SONYPI_EVENT_PKEY_P3 },
1292 { 0x5c, SONYPI_EVENT_PKEY_P1 },
1293 { 0, 0 } 1323 { 0, 0 }
1294}; 1324};
1295 1325
@@ -1331,6 +1361,8 @@ static struct sonypi_event sonypi_lidev[] = {
1331/* The set of possible zoom events */ 1361/* The set of possible zoom events */
1332static struct sonypi_event sonypi_zoomev[] = { 1362static struct sonypi_event sonypi_zoomev[] = {
1333 { 0x39, SONYPI_EVENT_ZOOM_PRESSED }, 1363 { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
1364 { 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
1365 { 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
1334 { 0, 0 } 1366 { 0, 0 }
1335}; 1367};
1336 1368
@@ -1361,76 +1393,58 @@ static struct sonypi_event sonypi_batteryev[] = {
1361 { 0, 0 } 1393 { 0, 0 }
1362}; 1394};
1363 1395
1364static struct sonypi_eventtypes { 1396static struct sonypi_eventtypes type1_events[] = {
1365 int model; 1397 { 0, 0xffffffff, sonypi_releaseev },
1366 u8 data; 1398 { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
1367 unsigned long mask; 1399 { 0x30, SONYPI_LID_MASK, sonypi_lidev },
1368 struct sonypi_event * events; 1400 { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
1369} sony_pic_eventtypes[] = { 1401 { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
1370 { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev }, 1402 { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1371 { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, 1403 { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
1372 { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev }, 1404 { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
1373 { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, 1405 { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1374 { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, 1406 { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
1375 { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1407 { 0 },
1376 { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, 1408};
1377 { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1409static struct sonypi_eventtypes type2_events[] = {
1378 { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1410 { 0, 0xffffffff, sonypi_releaseev },
1379 { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1411 { 0x38, SONYPI_LID_MASK, sonypi_lidev },
1380 1412 { 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
1381 { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev }, 1413 { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
1382 { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev }, 1414 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1383 { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, 1415 { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
1384 { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, 1416 { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
1385 { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1417 { 0x11, SONYPI_BACK_MASK, sonypi_backev },
1386 { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, 1418 { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
1387 { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1419 { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
1388 { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev }, 1420 { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
1389 { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev }, 1421 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1390 { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, 1422 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1391 { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, 1423 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
1392 { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1424 { 0 },
1393 { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1425};
1394 { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1426static struct sonypi_eventtypes type3_events[] = {
1395 1427 { 0, 0xffffffff, sonypi_releaseev },
1396 { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev }, 1428 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1397 { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, 1429 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
1398 { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, 1430 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1399 { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, 1431 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1400 { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, 1432 { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
1401 { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, 1433 { 0 },
1402 { 0 } 1434};
1435static struct sonypi_eventtypes type4_events[] = {
1436 { 0, 0xffffffff, sonypi_releaseev },
1437 { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
1438 { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
1439 { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
1440 { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
1441 { 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
1442 { 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
1443 { 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
1444 { 0 },
1403}; 1445};
1404 1446
1405static int sony_pic_detect_device_type(void) 1447/* low level spic calls */
1406{
1407 struct pci_dev *pcidev;
1408 int model = 0;
1409
1410 if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1411 PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
1412 model = SONYPI_DEVICE_TYPE1;
1413
1414 else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1415 PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
1416 model = SONYPI_DEVICE_TYPE3;
1417
1418 else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1419 PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
1420 model = SONYPI_DEVICE_TYPE3;
1421
1422 else
1423 model = SONYPI_DEVICE_TYPE2;
1424
1425 if (pcidev)
1426 pci_dev_put(pcidev);
1427
1428 printk(KERN_INFO DRV_PFX "detected Type%d model\n",
1429 model == SONYPI_DEVICE_TYPE1 ? 1 :
1430 model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
1431 return model;
1432}
1433
1434#define ITERATIONS_LONG 10000 1448#define ITERATIONS_LONG 10000
1435#define ITERATIONS_SHORT 10 1449#define ITERATIONS_SHORT 10
1436#define wait_on_command(command, iterations) { \ 1450#define wait_on_command(command, iterations) { \
@@ -1451,7 +1465,7 @@ static u8 sony_pic_call1(u8 dev)
1451 outb(dev, spic_dev.cur_ioport->io1.minimum + 4); 1465 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
1452 v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); 1466 v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
1453 v2 = inb_p(spic_dev.cur_ioport->io1.minimum); 1467 v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
1454 dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); 1468 dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
1455 return v2; 1469 return v2;
1456} 1470}
1457 1471
@@ -1466,7 +1480,7 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
1466 ITERATIONS_LONG); 1480 ITERATIONS_LONG);
1467 outb(fn, spic_dev.cur_ioport->io1.minimum); 1481 outb(fn, spic_dev.cur_ioport->io1.minimum);
1468 v1 = inb_p(spic_dev.cur_ioport->io1.minimum); 1482 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
1469 dprintk("sony_pic_call2: 0x%.4x\n", v1); 1483 dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
1470 return v1; 1484 return v1;
1471} 1485}
1472 1486
@@ -1481,10 +1495,105 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
1481 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); 1495 wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
1482 outb(v, spic_dev.cur_ioport->io1.minimum); 1496 outb(v, spic_dev.cur_ioport->io1.minimum);
1483 v1 = inb_p(spic_dev.cur_ioport->io1.minimum); 1497 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
1484 dprintk("sony_pic_call3: 0x%.4x\n", v1); 1498 dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
1499 dev, fn, v, v1);
1485 return v1; 1500 return v1;
1486} 1501}
1487 1502
1503/*
1504 * minidrivers for SPIC models
1505 */
1506static int type4_handle_irq(const u8 data_mask, const u8 ev)
1507{
1508 /*
1509 * 0x31 could mean we have to take some extra action and wait for
1510 * the next irq for some Type4 models, it will generate a new
1511 * irq and we can read new data from the device:
1512 * - 0x5c and 0x5f requires 0xA0
1513 * - 0x61 requires 0xB3
1514 */
1515 if (data_mask == 0x31) {
1516 if (ev == 0x5c || ev == 0x5f)
1517 sony_pic_call1(0xA0);
1518 else if (ev == 0x61)
1519 sony_pic_call1(0xB3);
1520 return 0;
1521 }
1522 return 1;
1523}
1524
1525static struct device_ctrl spic_types[] = {
1526 {
1527 .model = SONYPI_DEVICE_TYPE1,
1528 .handle_irq = NULL,
1529 .evport_offset = SONYPI_TYPE1_OFFSET,
1530 .event_types = type1_events,
1531 },
1532 {
1533 .model = SONYPI_DEVICE_TYPE2,
1534 .handle_irq = NULL,
1535 .evport_offset = SONYPI_TYPE2_OFFSET,
1536 .event_types = type2_events,
1537 },
1538 {
1539 .model = SONYPI_DEVICE_TYPE3,
1540 .handle_irq = NULL,
1541 .evport_offset = SONYPI_TYPE3_OFFSET,
1542 .event_types = type3_events,
1543 },
1544 {
1545 .model = SONYPI_DEVICE_TYPE4,
1546 .handle_irq = type4_handle_irq,
1547 .evport_offset = SONYPI_TYPE4_OFFSET,
1548 .event_types = type4_events,
1549 },
1550};
1551
1552static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
1553{
1554 struct pci_dev *pcidev;
1555
1556 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1557 PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
1558 if (pcidev) {
1559 dev->control = &spic_types[0];
1560 goto out;
1561 }
1562
1563 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1564 PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
1565 if (pcidev) {
1566 dev->control = &spic_types[2];
1567 goto out;
1568 }
1569
1570 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1571 PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
1572 if (pcidev) {
1573 dev->control = &spic_types[3];
1574 goto out;
1575 }
1576
1577 pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
1578 PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
1579 if (pcidev) {
1580 dev->control = &spic_types[3];
1581 goto out;
1582 }
1583
1584 /* default */
1585 dev->control = &spic_types[1];
1586
1587out:
1588 if (pcidev)
1589 pci_dev_put(pcidev);
1590
1591 printk(KERN_INFO DRV_PFX "detected Type%d model\n",
1592 dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 :
1593 dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 :
1594 dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4);
1595}
1596
1488/* camera tests and poweron/poweroff */ 1597/* camera tests and poweron/poweroff */
1489#define SONYPI_CAMERA_PICTURE 5 1598#define SONYPI_CAMERA_PICTURE 5
1490#define SONYPI_CAMERA_CONTROL 0x10 1599#define SONYPI_CAMERA_CONTROL 0x10
@@ -2253,7 +2362,7 @@ static int sony_pic_enable(struct acpi_device *device,
2253 buffer.pointer = resource; 2362 buffer.pointer = resource;
2254 2363
2255 /* setup Type 1 resources */ 2364 /* setup Type 1 resources */
2256 if (spic_dev.model == SONYPI_DEVICE_TYPE1) { 2365 if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) {
2257 2366
2258 /* setup io resources */ 2367 /* setup io resources */
2259 resource->res1.type = ACPI_RESOURCE_TYPE_IO; 2368 resource->res1.type = ACPI_RESOURCE_TYPE_IO;
@@ -2335,39 +2444,49 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
2335 if (dev->cur_ioport->io2.minimum) 2444 if (dev->cur_ioport->io2.minimum)
2336 data_mask = inb_p(dev->cur_ioport->io2.minimum); 2445 data_mask = inb_p(dev->cur_ioport->io2.minimum);
2337 else 2446 else
2338 data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset); 2447 data_mask = inb_p(dev->cur_ioport->io1.minimum +
2448 dev->control->evport_offset);
2339 2449
2340 dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", 2450 dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
2341 ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset); 2451 ev, data_mask, dev->cur_ioport->io1.minimum,
2452 dev->control->evport_offset);
2342 2453
2343 if (ev == 0x00 || ev == 0xff) 2454 if (ev == 0x00 || ev == 0xff)
2344 return IRQ_HANDLED; 2455 return IRQ_HANDLED;
2345 2456
2346 for (i = 0; sony_pic_eventtypes[i].model; i++) { 2457 for (i = 0; dev->control->event_types[i].mask; i++) {
2347
2348 if (spic_dev.model != sony_pic_eventtypes[i].model)
2349 continue;
2350 2458
2351 if ((data_mask & sony_pic_eventtypes[i].data) != 2459 if ((data_mask & dev->control->event_types[i].data) !=
2352 sony_pic_eventtypes[i].data) 2460 dev->control->event_types[i].data)
2353 continue; 2461 continue;
2354 2462
2355 if (!(mask & sony_pic_eventtypes[i].mask)) 2463 if (!(mask & dev->control->event_types[i].mask))
2356 continue; 2464 continue;
2357 2465
2358 for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) { 2466 for (j = 0; dev->control->event_types[i].events[j].event; j++) {
2359 if (ev == sony_pic_eventtypes[i].events[j].data) { 2467 if (ev == dev->control->event_types[i].events[j].data) {
2360 device_event = 2468 device_event =
2361 sony_pic_eventtypes[i].events[j].event; 2469 dev->control->
2470 event_types[i].events[j].event;
2362 goto found; 2471 goto found;
2363 } 2472 }
2364 } 2473 }
2365 } 2474 }
2475 /* Still not able to decode the event try to pass
2476 * it over to the minidriver
2477 */
2478 if (dev->control->handle_irq &&
2479 dev->control->handle_irq(data_mask, ev) == 0)
2480 return IRQ_HANDLED;
2481
2482 dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
2483 ev, data_mask, dev->cur_ioport->io1.minimum,
2484 dev->control->evport_offset);
2366 return IRQ_HANDLED; 2485 return IRQ_HANDLED;
2367 2486
2368found: 2487found:
2369 sony_laptop_report_input_event(device_event); 2488 sony_laptop_report_input_event(device_event);
2370 acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event); 2489 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
2371 sonypi_compat_report_event(device_event); 2490 sonypi_compat_report_event(device_event);
2372 2491
2373 return IRQ_HANDLED; 2492 return IRQ_HANDLED;
@@ -2429,23 +2548,9 @@ static int sony_pic_add(struct acpi_device *device)
2429 2548
2430 spic_dev.acpi_dev = device; 2549 spic_dev.acpi_dev = device;
2431 strcpy(acpi_device_class(device), "sony/hotkey"); 2550 strcpy(acpi_device_class(device), "sony/hotkey");
2432 spic_dev.model = sony_pic_detect_device_type(); 2551 sony_pic_detect_device_type(&spic_dev);
2433 mutex_init(&spic_dev.lock); 2552 mutex_init(&spic_dev.lock);
2434 2553
2435 /* model specific characteristics */
2436 switch(spic_dev.model) {
2437 case SONYPI_DEVICE_TYPE1:
2438 spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
2439 break;
2440 case SONYPI_DEVICE_TYPE3:
2441 spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
2442 break;
2443 case SONYPI_DEVICE_TYPE2:
2444 default:
2445 spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
2446 break;
2447 }
2448
2449 /* read _PRS resources */ 2554 /* read _PRS resources */
2450 result = sony_pic_possible_resources(device); 2555 result = sony_pic_possible_resources(device);
2451 if (result) { 2556 if (result) {
diff --git a/drivers/misc/tc1100-wmi.c b/drivers/misc/tc1100-wmi.c
new file mode 100644
index 000000000000..f25e4c974dcf
--- /dev/null
+++ b/drivers/misc/tc1100-wmi.c
@@ -0,0 +1,290 @@
1/*
2 * HP Compaq TC1100 Tablet WMI Extras Driver
3 *
4 * Copyright (C) 2007 Carlos Corbacho <carlos@strangeworlds.co.uk>
5 * Copyright (C) 2004 Jamey Hicks <jamey.hicks@hp.com>
6 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
7 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
8 *
9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at
14 * your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 *
25 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26 */
27
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/types.h>
32#include <acpi/acpi.h>
33#include <acpi/actypes.h>
34#include <acpi/acpi_bus.h>
35#include <acpi/acpi_drivers.h>
36#include <linux/platform_device.h>
37
38#define GUID "C364AC71-36DB-495A-8494-B439D472A505"
39
40#define TC1100_INSTANCE_WIRELESS 1
41#define TC1100_INSTANCE_JOGDIAL 2
42
43#define TC1100_LOGPREFIX "tc1100-wmi: "
44#define TC1100_INFO KERN_INFO TC1100_LOGPREFIX
45
46MODULE_AUTHOR("Jamey Hicks, Carlos Corbacho");
47MODULE_DESCRIPTION("HP Compaq TC1100 Tablet WMI Extras");
48MODULE_LICENSE("GPL");
49MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505");
50
51static int tc1100_probe(struct platform_device *device);
52static int tc1100_remove(struct platform_device *device);
53static int tc1100_suspend(struct platform_device *device, pm_message_t state);
54static int tc1100_resume(struct platform_device *device);
55
56static struct platform_driver tc1100_driver = {
57 .driver = {
58 .name = "tc1100-wmi",
59 .owner = THIS_MODULE,
60 },
61 .probe = tc1100_probe,
62 .remove = tc1100_remove,
63 .suspend = tc1100_suspend,
64 .resume = tc1100_resume,
65};
66
67static struct platform_device *tc1100_device;
68
69struct tc1100_data {
70 u32 wireless;
71 u32 jogdial;
72};
73
74static struct tc1100_data suspend_data;
75
76/* --------------------------------------------------------------------------
77 Device Management
78 -------------------------------------------------------------------------- */
79
80static int get_state(u32 *out, u8 instance)
81{
82 u32 tmp;
83 acpi_status status;
84 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
85 union acpi_object *obj;
86
87 if (!out)
88 return -EINVAL;
89
90 if (instance > 2)
91 return -ENODEV;
92
93 status = wmi_query_block(GUID, instance, &result);
94 if (ACPI_FAILURE(status))
95 return -ENODEV;
96
97 obj = (union acpi_object *) result.pointer;
98 if (obj && obj->type == ACPI_TYPE_BUFFER &&
99 obj->buffer.length == sizeof(u32)) {
100 tmp = *((u32 *) obj->buffer.pointer);
101 } else {
102 tmp = 0;
103 }
104
105 if (result.length > 0 && result.pointer)
106 kfree(result.pointer);
107
108 switch (instance) {
109 case TC1100_INSTANCE_WIRELESS:
110 *out = (tmp == 3) ? 1 : 0;
111 return 0;
112 case TC1100_INSTANCE_JOGDIAL:
113 *out = (tmp == 1) ? 1 : 0;
114 return 0;
115 default:
116 return -ENODEV;
117 }
118}
119
120static int set_state(u32 *in, u8 instance)
121{
122 u32 value;
123 acpi_status status;
124 struct acpi_buffer input;
125
126 if (!in)
127 return -EINVAL;
128
129 if (instance > 2)
130 return -ENODEV;
131
132 switch (instance) {
133 case TC1100_INSTANCE_WIRELESS:
134 value = (*in) ? 1 : 2;
135 break;
136 case TC1100_INSTANCE_JOGDIAL:
137 value = (*in) ? 0 : 1;
138 break;
139 default:
140 return -ENODEV;
141 }
142
143 input.length = sizeof(u32);
144 input.pointer = &value;
145
146 status = wmi_set_block(GUID, instance, &input);
147 if (ACPI_FAILURE(status))
148 return -ENODEV;
149
150 return 0;
151}
152
153/* --------------------------------------------------------------------------
154 FS Interface (/sys)
155 -------------------------------------------------------------------------- */
156
157/*
158 * Read/ write bool sysfs macro
159 */
160#define show_set_bool(value, instance) \
161static ssize_t \
162show_bool_##value(struct device *dev, struct device_attribute *attr, \
163 char *buf) \
164{ \
165 u32 result; \
166 acpi_status status = get_state(&result, instance); \
167 if (ACPI_SUCCESS(status)) \
168 return sprintf(buf, "%d\n", result); \
169 return sprintf(buf, "Read error\n"); \
170} \
171\
172static ssize_t \
173set_bool_##value(struct device *dev, struct device_attribute *attr, \
174 const char *buf, size_t count) \
175{ \
176 u32 tmp = simple_strtoul(buf, NULL, 10); \
177 acpi_status status = set_state(&tmp, instance); \
178 if (ACPI_FAILURE(status)) \
179 return -EINVAL; \
180 return count; \
181} \
182static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
183 show_bool_##value, set_bool_##value);
184
185show_set_bool(wireless, TC1100_INSTANCE_WIRELESS);
186show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL);
187
188static void remove_fs(void)
189{
190 device_remove_file(&tc1100_device->dev, &dev_attr_wireless);
191 device_remove_file(&tc1100_device->dev, &dev_attr_jogdial);
192}
193
194static int add_fs(void)
195{
196 int ret;
197
198 ret = device_create_file(&tc1100_device->dev, &dev_attr_wireless);
199 if (ret)
200 goto add_sysfs_error;
201
202 ret = device_create_file(&tc1100_device->dev, &dev_attr_jogdial);
203 if (ret)
204 goto add_sysfs_error;
205
206 return ret;
207
208add_sysfs_error:
209 remove_fs();
210 return ret;
211}
212
213/* --------------------------------------------------------------------------
214 Driver Model
215 -------------------------------------------------------------------------- */
216
217static int tc1100_probe(struct platform_device *device)
218{
219 int result = 0;
220
221 result = add_fs();
222 return result;
223}
224
225
226static int tc1100_remove(struct platform_device *device)
227{
228 remove_fs();
229 return 0;
230}
231
232static int tc1100_suspend(struct platform_device *dev, pm_message_t state)
233{
234 int ret;
235
236 ret = get_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS);
237 if (ret)
238 return ret;
239
240 ret = get_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL);
241 if (ret)
242 return ret;
243
244 return ret;
245}
246
247static int tc1100_resume(struct platform_device *dev)
248{
249 int ret;
250
251 ret = set_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS);
252 if (ret)
253 return ret;
254
255 ret = set_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL);
256 if (ret)
257 return ret;
258
259 return ret;
260}
261
262static int __init tc1100_init(void)
263{
264 int result = 0;
265
266 if (!wmi_has_guid(GUID))
267 return -ENODEV;
268
269 result = platform_driver_register(&tc1100_driver);
270 if (result)
271 return result;
272
273 tc1100_device = platform_device_alloc("tc1100-wmi", -1);
274 platform_device_add(tc1100_device);
275
276 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n");
277
278 return result;
279}
280
281static void __exit tc1100_exit(void)
282{
283 platform_device_del(tc1100_device);
284 platform_driver_unregister(&tc1100_driver);
285
286 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras unloaded\n");
287}
288
289module_init(tc1100_init);
290module_exit(tc1100_exit);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index cf56647a6ca4..7ba1acad5402 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -3,7 +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-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br> 6 * Copyright (C) 2006-2008 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
7 * 7 *
8 * 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
9 * 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
@@ -21,11 +21,13 @@
21 * 02110-1301, USA. 21 * 02110-1301, USA.
22 */ 22 */
23 23
24#define IBM_VERSION "0.17" 24#define TPACPI_VERSION "0.19"
25#define TPACPI_SYSFS_VERSION 0x020000 25#define TPACPI_SYSFS_VERSION 0x020200
26 26
27/* 27/*
28 * Changelog: 28 * Changelog:
29 * 2007-10-20 changelog trimmed down
30 *
29 * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to 31 * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to
30 * drivers/misc. 32 * drivers/misc.
31 * 33 *
@@ -33,89 +35,219 @@
33 * changelog now lives in git commit history, and will 35 * changelog now lives in git commit history, and will
34 * not be updated further in-file. 36 * not be updated further in-file.
35 * 37 *
36 * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
37 * 2005-03-17 0.11 support for 600e, 770x 38 * 2005-03-17 0.11 support for 600e, 770x
38 * thanks to Jamie Lentin <lentinj@dial.pipex.com> 39 * thanks to Jamie Lentin <lentinj@dial.pipex.com>
39 * support for 770e, G41 40 *
40 * G40 and G41 don't have a thinklight 41 * 2005-01-16 0.9 use MODULE_VERSION
41 * temperatures no longer experimental
42 * experimental brightness control
43 * experimental volume control
44 * experimental fan enable/disable
45 * 2005-01-16 0.10 fix module loading on R30, R31
46 * 2005-01-16 0.9 support for 570, R30, R31
47 * ultrabay support on A22p, A3x
48 * limit arg for cmos, led, beep, drop experimental status
49 * more capable led control on A21e, A22p, T20-22, X20
50 * experimental temperatures and fan speed
51 * experimental embedded controller register dump
52 * mark more functions as __init, drop incorrect __exit
53 * use MODULE_VERSION
54 * thanks to Henrik Brix Andersen <brix@gentoo.org> 42 * thanks to Henrik Brix Andersen <brix@gentoo.org>
55 * fix parameter passing on module loading 43 * fix parameter passing on module loading
56 * thanks to Rusty Russell <rusty@rustcorp.com.au> 44 * thanks to Rusty Russell <rusty@rustcorp.com.au>
57 * thanks to Jim Radford <radford@blackbean.org> 45 * thanks to Jim Radford <radford@blackbean.org>
58 * 2004-11-08 0.8 fix init error case, don't return from a macro 46 * 2004-11-08 0.8 fix init error case, don't return from a macro
59 * thanks to Chris Wright <chrisw@osdl.org> 47 * thanks to Chris Wright <chrisw@osdl.org>
60 * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20
61 * fix led control on A21e
62 * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device
63 * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20
64 * proc file format changed
65 * video_switch command
66 * experimental cmos control
67 * experimental led control
68 * experimental acpi sounds
69 * 2004-09-16 0.4 support for module parameters
70 * hotkey mask can be prefixed by 0x
71 * video output switching
72 * video expansion control
73 * ultrabay eject support
74 * removed lcd brightness/on/off control, didn't work
75 * 2004-08-17 0.3 support for R40
76 * lcd off, brightness control
77 * thinklight on/off
78 * 2004-08-14 0.2 support for T series, X20
79 * bluetooth enable/disable
80 * hotkey events disabled by default
81 * removed fan control, currently useless
82 * 2004-08-09 0.1 initial release, support for X series
83 */ 48 */
84 49
85#include "thinkpad_acpi.h" 50#include <linux/kernel.h>
51#include <linux/module.h>
52#include <linux/init.h>
53#include <linux/types.h>
54#include <linux/string.h>
55#include <linux/list.h>
56#include <linux/mutex.h>
57#include <linux/kthread.h>
58#include <linux/freezer.h>
59#include <linux/delay.h>
60
61#include <linux/nvram.h>
62#include <linux/proc_fs.h>
63#include <linux/sysfs.h>
64#include <linux/backlight.h>
65#include <linux/fb.h>
66#include <linux/platform_device.h>
67#include <linux/hwmon.h>
68#include <linux/hwmon-sysfs.h>
69#include <linux/input.h>
70#include <asm/uaccess.h>
71
72#include <linux/dmi.h>
73#include <linux/jiffies.h>
74#include <linux/workqueue.h>
75
76#include <acpi/acpi_drivers.h>
77#include <acpi/acnamesp.h>
78
79#include <linux/pci_ids.h>
80
81
82/* ThinkPad CMOS commands */
83#define TP_CMOS_VOLUME_DOWN 0
84#define TP_CMOS_VOLUME_UP 1
85#define TP_CMOS_VOLUME_MUTE 2
86#define TP_CMOS_BRIGHTNESS_UP 4
87#define TP_CMOS_BRIGHTNESS_DOWN 5
88
89/* NVRAM Addresses */
90enum tp_nvram_addr {
91 TP_NVRAM_ADDR_HK2 = 0x57,
92 TP_NVRAM_ADDR_THINKLIGHT = 0x58,
93 TP_NVRAM_ADDR_VIDEO = 0x59,
94 TP_NVRAM_ADDR_BRIGHTNESS = 0x5e,
95 TP_NVRAM_ADDR_MIXER = 0x60,
96};
86 97
87MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); 98/* NVRAM bit masks */
88MODULE_DESCRIPTION(IBM_DESC); 99enum {
89MODULE_VERSION(IBM_VERSION); 100 TP_NVRAM_MASK_HKT_THINKPAD = 0x08,
90MODULE_LICENSE("GPL"); 101 TP_NVRAM_MASK_HKT_ZOOM = 0x20,
102 TP_NVRAM_MASK_HKT_DISPLAY = 0x40,
103 TP_NVRAM_MASK_HKT_HIBERNATE = 0x80,
104 TP_NVRAM_MASK_THINKLIGHT = 0x10,
105 TP_NVRAM_MASK_HKT_DISPEXPND = 0x30,
106 TP_NVRAM_MASK_HKT_BRIGHTNESS = 0x20,
107 TP_NVRAM_MASK_LEVEL_BRIGHTNESS = 0x0f,
108 TP_NVRAM_POS_LEVEL_BRIGHTNESS = 0,
109 TP_NVRAM_MASK_MUTE = 0x40,
110 TP_NVRAM_MASK_HKT_VOLUME = 0x80,
111 TP_NVRAM_MASK_LEVEL_VOLUME = 0x0f,
112 TP_NVRAM_POS_LEVEL_VOLUME = 0,
113};
91 114
92/* Please remove this in year 2009 */ 115/* ACPI HIDs */
93MODULE_ALIAS("ibm_acpi"); 116#define TPACPI_ACPI_HKEY_HID "IBM0068"
94 117
95/* 118/* Input IDs */
96 * DMI matching for module autoloading 119#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
97 * 120#define TPACPI_HKEY_INPUT_VERSION 0x4101
98 * See http://thinkwiki.org/wiki/List_of_DMI_IDs 121
99 * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads 122
100 * 123/****************************************************************************
101 * Only models listed in thinkwiki will be supported, so add yours 124 * Main driver
102 * if it is not there yet.
103 */ 125 */
104#define IBM_BIOS_MODULE_ALIAS(__type) \
105 MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
106 126
107/* Non-ancient thinkpads */ 127#define TPACPI_NAME "thinkpad"
108MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); 128#define TPACPI_DESC "ThinkPad ACPI Extras"
109MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); 129#define TPACPI_FILE TPACPI_NAME "_acpi"
130#define TPACPI_URL "http://ibm-acpi.sf.net/"
131#define TPACPI_MAIL "ibm-acpi-devel@lists.sourceforge.net"
132
133#define TPACPI_PROC_DIR "ibm"
134#define TPACPI_ACPI_EVENT_PREFIX "ibm"
135#define TPACPI_DRVR_NAME TPACPI_FILE
136#define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon"
137
138#define TPACPI_MAX_ACPI_ARGS 3
139
140/* Debugging */
141#define TPACPI_LOG TPACPI_FILE ": "
142#define TPACPI_ERR KERN_ERR TPACPI_LOG
143#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG
144#define TPACPI_INFO KERN_INFO TPACPI_LOG
145#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG
146
147#define TPACPI_DBG_ALL 0xffff
148#define TPACPI_DBG_ALL 0xffff
149#define TPACPI_DBG_INIT 0x0001
150#define TPACPI_DBG_EXIT 0x0002
151#define dbg_printk(a_dbg_level, format, arg...) \
152 do { if (dbg_level & a_dbg_level) \
153 printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \
154 } while (0)
155#ifdef CONFIG_THINKPAD_ACPI_DEBUG
156#define vdbg_printk(a_dbg_level, format, arg...) \
157 dbg_printk(a_dbg_level, format, ## arg)
158static const char *str_supported(int is_supported);
159#else
160#define vdbg_printk(a_dbg_level, format, arg...)
161#endif
110 162
111/* Ancient thinkpad BIOSes have to be identified by 163#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off")
112 * BIOS type or model number, and there are far less 164#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
113 * BIOS types than model numbers... */ 165#define strlencmp(a, b) (strncmp((a), (b), strlen(b)))
114IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); 166
115IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); 167
116IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); 168/****************************************************************************
169 * Driver-wide structs and misc. variables
170 */
171
172struct ibm_struct;
173
174struct tp_acpi_drv_struct {
175 const struct acpi_device_id *hid;
176 struct acpi_driver *driver;
117 177
118#define __unused __attribute__ ((unused)) 178 void (*notify) (struct ibm_struct *, u32);
179 acpi_handle *handle;
180 u32 type;
181 struct acpi_device *device;
182};
183
184struct ibm_struct {
185 char *name;
186
187 int (*read) (char *);
188 int (*write) (char *);
189 void (*exit) (void);
190 void (*resume) (void);
191 void (*suspend) (pm_message_t state);
192
193 struct list_head all_drivers;
194
195 struct tp_acpi_drv_struct *acpi;
196
197 struct {
198 u8 acpi_driver_registered:1;
199 u8 acpi_notify_installed:1;
200 u8 proc_created:1;
201 u8 init_called:1;
202 u8 experimental:1;
203 } flags;
204};
205
206struct ibm_init_struct {
207 char param[32];
208
209 int (*init) (struct ibm_init_struct *);
210 struct ibm_struct *data;
211};
212
213static struct {
214#ifdef CONFIG_THINKPAD_ACPI_BAY
215 u32 bay_status:1;
216 u32 bay_eject:1;
217 u32 bay_status2:1;
218 u32 bay_eject2:1;
219#endif
220 u32 bluetooth:1;
221 u32 hotkey:1;
222 u32 hotkey_mask:1;
223 u32 hotkey_wlsw:1;
224 u32 light:1;
225 u32 light_status:1;
226 u32 bright_16levels:1;
227 u32 wan:1;
228 u32 fan_ctrl_status_undef:1;
229 u32 input_device_registered:1;
230 u32 platform_drv_registered:1;
231 u32 platform_drv_attrs_registered:1;
232 u32 sensors_pdrv_registered:1;
233 u32 sensors_pdrv_attrs_registered:1;
234 u32 sensors_pdev_attrs_registered:1;
235 u32 hotkey_poll_active:1;
236} tp_features;
237
238struct thinkpad_id_data {
239 unsigned int vendor; /* ThinkPad vendor:
240 * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
241
242 char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
243 char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
244
245 u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
246 u16 ec_model;
247
248 char *model_str;
249};
250static struct thinkpad_id_data thinkpad_id;
119 251
120static enum { 252static enum {
121 TPACPI_LIFE_INIT = 0, 253 TPACPI_LIFE_INIT = 0,
@@ -123,6 +255,9 @@ static enum {
123 TPACPI_LIFE_EXITING, 255 TPACPI_LIFE_EXITING,
124} tpacpi_lifecycle; 256} tpacpi_lifecycle;
125 257
258static int experimental;
259static u32 dbg_level;
260
126/**************************************************************************** 261/****************************************************************************
127 **************************************************************************** 262 ****************************************************************************
128 * 263 *
@@ -137,13 +272,13 @@ static enum {
137 272
138static acpi_handle root_handle; 273static acpi_handle root_handle;
139 274
140#define IBM_HANDLE(object, parent, paths...) \ 275#define TPACPI_HANDLE(object, parent, paths...) \
141 static acpi_handle object##_handle; \ 276 static acpi_handle object##_handle; \
142 static acpi_handle *object##_parent = &parent##_handle; \ 277 static acpi_handle *object##_parent = &parent##_handle; \
143 static char *object##_path; \ 278 static char *object##_path; \
144 static char *object##_paths[] = { paths } 279 static char *object##_paths[] = { paths }
145 280
146IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ 281TPACPI_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
147 "\\_SB.PCI.ISA.EC", /* 570 */ 282 "\\_SB.PCI.ISA.EC", /* 570 */
148 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ 283 "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
149 "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ 284 "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
@@ -152,20 +287,16 @@ IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
152 "\\_SB.PCI0.LPC.EC", /* all others */ 287 "\\_SB.PCI0.LPC.EC", /* all others */
153 ); 288 );
154 289
155IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ 290TPACPI_HANDLE(ecrd, ec, "ECRD"); /* 570 */
156IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ 291TPACPI_HANDLE(ecwr, ec, "ECWR"); /* 570 */
157
158
159/*************************************************************************
160 * Misc ACPI handles
161 */
162 292
163IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ 293TPACPI_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, */
294 /* T4x, X31, X40 */
164 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ 295 "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
165 "\\CMS", /* R40, R40e */ 296 "\\CMS", /* R40, R40e */
166 ); /* all others */ 297 ); /* all others */
167 298
168IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ 299TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
169 "^HKEY", /* R30, R31 */ 300 "^HKEY", /* R30, R31 */
170 "HKEY", /* all others */ 301 "HKEY", /* all others */
171 ); /* 570 */ 302 ); /* 570 */
@@ -180,7 +311,7 @@ static int acpi_evalf(acpi_handle handle,
180{ 311{
181 char *fmt0 = fmt; 312 char *fmt0 = fmt;
182 struct acpi_object_list params; 313 struct acpi_object_list params;
183 union acpi_object in_objs[IBM_MAX_ACPI_ARGS]; 314 union acpi_object in_objs[TPACPI_MAX_ACPI_ARGS];
184 struct acpi_buffer result, *resultp; 315 struct acpi_buffer result, *resultp;
185 union acpi_object out_obj; 316 union acpi_object out_obj;
186 acpi_status status; 317 acpi_status status;
@@ -190,7 +321,7 @@ static int acpi_evalf(acpi_handle handle,
190 int quiet; 321 int quiet;
191 322
192 if (!*fmt) { 323 if (!*fmt) {
193 printk(IBM_ERR "acpi_evalf() called with empty format\n"); 324 printk(TPACPI_ERR "acpi_evalf() called with empty format\n");
194 return 0; 325 return 0;
195 } 326 }
196 327
@@ -215,7 +346,7 @@ static int acpi_evalf(acpi_handle handle,
215 break; 346 break;
216 /* add more types as needed */ 347 /* add more types as needed */
217 default: 348 default:
218 printk(IBM_ERR "acpi_evalf() called " 349 printk(TPACPI_ERR "acpi_evalf() called "
219 "with invalid format character '%c'\n", c); 350 "with invalid format character '%c'\n", c);
220 return 0; 351 return 0;
221 } 352 }
@@ -242,29 +373,19 @@ static int acpi_evalf(acpi_handle handle,
242 break; 373 break;
243 /* add more types as needed */ 374 /* add more types as needed */
244 default: 375 default:
245 printk(IBM_ERR "acpi_evalf() called " 376 printk(TPACPI_ERR "acpi_evalf() called "
246 "with invalid format character '%c'\n", res_type); 377 "with invalid format character '%c'\n", res_type);
247 return 0; 378 return 0;
248 } 379 }
249 380
250 if (!success && !quiet) 381 if (!success && !quiet)
251 printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", 382 printk(TPACPI_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
252 method, fmt0, status); 383 method, fmt0, status);
253 384
254 return success; 385 return success;
255} 386}
256 387
257static void __unused acpi_print_int(acpi_handle handle, char *method) 388static int acpi_ec_read(int i, u8 *p)
258{
259 int i;
260
261 if (acpi_evalf(handle, &i, method, "d"))
262 printk(IBM_INFO "%s = 0x%x\n", method, i);
263 else
264 printk(IBM_ERR "error calling %s\n", method);
265}
266
267static int acpi_ec_read(int i, u8 * p)
268{ 389{
269 int v; 390 int v;
270 391
@@ -293,6 +414,7 @@ static int acpi_ec_write(int i, u8 v)
293 return 1; 414 return 1;
294} 415}
295 416
417#if defined(CONFIG_THINKPAD_ACPI_DOCK) || defined(CONFIG_THINKPAD_ACPI_BAY)
296static int _sta(acpi_handle handle) 418static int _sta(acpi_handle handle)
297{ 419{
298 int status; 420 int status;
@@ -302,6 +424,7 @@ static int _sta(acpi_handle handle)
302 424
303 return status; 425 return status;
304} 426}
427#endif
305 428
306static int issue_thinkpad_cmos_command(int cmos_cmd) 429static int issue_thinkpad_cmos_command(int cmos_cmd)
307{ 430{
@@ -318,6 +441,10 @@ static int issue_thinkpad_cmos_command(int cmos_cmd)
318 * ACPI device model 441 * ACPI device model
319 */ 442 */
320 443
444#define TPACPI_ACPIHANDLE_INIT(object) \
445 drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
446 object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
447
321static void drv_acpi_handle_init(char *name, 448static void drv_acpi_handle_init(char *name,
322 acpi_handle *handle, acpi_handle parent, 449 acpi_handle *handle, acpi_handle parent,
323 char **paths, int num_paths, char **path) 450 char **paths, int num_paths, char **path)
@@ -372,25 +499,27 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
372 499
373 rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); 500 rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
374 if (rc < 0) { 501 if (rc < 0) {
375 printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n", 502 printk(TPACPI_ERR "acpi_bus_get_device(%s) failed: %d\n",
376 ibm->name, rc); 503 ibm->name, rc);
377 return -ENODEV; 504 return -ENODEV;
378 } 505 }
379 506
380 acpi_driver_data(ibm->acpi->device) = ibm; 507 acpi_driver_data(ibm->acpi->device) = ibm;
381 sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", 508 sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
382 IBM_ACPI_EVENT_PREFIX, 509 TPACPI_ACPI_EVENT_PREFIX,
383 ibm->name); 510 ibm->name);
384 511
385 status = acpi_install_notify_handler(*ibm->acpi->handle, 512 status = acpi_install_notify_handler(*ibm->acpi->handle,
386 ibm->acpi->type, dispatch_acpi_notify, ibm); 513 ibm->acpi->type, dispatch_acpi_notify, ibm);
387 if (ACPI_FAILURE(status)) { 514 if (ACPI_FAILURE(status)) {
388 if (status == AE_ALREADY_EXISTS) { 515 if (status == AE_ALREADY_EXISTS) {
389 printk(IBM_NOTICE "another device driver is already handling %s events\n", 516 printk(TPACPI_NOTICE
390 ibm->name); 517 "another device driver is already "
518 "handling %s events\n", ibm->name);
391 } else { 519 } else {
392 printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n", 520 printk(TPACPI_ERR
393 ibm->name, status); 521 "acpi_install_notify_handler(%s) failed: %d\n",
522 ibm->name, status);
394 } 523 }
395 return -ENODEV; 524 return -ENODEV;
396 } 525 }
@@ -414,18 +543,18 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
414 543
415 ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); 544 ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
416 if (!ibm->acpi->driver) { 545 if (!ibm->acpi->driver) {
417 printk(IBM_ERR "kzalloc(ibm->driver) failed\n"); 546 printk(TPACPI_ERR "kzalloc(ibm->driver) failed\n");
418 return -ENOMEM; 547 return -ENOMEM;
419 } 548 }
420 549
421 sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); 550 sprintf(ibm->acpi->driver->name, "%s_%s", TPACPI_NAME, ibm->name);
422 ibm->acpi->driver->ids = ibm->acpi->hid; 551 ibm->acpi->driver->ids = ibm->acpi->hid;
423 552
424 ibm->acpi->driver->ops.add = &tpacpi_device_add; 553 ibm->acpi->driver->ops.add = &tpacpi_device_add;
425 554
426 rc = acpi_bus_register_driver(ibm->acpi->driver); 555 rc = acpi_bus_register_driver(ibm->acpi->driver);
427 if (rc < 0) { 556 if (rc < 0) {
428 printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", 557 printk(TPACPI_ERR "acpi_bus_register_driver(%s) failed: %d\n",
429 ibm->name, rc); 558 ibm->name, rc);
430 kfree(ibm->acpi->driver); 559 kfree(ibm->acpi->driver);
431 ibm->acpi->driver = NULL; 560 ibm->acpi->driver = NULL;
@@ -470,7 +599,7 @@ static int dispatch_procfs_read(char *page, char **start, off_t off,
470} 599}
471 600
472static int dispatch_procfs_write(struct file *file, 601static int dispatch_procfs_write(struct file *file,
473 const char __user * userbuf, 602 const char __user *userbuf,
474 unsigned long count, void *data) 603 unsigned long count, void *data)
475{ 604{
476 struct ibm_struct *ibm = data; 605 struct ibm_struct *ibm = data;
@@ -530,7 +659,22 @@ static struct platform_device *tpacpi_sensors_pdev;
530static struct device *tpacpi_hwmon; 659static struct device *tpacpi_hwmon;
531static struct input_dev *tpacpi_inputdev; 660static struct input_dev *tpacpi_inputdev;
532static struct mutex tpacpi_inputdev_send_mutex; 661static struct mutex tpacpi_inputdev_send_mutex;
662static LIST_HEAD(tpacpi_all_drivers);
663
664static int tpacpi_suspend_handler(struct platform_device *pdev,
665 pm_message_t state)
666{
667 struct ibm_struct *ibm, *itmp;
668
669 list_for_each_entry_safe(ibm, itmp,
670 &tpacpi_all_drivers,
671 all_drivers) {
672 if (ibm->suspend)
673 (ibm->suspend)(state);
674 }
533 675
676 return 0;
677}
534 678
535static int tpacpi_resume_handler(struct platform_device *pdev) 679static int tpacpi_resume_handler(struct platform_device *pdev)
536{ 680{
@@ -548,107 +692,36 @@ static int tpacpi_resume_handler(struct platform_device *pdev)
548 692
549static struct platform_driver tpacpi_pdriver = { 693static struct platform_driver tpacpi_pdriver = {
550 .driver = { 694 .driver = {
551 .name = IBM_DRVR_NAME, 695 .name = TPACPI_DRVR_NAME,
552 .owner = THIS_MODULE, 696 .owner = THIS_MODULE,
553 }, 697 },
698 .suspend = tpacpi_suspend_handler,
554 .resume = tpacpi_resume_handler, 699 .resume = tpacpi_resume_handler,
555}; 700};
556 701
557static struct platform_driver tpacpi_hwmon_pdriver = { 702static struct platform_driver tpacpi_hwmon_pdriver = {
558 .driver = { 703 .driver = {
559 .name = IBM_HWMON_DRVR_NAME, 704 .name = TPACPI_HWMON_DRVR_NAME,
560 .owner = THIS_MODULE, 705 .owner = THIS_MODULE,
561 }, 706 },
562}; 707};
563 708
564/************************************************************************* 709/*************************************************************************
565 * thinkpad-acpi driver attributes 710 * sysfs support helpers
566 */ 711 */
567 712
568/* interface_version --------------------------------------------------- */ 713struct attribute_set {
569static ssize_t tpacpi_driver_interface_version_show( 714 unsigned int members, max_members;
570 struct device_driver *drv, 715 struct attribute_group group;
571 char *buf)
572{
573 return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
574}
575
576static DRIVER_ATTR(interface_version, S_IRUGO,
577 tpacpi_driver_interface_version_show, NULL);
578
579/* debug_level --------------------------------------------------------- */
580static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
581 char *buf)
582{
583 return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
584}
585
586static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
587 const char *buf, size_t count)
588{
589 unsigned long t;
590
591 if (parse_strtoul(buf, 0xffff, &t))
592 return -EINVAL;
593
594 dbg_level = t;
595
596 return count;
597}
598
599static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
600 tpacpi_driver_debug_show, tpacpi_driver_debug_store);
601
602/* version ------------------------------------------------------------- */
603static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
604 char *buf)
605{
606 return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
607}
608
609static DRIVER_ATTR(version, S_IRUGO,
610 tpacpi_driver_version_show, NULL);
611
612/* --------------------------------------------------------------------- */
613
614static struct driver_attribute* tpacpi_driver_attributes[] = {
615 &driver_attr_debug_level, &driver_attr_version,
616 &driver_attr_interface_version,
617}; 716};
618 717
619static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
620{
621 int i, res;
622
623 i = 0;
624 res = 0;
625 while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
626 res = driver_create_file(drv, tpacpi_driver_attributes[i]);
627 i++;
628 }
629
630 return res;
631}
632
633static void tpacpi_remove_driver_attributes(struct device_driver *drv)
634{
635 int i;
636
637 for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
638 driver_remove_file(drv, tpacpi_driver_attributes[i]);
639}
640
641/*************************************************************************
642 * sysfs support helpers
643 */
644
645struct attribute_set_obj { 718struct attribute_set_obj {
646 struct attribute_set s; 719 struct attribute_set s;
647 struct attribute *a; 720 struct attribute *a;
648} __attribute__((packed)); 721} __attribute__((packed));
649 722
650static struct attribute_set *create_attr_set(unsigned int max_members, 723static struct attribute_set *create_attr_set(unsigned int max_members,
651 const char* name) 724 const char *name)
652{ 725{
653 struct attribute_set_obj *sobj; 726 struct attribute_set_obj *sobj;
654 727
@@ -668,8 +741,11 @@ static struct attribute_set *create_attr_set(unsigned int max_members,
668 return &sobj->s; 741 return &sobj->s;
669} 742}
670 743
744#define destroy_attr_set(_set) \
745 kfree(_set);
746
671/* not multi-threaded safe, use it in a single thread per set */ 747/* not multi-threaded safe, use it in a single thread per set */
672static int add_to_attr_set(struct attribute_set* s, struct attribute *attr) 748static int add_to_attr_set(struct attribute_set *s, struct attribute *attr)
673{ 749{
674 if (!s || !attr) 750 if (!s || !attr)
675 return -EINVAL; 751 return -EINVAL;
@@ -683,7 +759,7 @@ static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
683 return 0; 759 return 0;
684} 760}
685 761
686static int add_many_to_attr_set(struct attribute_set* s, 762static int add_many_to_attr_set(struct attribute_set *s,
687 struct attribute **attr, 763 struct attribute **attr,
688 unsigned int count) 764 unsigned int count)
689{ 765{
@@ -698,12 +774,15 @@ static int add_many_to_attr_set(struct attribute_set* s,
698 return 0; 774 return 0;
699} 775}
700 776
701static void delete_attr_set(struct attribute_set* s, struct kobject *kobj) 777static void delete_attr_set(struct attribute_set *s, struct kobject *kobj)
702{ 778{
703 sysfs_remove_group(kobj, &s->group); 779 sysfs_remove_group(kobj, &s->group);
704 destroy_attr_set(s); 780 destroy_attr_set(s);
705} 781}
706 782
783#define register_attr_set_with_sysfs(_attr_set, _kobj) \
784 sysfs_create_group(_kobj, &_attr_set->group)
785
707static int parse_strtoul(const char *buf, 786static int parse_strtoul(const char *buf,
708 unsigned long max, unsigned long *value) 787 unsigned long max, unsigned long *value)
709{ 788{
@@ -720,6 +799,84 @@ static int parse_strtoul(const char *buf,
720 return 0; 799 return 0;
721} 800}
722 801
802/*************************************************************************
803 * thinkpad-acpi driver attributes
804 */
805
806/* interface_version --------------------------------------------------- */
807static ssize_t tpacpi_driver_interface_version_show(
808 struct device_driver *drv,
809 char *buf)
810{
811 return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
812}
813
814static DRIVER_ATTR(interface_version, S_IRUGO,
815 tpacpi_driver_interface_version_show, NULL);
816
817/* debug_level --------------------------------------------------------- */
818static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
819 char *buf)
820{
821 return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
822}
823
824static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
825 const char *buf, size_t count)
826{
827 unsigned long t;
828
829 if (parse_strtoul(buf, 0xffff, &t))
830 return -EINVAL;
831
832 dbg_level = t;
833
834 return count;
835}
836
837static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
838 tpacpi_driver_debug_show, tpacpi_driver_debug_store);
839
840/* version ------------------------------------------------------------- */
841static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
842 char *buf)
843{
844 return snprintf(buf, PAGE_SIZE, "%s v%s\n",
845 TPACPI_DESC, TPACPI_VERSION);
846}
847
848static DRIVER_ATTR(version, S_IRUGO,
849 tpacpi_driver_version_show, NULL);
850
851/* --------------------------------------------------------------------- */
852
853static struct driver_attribute *tpacpi_driver_attributes[] = {
854 &driver_attr_debug_level, &driver_attr_version,
855 &driver_attr_interface_version,
856};
857
858static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
859{
860 int i, res;
861
862 i = 0;
863 res = 0;
864 while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
865 res = driver_create_file(drv, tpacpi_driver_attributes[i]);
866 i++;
867 }
868
869 return res;
870}
871
872static void tpacpi_remove_driver_attributes(struct device_driver *drv)
873{
874 int i;
875
876 for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
877 driver_remove_file(drv, tpacpi_driver_attributes[i]);
878}
879
723/**************************************************************************** 880/****************************************************************************
724 **************************************************************************** 881 ****************************************************************************
725 * 882 *
@@ -734,17 +891,17 @@ static int parse_strtoul(const char *buf,
734 891
735static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) 892static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
736{ 893{
737 printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); 894 printk(TPACPI_INFO "%s v%s\n", TPACPI_DESC, TPACPI_VERSION);
738 printk(IBM_INFO "%s\n", IBM_URL); 895 printk(TPACPI_INFO "%s\n", TPACPI_URL);
739 896
740 printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n", 897 printk(TPACPI_INFO "ThinkPad BIOS %s, EC %s\n",
741 (thinkpad_id.bios_version_str) ? 898 (thinkpad_id.bios_version_str) ?
742 thinkpad_id.bios_version_str : "unknown", 899 thinkpad_id.bios_version_str : "unknown",
743 (thinkpad_id.ec_version_str) ? 900 (thinkpad_id.ec_version_str) ?
744 thinkpad_id.ec_version_str : "unknown"); 901 thinkpad_id.ec_version_str : "unknown");
745 902
746 if (thinkpad_id.vendor && thinkpad_id.model_str) 903 if (thinkpad_id.vendor && thinkpad_id.model_str)
747 printk(IBM_INFO "%s %s\n", 904 printk(TPACPI_INFO "%s %s\n",
748 (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? 905 (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
749 "IBM" : ((thinkpad_id.vendor == 906 "IBM" : ((thinkpad_id.vendor ==
750 PCI_VENDOR_ID_LENOVO) ? 907 PCI_VENDOR_ID_LENOVO) ?
@@ -758,8 +915,8 @@ static int thinkpad_acpi_driver_read(char *p)
758{ 915{
759 int len = 0; 916 int len = 0;
760 917
761 len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC); 918 len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC);
762 len += sprintf(p + len, "version:\t%s\n", IBM_VERSION); 919 len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION);
763 920
764 return len; 921 return len;
765} 922}
@@ -773,15 +930,129 @@ static struct ibm_struct thinkpad_acpi_driver_data = {
773 * Hotkey subdriver 930 * Hotkey subdriver
774 */ 931 */
775 932
933enum { /* hot key scan codes (derived from ACPI DSDT) */
934 TP_ACPI_HOTKEYSCAN_FNF1 = 0,
935 TP_ACPI_HOTKEYSCAN_FNF2,
936 TP_ACPI_HOTKEYSCAN_FNF3,
937 TP_ACPI_HOTKEYSCAN_FNF4,
938 TP_ACPI_HOTKEYSCAN_FNF5,
939 TP_ACPI_HOTKEYSCAN_FNF6,
940 TP_ACPI_HOTKEYSCAN_FNF7,
941 TP_ACPI_HOTKEYSCAN_FNF8,
942 TP_ACPI_HOTKEYSCAN_FNF9,
943 TP_ACPI_HOTKEYSCAN_FNF10,
944 TP_ACPI_HOTKEYSCAN_FNF11,
945 TP_ACPI_HOTKEYSCAN_FNF12,
946 TP_ACPI_HOTKEYSCAN_FNBACKSPACE,
947 TP_ACPI_HOTKEYSCAN_FNINSERT,
948 TP_ACPI_HOTKEYSCAN_FNDELETE,
949 TP_ACPI_HOTKEYSCAN_FNHOME,
950 TP_ACPI_HOTKEYSCAN_FNEND,
951 TP_ACPI_HOTKEYSCAN_FNPAGEUP,
952 TP_ACPI_HOTKEYSCAN_FNPAGEDOWN,
953 TP_ACPI_HOTKEYSCAN_FNSPACE,
954 TP_ACPI_HOTKEYSCAN_VOLUMEUP,
955 TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
956 TP_ACPI_HOTKEYSCAN_MUTE,
957 TP_ACPI_HOTKEYSCAN_THINKPAD,
958};
959
960enum { /* Keys available through NVRAM polling */
961 TPACPI_HKEY_NVRAM_KNOWN_MASK = 0x00fb88c0U,
962 TPACPI_HKEY_NVRAM_GOOD_MASK = 0x00fb8000U,
963};
964
965enum { /* Positions of some of the keys in hotkey masks */
966 TP_ACPI_HKEY_DISPSWTCH_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF7,
967 TP_ACPI_HKEY_DISPXPAND_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF8,
968 TP_ACPI_HKEY_HIBERNATE_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF12,
969 TP_ACPI_HKEY_BRGHTUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNHOME,
970 TP_ACPI_HKEY_BRGHTDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNEND,
971 TP_ACPI_HKEY_THNKLGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP,
972 TP_ACPI_HKEY_ZOOM_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE,
973 TP_ACPI_HKEY_VOLUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP,
974 TP_ACPI_HKEY_VOLDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN,
975 TP_ACPI_HKEY_MUTE_MASK = 1 << TP_ACPI_HOTKEYSCAN_MUTE,
976 TP_ACPI_HKEY_THINKPAD_MASK = 1 << TP_ACPI_HOTKEYSCAN_THINKPAD,
977};
978
979enum { /* NVRAM to ACPI HKEY group map */
980 TP_NVRAM_HKEY_GROUP_HK2 = TP_ACPI_HKEY_THINKPAD_MASK |
981 TP_ACPI_HKEY_ZOOM_MASK |
982 TP_ACPI_HKEY_DISPSWTCH_MASK |
983 TP_ACPI_HKEY_HIBERNATE_MASK,
984 TP_NVRAM_HKEY_GROUP_BRIGHTNESS = TP_ACPI_HKEY_BRGHTUP_MASK |
985 TP_ACPI_HKEY_BRGHTDWN_MASK,
986 TP_NVRAM_HKEY_GROUP_VOLUME = TP_ACPI_HKEY_VOLUP_MASK |
987 TP_ACPI_HKEY_VOLDWN_MASK |
988 TP_ACPI_HKEY_MUTE_MASK,
989};
990
991#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
992struct tp_nvram_state {
993 u16 thinkpad_toggle:1;
994 u16 zoom_toggle:1;
995 u16 display_toggle:1;
996 u16 thinklight_toggle:1;
997 u16 hibernate_toggle:1;
998 u16 displayexp_toggle:1;
999 u16 display_state:1;
1000 u16 brightness_toggle:1;
1001 u16 volume_toggle:1;
1002 u16 mute:1;
1003
1004 u8 brightness_level;
1005 u8 volume_level;
1006};
1007
1008static struct task_struct *tpacpi_hotkey_task;
1009static u32 hotkey_source_mask; /* bit mask 0=ACPI,1=NVRAM */
1010static int hotkey_poll_freq = 10; /* Hz */
1011static struct mutex hotkey_thread_mutex;
1012static struct mutex hotkey_thread_data_mutex;
1013static unsigned int hotkey_config_change;
1014
1015#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1016
1017#define hotkey_source_mask 0U
1018
1019#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1020
1021static struct mutex hotkey_mutex;
1022
1023static enum { /* Reasons for waking up */
1024 TP_ACPI_WAKEUP_NONE = 0, /* None or unknown */
1025 TP_ACPI_WAKEUP_BAYEJ, /* Bay ejection request */
1026 TP_ACPI_WAKEUP_UNDOCK, /* Undock request */
1027} hotkey_wakeup_reason;
1028
1029static int hotkey_autosleep_ack;
1030
776static int hotkey_orig_status; 1031static int hotkey_orig_status;
777static u32 hotkey_orig_mask; 1032static u32 hotkey_orig_mask;
778static u32 hotkey_all_mask; 1033static u32 hotkey_all_mask;
779static u32 hotkey_reserved_mask; 1034static u32 hotkey_reserved_mask;
1035static u32 hotkey_mask;
1036
1037static unsigned int hotkey_report_mode;
780 1038
781static u16 *hotkey_keycode_map; 1039static u16 *hotkey_keycode_map;
782 1040
783static struct attribute_set *hotkey_dev_attributes; 1041static struct attribute_set *hotkey_dev_attributes;
784 1042
1043#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1044#define HOTKEY_CONFIG_CRITICAL_START \
1045 do { \
1046 mutex_lock(&hotkey_thread_data_mutex); \
1047 hotkey_config_change++; \
1048 } while (0);
1049#define HOTKEY_CONFIG_CRITICAL_END \
1050 mutex_unlock(&hotkey_thread_data_mutex);
1051#else
1052#define HOTKEY_CONFIG_CRITICAL_START
1053#define HOTKEY_CONFIG_CRITICAL_END
1054#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1055
785static int hotkey_get_wlsw(int *status) 1056static int hotkey_get_wlsw(int *status)
786{ 1057{
787 if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) 1058 if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@@ -789,15 +1060,400 @@ static int hotkey_get_wlsw(int *status)
789 return 0; 1060 return 0;
790} 1061}
791 1062
1063/*
1064 * Call with hotkey_mutex held
1065 */
1066static int hotkey_mask_get(void)
1067{
1068 u32 m = 0;
1069
1070 if (tp_features.hotkey_mask) {
1071 if (!acpi_evalf(hkey_handle, &m, "DHKN", "d"))
1072 return -EIO;
1073 }
1074 hotkey_mask = m | (hotkey_source_mask & hotkey_mask);
1075
1076 return 0;
1077}
1078
1079/*
1080 * Call with hotkey_mutex held
1081 */
1082static int hotkey_mask_set(u32 mask)
1083{
1084 int i;
1085 int rc = 0;
1086
1087 if (tp_features.hotkey_mask) {
1088 HOTKEY_CONFIG_CRITICAL_START
1089 for (i = 0; i < 32; i++) {
1090 u32 m = 1 << i;
1091 /* enable in firmware mask only keys not in NVRAM
1092 * mode, but enable the key in the cached hotkey_mask
1093 * regardless of mode, or the key will end up
1094 * disabled by hotkey_mask_get() */
1095 if (!acpi_evalf(hkey_handle,
1096 NULL, "MHKM", "vdd", i + 1,
1097 !!((mask & ~hotkey_source_mask) & m))) {
1098 rc = -EIO;
1099 break;
1100 } else {
1101 hotkey_mask = (hotkey_mask & ~m) | (mask & m);
1102 }
1103 }
1104 HOTKEY_CONFIG_CRITICAL_END
1105
1106 /* hotkey_mask_get must be called unconditionally below */
1107 if (!hotkey_mask_get() && !rc &&
1108 (hotkey_mask & ~hotkey_source_mask) !=
1109 (mask & ~hotkey_source_mask)) {
1110 printk(TPACPI_NOTICE
1111 "requested hot key mask 0x%08x, but "
1112 "firmware forced it to 0x%08x\n",
1113 mask, hotkey_mask);
1114 }
1115 } else {
1116#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1117 HOTKEY_CONFIG_CRITICAL_START
1118 hotkey_mask = mask & hotkey_source_mask;
1119 HOTKEY_CONFIG_CRITICAL_END
1120 hotkey_mask_get();
1121 if (hotkey_mask != mask) {
1122 printk(TPACPI_NOTICE
1123 "requested hot key mask 0x%08x, "
1124 "forced to 0x%08x (NVRAM poll mask is "
1125 "0x%08x): no firmware mask support\n",
1126 mask, hotkey_mask, hotkey_source_mask);
1127 }
1128#else
1129 hotkey_mask_get();
1130 rc = -ENXIO;
1131#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1132 }
1133
1134 return rc;
1135}
1136
1137static int hotkey_status_get(int *status)
1138{
1139 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
1140 return -EIO;
1141
1142 return 0;
1143}
1144
1145static int hotkey_status_set(int status)
1146{
1147 if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
1148 return -EIO;
1149
1150 return 0;
1151}
1152
1153static void tpacpi_input_send_radiosw(void)
1154{
1155 int wlsw;
1156
1157 mutex_lock(&tpacpi_inputdev_send_mutex);
1158
1159 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
1160 input_report_switch(tpacpi_inputdev,
1161 SW_RADIO, !!wlsw);
1162 input_sync(tpacpi_inputdev);
1163 }
1164
1165 mutex_unlock(&tpacpi_inputdev_send_mutex);
1166}
1167
1168static void tpacpi_input_send_key(unsigned int scancode)
1169{
1170 unsigned int keycode;
1171
1172 keycode = hotkey_keycode_map[scancode];
1173
1174 if (keycode != KEY_RESERVED) {
1175 mutex_lock(&tpacpi_inputdev_send_mutex);
1176
1177 input_report_key(tpacpi_inputdev, keycode, 1);
1178 if (keycode == KEY_UNKNOWN)
1179 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1180 scancode);
1181 input_sync(tpacpi_inputdev);
1182
1183 input_report_key(tpacpi_inputdev, keycode, 0);
1184 if (keycode == KEY_UNKNOWN)
1185 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1186 scancode);
1187 input_sync(tpacpi_inputdev);
1188
1189 mutex_unlock(&tpacpi_inputdev_send_mutex);
1190 }
1191}
1192
1193#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1194static struct tp_acpi_drv_struct ibm_hotkey_acpidriver;
1195
1196static void tpacpi_hotkey_send_key(unsigned int scancode)
1197{
1198 tpacpi_input_send_key(scancode);
1199 if (hotkey_report_mode < 2) {
1200 acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device,
1201 0x80, 0x1001 + scancode);
1202 }
1203}
1204
1205static void hotkey_read_nvram(struct tp_nvram_state *n, u32 m)
1206{
1207 u8 d;
1208
1209 if (m & TP_NVRAM_HKEY_GROUP_HK2) {
1210 d = nvram_read_byte(TP_NVRAM_ADDR_HK2);
1211 n->thinkpad_toggle = !!(d & TP_NVRAM_MASK_HKT_THINKPAD);
1212 n->zoom_toggle = !!(d & TP_NVRAM_MASK_HKT_ZOOM);
1213 n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY);
1214 n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE);
1215 }
1216 if (m & TP_ACPI_HKEY_THNKLGHT_MASK) {
1217 d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT);
1218 n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT);
1219 }
1220 if (m & TP_ACPI_HKEY_DISPXPAND_MASK) {
1221 d = nvram_read_byte(TP_NVRAM_ADDR_VIDEO);
1222 n->displayexp_toggle =
1223 !!(d & TP_NVRAM_MASK_HKT_DISPEXPND);
1224 }
1225 if (m & TP_NVRAM_HKEY_GROUP_BRIGHTNESS) {
1226 d = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS);
1227 n->brightness_level = (d & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
1228 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
1229 n->brightness_toggle =
1230 !!(d & TP_NVRAM_MASK_HKT_BRIGHTNESS);
1231 }
1232 if (m & TP_NVRAM_HKEY_GROUP_VOLUME) {
1233 d = nvram_read_byte(TP_NVRAM_ADDR_MIXER);
1234 n->volume_level = (d & TP_NVRAM_MASK_LEVEL_VOLUME)
1235 >> TP_NVRAM_POS_LEVEL_VOLUME;
1236 n->mute = !!(d & TP_NVRAM_MASK_MUTE);
1237 n->volume_toggle = !!(d & TP_NVRAM_MASK_HKT_VOLUME);
1238 }
1239}
1240
1241#define TPACPI_COMPARE_KEY(__scancode, __member) \
1242 do { \
1243 if ((mask & (1 << __scancode)) && \
1244 oldn->__member != newn->__member) \
1245 tpacpi_hotkey_send_key(__scancode); \
1246 } while (0)
1247
1248#define TPACPI_MAY_SEND_KEY(__scancode) \
1249 do { if (mask & (1 << __scancode)) \
1250 tpacpi_hotkey_send_key(__scancode); } while (0)
1251
1252static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
1253 struct tp_nvram_state *newn,
1254 u32 mask)
1255{
1256 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_THINKPAD, thinkpad_toggle);
1257 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNSPACE, zoom_toggle);
1258 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF7, display_toggle);
1259 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF12, hibernate_toggle);
1260
1261 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNPAGEUP, thinklight_toggle);
1262
1263 TPACPI_COMPARE_KEY(TP_ACPI_HOTKEYSCAN_FNF8, displayexp_toggle);
1264
1265 /* handle volume */
1266 if (oldn->volume_toggle != newn->volume_toggle) {
1267 if (oldn->mute != newn->mute) {
1268 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
1269 }
1270 if (oldn->volume_level > newn->volume_level) {
1271 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
1272 } else if (oldn->volume_level < newn->volume_level) {
1273 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
1274 } else if (oldn->mute == newn->mute) {
1275 /* repeated key presses that didn't change state */
1276 if (newn->mute) {
1277 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_MUTE);
1278 } else if (newn->volume_level != 0) {
1279 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEUP);
1280 } else {
1281 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_VOLUMEDOWN);
1282 }
1283 }
1284 }
1285
1286 /* handle brightness */
1287 if (oldn->brightness_toggle != newn->brightness_toggle) {
1288 if (oldn->brightness_level < newn->brightness_level) {
1289 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
1290 } else if (oldn->brightness_level > newn->brightness_level) {
1291 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
1292 } else {
1293 /* repeated key presses that didn't change state */
1294 if (newn->brightness_level != 0) {
1295 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNHOME);
1296 } else {
1297 TPACPI_MAY_SEND_KEY(TP_ACPI_HOTKEYSCAN_FNEND);
1298 }
1299 }
1300 }
1301}
1302
1303#undef TPACPI_COMPARE_KEY
1304#undef TPACPI_MAY_SEND_KEY
1305
1306static int hotkey_kthread(void *data)
1307{
1308 struct tp_nvram_state s[2];
1309 u32 mask;
1310 unsigned int si, so;
1311 unsigned long t;
1312 unsigned int change_detector, must_reset;
1313
1314 mutex_lock(&hotkey_thread_mutex);
1315
1316 if (tpacpi_lifecycle == TPACPI_LIFE_EXITING)
1317 goto exit;
1318
1319 set_freezable();
1320
1321 so = 0;
1322 si = 1;
1323 t = 0;
1324
1325 /* Initial state for compares */
1326 mutex_lock(&hotkey_thread_data_mutex);
1327 change_detector = hotkey_config_change;
1328 mask = hotkey_source_mask & hotkey_mask;
1329 mutex_unlock(&hotkey_thread_data_mutex);
1330 hotkey_read_nvram(&s[so], mask);
1331
1332 while (!kthread_should_stop() && hotkey_poll_freq) {
1333 if (t == 0)
1334 t = 1000/hotkey_poll_freq;
1335 t = msleep_interruptible(t);
1336 if (unlikely(kthread_should_stop()))
1337 break;
1338 must_reset = try_to_freeze();
1339 if (t > 0 && !must_reset)
1340 continue;
1341
1342 mutex_lock(&hotkey_thread_data_mutex);
1343 if (must_reset || hotkey_config_change != change_detector) {
1344 /* forget old state on thaw or config change */
1345 si = so;
1346 t = 0;
1347 change_detector = hotkey_config_change;
1348 }
1349 mask = hotkey_source_mask & hotkey_mask;
1350 mutex_unlock(&hotkey_thread_data_mutex);
1351
1352 if (likely(mask)) {
1353 hotkey_read_nvram(&s[si], mask);
1354 if (likely(si != so)) {
1355 hotkey_compare_and_issue_event(&s[so], &s[si],
1356 mask);
1357 }
1358 }
1359
1360 so = si;
1361 si ^= 1;
1362 }
1363
1364exit:
1365 mutex_unlock(&hotkey_thread_mutex);
1366 return 0;
1367}
1368
1369static void hotkey_poll_stop_sync(void)
1370{
1371 if (tpacpi_hotkey_task) {
1372 if (frozen(tpacpi_hotkey_task) ||
1373 freezing(tpacpi_hotkey_task))
1374 thaw_process(tpacpi_hotkey_task);
1375
1376 kthread_stop(tpacpi_hotkey_task);
1377 tpacpi_hotkey_task = NULL;
1378 mutex_lock(&hotkey_thread_mutex);
1379 /* at this point, the thread did exit */
1380 mutex_unlock(&hotkey_thread_mutex);
1381 }
1382}
1383
1384/* call with hotkey_mutex held */
1385static void hotkey_poll_setup(int may_warn)
1386{
1387 if ((hotkey_source_mask & hotkey_mask) != 0 &&
1388 hotkey_poll_freq > 0 &&
1389 (tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
1390 if (!tpacpi_hotkey_task) {
1391 tpacpi_hotkey_task = kthread_run(hotkey_kthread,
1392 NULL,
1393 TPACPI_FILE "d");
1394 if (IS_ERR(tpacpi_hotkey_task)) {
1395 tpacpi_hotkey_task = NULL;
1396 printk(TPACPI_ERR
1397 "could not create kernel thread "
1398 "for hotkey polling\n");
1399 }
1400 }
1401 } else {
1402 hotkey_poll_stop_sync();
1403 if (may_warn &&
1404 hotkey_source_mask != 0 && hotkey_poll_freq == 0) {
1405 printk(TPACPI_NOTICE
1406 "hot keys 0x%08x require polling, "
1407 "which is currently disabled\n",
1408 hotkey_source_mask);
1409 }
1410 }
1411}
1412
1413static void hotkey_poll_setup_safe(int may_warn)
1414{
1415 mutex_lock(&hotkey_mutex);
1416 hotkey_poll_setup(may_warn);
1417 mutex_unlock(&hotkey_mutex);
1418}
1419
1420static int hotkey_inputdev_open(struct input_dev *dev)
1421{
1422 switch (tpacpi_lifecycle) {
1423 case TPACPI_LIFE_INIT:
1424 /*
1425 * hotkey_init will call hotkey_poll_setup_safe
1426 * at the appropriate moment
1427 */
1428 return 0;
1429 case TPACPI_LIFE_EXITING:
1430 return -EBUSY;
1431 case TPACPI_LIFE_RUNNING:
1432 hotkey_poll_setup_safe(0);
1433 return 0;
1434 }
1435
1436 /* Should only happen if tpacpi_lifecycle is corrupt */
1437 BUG();
1438 return -EBUSY;
1439}
1440
1441static void hotkey_inputdev_close(struct input_dev *dev)
1442{
1443 /* disable hotkey polling when possible */
1444 if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
1445 hotkey_poll_setup_safe(0);
1446}
1447#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1448
792/* sysfs hotkey enable ------------------------------------------------- */ 1449/* sysfs hotkey enable ------------------------------------------------- */
793static ssize_t hotkey_enable_show(struct device *dev, 1450static ssize_t hotkey_enable_show(struct device *dev,
794 struct device_attribute *attr, 1451 struct device_attribute *attr,
795 char *buf) 1452 char *buf)
796{ 1453{
797 int res, status; 1454 int res, status;
798 u32 mask;
799 1455
800 res = hotkey_get(&status, &mask); 1456 res = hotkey_status_get(&status);
801 if (res) 1457 if (res)
802 return res; 1458 return res;
803 1459
@@ -809,15 +1465,12 @@ static ssize_t hotkey_enable_store(struct device *dev,
809 const char *buf, size_t count) 1465 const char *buf, size_t count)
810{ 1466{
811 unsigned long t; 1467 unsigned long t;
812 int res, status; 1468 int res;
813 u32 mask;
814 1469
815 if (parse_strtoul(buf, 1, &t)) 1470 if (parse_strtoul(buf, 1, &t))
816 return -EINVAL; 1471 return -EINVAL;
817 1472
818 res = hotkey_get(&status, &mask); 1473 res = hotkey_status_set(t);
819 if (!res)
820 res = hotkey_set(t, mask);
821 1474
822 return (res) ? res : count; 1475 return (res) ? res : count;
823} 1476}
@@ -831,14 +1484,15 @@ static ssize_t hotkey_mask_show(struct device *dev,
831 struct device_attribute *attr, 1484 struct device_attribute *attr,
832 char *buf) 1485 char *buf)
833{ 1486{
834 int res, status; 1487 int res;
835 u32 mask;
836 1488
837 res = hotkey_get(&status, &mask); 1489 if (mutex_lock_interruptible(&hotkey_mutex))
838 if (res) 1490 return -ERESTARTSYS;
839 return res; 1491 res = hotkey_mask_get();
1492 mutex_unlock(&hotkey_mutex);
840 1493
841 return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask); 1494 return (res)?
1495 res : snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_mask);
842} 1496}
843 1497
844static ssize_t hotkey_mask_store(struct device *dev, 1498static ssize_t hotkey_mask_store(struct device *dev,
@@ -846,15 +1500,21 @@ static ssize_t hotkey_mask_store(struct device *dev,
846 const char *buf, size_t count) 1500 const char *buf, size_t count)
847{ 1501{
848 unsigned long t; 1502 unsigned long t;
849 int res, status; 1503 int res;
850 u32 mask;
851 1504
852 if (parse_strtoul(buf, 0xffffffffUL, &t)) 1505 if (parse_strtoul(buf, 0xffffffffUL, &t))
853 return -EINVAL; 1506 return -EINVAL;
854 1507
855 res = hotkey_get(&status, &mask); 1508 if (mutex_lock_interruptible(&hotkey_mutex))
856 if (!res) 1509 return -ERESTARTSYS;
857 hotkey_set(status, t); 1510
1511 res = hotkey_mask_set(t);
1512
1513#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1514 hotkey_poll_setup(1);
1515#endif
1516
1517 mutex_unlock(&hotkey_mutex);
858 1518
859 return (res) ? res : count; 1519 return (res) ? res : count;
860} 1520}
@@ -890,7 +1550,8 @@ static ssize_t hotkey_all_mask_show(struct device *dev,
890 struct device_attribute *attr, 1550 struct device_attribute *attr,
891 char *buf) 1551 char *buf)
892{ 1552{
893 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask); 1553 return snprintf(buf, PAGE_SIZE, "0x%08x\n",
1554 hotkey_all_mask | hotkey_source_mask);
894} 1555}
895 1556
896static struct device_attribute dev_attr_hotkey_all_mask = 1557static struct device_attribute dev_attr_hotkey_all_mask =
@@ -902,14 +1563,87 @@ static ssize_t hotkey_recommended_mask_show(struct device *dev,
902 char *buf) 1563 char *buf)
903{ 1564{
904 return snprintf(buf, PAGE_SIZE, "0x%08x\n", 1565 return snprintf(buf, PAGE_SIZE, "0x%08x\n",
905 hotkey_all_mask & ~hotkey_reserved_mask); 1566 (hotkey_all_mask | hotkey_source_mask)
1567 & ~hotkey_reserved_mask);
906} 1568}
907 1569
908static struct device_attribute dev_attr_hotkey_recommended_mask = 1570static struct device_attribute dev_attr_hotkey_recommended_mask =
909 __ATTR(hotkey_recommended_mask, S_IRUGO, 1571 __ATTR(hotkey_recommended_mask, S_IRUGO,
910 hotkey_recommended_mask_show, NULL); 1572 hotkey_recommended_mask_show, NULL);
911 1573
912/* sysfs hotkey radio_sw ----------------------------------------------- */ 1574#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1575
1576/* sysfs hotkey hotkey_source_mask ------------------------------------- */
1577static ssize_t hotkey_source_mask_show(struct device *dev,
1578 struct device_attribute *attr,
1579 char *buf)
1580{
1581 return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_source_mask);
1582}
1583
1584static ssize_t hotkey_source_mask_store(struct device *dev,
1585 struct device_attribute *attr,
1586 const char *buf, size_t count)
1587{
1588 unsigned long t;
1589
1590 if (parse_strtoul(buf, 0xffffffffUL, &t) ||
1591 ((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0))
1592 return -EINVAL;
1593
1594 if (mutex_lock_interruptible(&hotkey_mutex))
1595 return -ERESTARTSYS;
1596
1597 HOTKEY_CONFIG_CRITICAL_START
1598 hotkey_source_mask = t;
1599 HOTKEY_CONFIG_CRITICAL_END
1600
1601 hotkey_poll_setup(1);
1602
1603 mutex_unlock(&hotkey_mutex);
1604
1605 return count;
1606}
1607
1608static struct device_attribute dev_attr_hotkey_source_mask =
1609 __ATTR(hotkey_source_mask, S_IWUSR | S_IRUGO,
1610 hotkey_source_mask_show, hotkey_source_mask_store);
1611
1612/* sysfs hotkey hotkey_poll_freq --------------------------------------- */
1613static ssize_t hotkey_poll_freq_show(struct device *dev,
1614 struct device_attribute *attr,
1615 char *buf)
1616{
1617 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_poll_freq);
1618}
1619
1620static ssize_t hotkey_poll_freq_store(struct device *dev,
1621 struct device_attribute *attr,
1622 const char *buf, size_t count)
1623{
1624 unsigned long t;
1625
1626 if (parse_strtoul(buf, 25, &t))
1627 return -EINVAL;
1628
1629 if (mutex_lock_interruptible(&hotkey_mutex))
1630 return -ERESTARTSYS;
1631
1632 hotkey_poll_freq = t;
1633
1634 hotkey_poll_setup(1);
1635 mutex_unlock(&hotkey_mutex);
1636
1637 return count;
1638}
1639
1640static struct device_attribute dev_attr_hotkey_poll_freq =
1641 __ATTR(hotkey_poll_freq, S_IWUSR | S_IRUGO,
1642 hotkey_poll_freq_show, hotkey_poll_freq_store);
1643
1644#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
1645
1646/* sysfs hotkey radio_sw (pollable) ------------------------------------ */
913static ssize_t hotkey_radio_sw_show(struct device *dev, 1647static ssize_t hotkey_radio_sw_show(struct device *dev,
914 struct device_attribute *attr, 1648 struct device_attribute *attr,
915 char *buf) 1649 char *buf)
@@ -925,6 +1659,13 @@ static ssize_t hotkey_radio_sw_show(struct device *dev,
925static struct device_attribute dev_attr_hotkey_radio_sw = 1659static struct device_attribute dev_attr_hotkey_radio_sw =
926 __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); 1660 __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
927 1661
1662static void hotkey_radio_sw_notify_change(void)
1663{
1664 if (tp_features.hotkey_wlsw)
1665 sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
1666 "hotkey_radio_sw");
1667}
1668
928/* sysfs hotkey report_mode -------------------------------------------- */ 1669/* sysfs hotkey report_mode -------------------------------------------- */
929static ssize_t hotkey_report_mode_show(struct device *dev, 1670static ssize_t hotkey_report_mode_show(struct device *dev,
930 struct device_attribute *attr, 1671 struct device_attribute *attr,
@@ -937,43 +1678,132 @@ static ssize_t hotkey_report_mode_show(struct device *dev,
937static struct device_attribute dev_attr_hotkey_report_mode = 1678static struct device_attribute dev_attr_hotkey_report_mode =
938 __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); 1679 __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
939 1680
1681/* sysfs wakeup reason (pollable) -------------------------------------- */
1682static ssize_t hotkey_wakeup_reason_show(struct device *dev,
1683 struct device_attribute *attr,
1684 char *buf)
1685{
1686 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_wakeup_reason);
1687}
1688
1689static struct device_attribute dev_attr_hotkey_wakeup_reason =
1690 __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL);
1691
1692void hotkey_wakeup_reason_notify_change(void)
1693{
1694 if (tp_features.hotkey_mask)
1695 sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
1696 "wakeup_reason");
1697}
1698
1699/* sysfs wakeup hotunplug_complete (pollable) -------------------------- */
1700static ssize_t hotkey_wakeup_hotunplug_complete_show(struct device *dev,
1701 struct device_attribute *attr,
1702 char *buf)
1703{
1704 return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_autosleep_ack);
1705}
1706
1707static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete =
1708 __ATTR(wakeup_hotunplug_complete, S_IRUGO,
1709 hotkey_wakeup_hotunplug_complete_show, NULL);
1710
1711void hotkey_wakeup_hotunplug_complete_notify_change(void)
1712{
1713 if (tp_features.hotkey_mask)
1714 sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
1715 "wakeup_hotunplug_complete");
1716}
1717
940/* --------------------------------------------------------------------- */ 1718/* --------------------------------------------------------------------- */
941 1719
942static struct attribute *hotkey_attributes[] __initdata = { 1720static struct attribute *hotkey_attributes[] __initdata = {
943 &dev_attr_hotkey_enable.attr, 1721 &dev_attr_hotkey_enable.attr,
1722 &dev_attr_hotkey_bios_enabled.attr,
944 &dev_attr_hotkey_report_mode.attr, 1723 &dev_attr_hotkey_report_mode.attr,
1724#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1725 &dev_attr_hotkey_mask.attr,
1726 &dev_attr_hotkey_all_mask.attr,
1727 &dev_attr_hotkey_recommended_mask.attr,
1728 &dev_attr_hotkey_source_mask.attr,
1729 &dev_attr_hotkey_poll_freq.attr,
1730#endif
945}; 1731};
946 1732
947static struct attribute *hotkey_mask_attributes[] __initdata = { 1733static struct attribute *hotkey_mask_attributes[] __initdata = {
948 &dev_attr_hotkey_mask.attr,
949 &dev_attr_hotkey_bios_enabled.attr,
950 &dev_attr_hotkey_bios_mask.attr, 1734 &dev_attr_hotkey_bios_mask.attr,
1735#ifndef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1736 &dev_attr_hotkey_mask.attr,
951 &dev_attr_hotkey_all_mask.attr, 1737 &dev_attr_hotkey_all_mask.attr,
952 &dev_attr_hotkey_recommended_mask.attr, 1738 &dev_attr_hotkey_recommended_mask.attr,
1739#endif
1740 &dev_attr_hotkey_wakeup_reason.attr,
1741 &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
953}; 1742};
954 1743
955static int __init hotkey_init(struct ibm_init_struct *iibm) 1744static int __init hotkey_init(struct ibm_init_struct *iibm)
956{ 1745{
957 1746 /* Requirements for changing the default keymaps:
1747 *
1748 * 1. Many of the keys are mapped to KEY_RESERVED for very
1749 * good reasons. Do not change them unless you have deep
1750 * knowledge on the IBM and Lenovo ThinkPad firmware for
1751 * the various ThinkPad models. The driver behaves
1752 * differently for KEY_RESERVED: such keys have their
1753 * hot key mask *unset* in mask_recommended, and also
1754 * in the initial hot key mask programmed into the
1755 * firmware at driver load time, which means the firm-
1756 * ware may react very differently if you change them to
1757 * something else;
1758 *
1759 * 2. You must be subscribed to the linux-thinkpad and
1760 * ibm-acpi-devel mailing lists, and you should read the
1761 * list archives since 2007 if you want to change the
1762 * keymaps. This requirement exists so that you will
1763 * know the past history of problems with the thinkpad-
1764 * acpi driver keymaps, and also that you will be
1765 * listening to any bug reports;
1766 *
1767 * 3. Do not send thinkpad-acpi specific patches directly to
1768 * for merging, *ever*. Send them to the linux-acpi
1769 * mailinglist for comments. Merging is to be done only
1770 * through acpi-test and the ACPI maintainer.
1771 *
1772 * If the above is too much to ask, don't change the keymap.
1773 * Ask the thinkpad-acpi maintainer to do it, instead.
1774 */
958 static u16 ibm_keycode_map[] __initdata = { 1775 static u16 ibm_keycode_map[] __initdata = {
959 /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ 1776 /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
960 KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, 1777 KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP,
961 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, 1778 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
962 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, 1779 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
963 /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ 1780
1781 /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */
964 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ 1782 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
965 KEY_UNKNOWN, /* 0x0D: FN+INSERT */ 1783 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
966 KEY_UNKNOWN, /* 0x0E: FN+DELETE */ 1784 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
1785
1786 /* brightness: firmware always reacts to them, unless
1787 * X.org did some tricks in the radeon BIOS scratch
1788 * registers of *some* models */
967 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ 1789 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
968 /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
969 KEY_RESERVED, /* 0x10: FN+END (brightness down) */ 1790 KEY_RESERVED, /* 0x10: FN+END (brightness down) */
1791
1792 /* Thinklight: firmware always react to it */
970 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ 1793 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
1794
971 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ 1795 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
972 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ 1796 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
1797
1798 /* Volume: firmware always react to it and reprograms
1799 * the built-in *extra* mixer. Never map it to control
1800 * another mixer by default. */
973 KEY_RESERVED, /* 0x14: VOLUME UP */ 1801 KEY_RESERVED, /* 0x14: VOLUME UP */
974 KEY_RESERVED, /* 0x15: VOLUME DOWN */ 1802 KEY_RESERVED, /* 0x15: VOLUME DOWN */
975 KEY_RESERVED, /* 0x16: MUTE */ 1803 KEY_RESERVED, /* 0x16: MUTE */
1804
976 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ 1805 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
1806
977 /* (assignments unknown, please report if found) */ 1807 /* (assignments unknown, please report if found) */
978 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 1808 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
979 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 1809 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -983,20 +1813,37 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
983 KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, 1813 KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP,
984 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, 1814 KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
985 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, 1815 KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
986 /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ 1816
1817 /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */
987 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ 1818 KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
988 KEY_UNKNOWN, /* 0x0D: FN+INSERT */ 1819 KEY_UNKNOWN, /* 0x0D: FN+INSERT */
989 KEY_UNKNOWN, /* 0x0E: FN+DELETE */ 1820 KEY_UNKNOWN, /* 0x0E: FN+DELETE */
1821
990 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ 1822 KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
991 /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
992 KEY_RESERVED, /* 0x10: FN+END (brightness down) */ 1823 KEY_RESERVED, /* 0x10: FN+END (brightness down) */
1824
993 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ 1825 KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
1826
994 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ 1827 KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
995 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ 1828 KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
1829
1830 /* Volume: z60/z61, T60 (BIOS version?): firmware always
1831 * react to it and reprograms the built-in *extra* mixer.
1832 * Never map it to control another mixer by default.
1833 *
1834 * T60?, T61, R60?, R61: firmware and EC tries to send
1835 * these over the regular keyboard, so these are no-ops,
1836 * but there are still weird bugs re. MUTE, so do not
1837 * change unless you get test reports from all Lenovo
1838 * models. May cause the BIOS to interfere with the
1839 * HDA mixer.
1840 */
996 KEY_RESERVED, /* 0x14: VOLUME UP */ 1841 KEY_RESERVED, /* 0x14: VOLUME UP */
997 KEY_RESERVED, /* 0x15: VOLUME DOWN */ 1842 KEY_RESERVED, /* 0x15: VOLUME DOWN */
998 KEY_RESERVED, /* 0x16: MUTE */ 1843 KEY_RESERVED, /* 0x16: MUTE */
1844
999 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ 1845 KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
1846
1000 /* (assignments unknown, please report if found) */ 1847 /* (assignments unknown, please report if found) */
1001 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 1848 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
1002 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, 1849 KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -1013,10 +1860,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1013 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); 1860 vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
1014 1861
1015 BUG_ON(!tpacpi_inputdev); 1862 BUG_ON(!tpacpi_inputdev);
1863 BUG_ON(tpacpi_inputdev->open != NULL ||
1864 tpacpi_inputdev->close != NULL);
1016 1865
1017 IBM_ACPIHANDLE_INIT(hkey); 1866 TPACPI_ACPIHANDLE_INIT(hkey);
1018 mutex_init(&hotkey_mutex); 1867 mutex_init(&hotkey_mutex);
1019 1868
1869#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1870 mutex_init(&hotkey_thread_mutex);
1871 mutex_init(&hotkey_thread_data_mutex);
1872#endif
1873
1020 /* hotkey not supported on 570 */ 1874 /* hotkey not supported on 570 */
1021 tp_features.hotkey = hkey_handle != NULL; 1875 tp_features.hotkey = hkey_handle != NULL;
1022 1876
@@ -1024,7 +1878,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1024 str_supported(tp_features.hotkey)); 1878 str_supported(tp_features.hotkey));
1025 1879
1026 if (tp_features.hotkey) { 1880 if (tp_features.hotkey) {
1027 hotkey_dev_attributes = create_attr_set(8, NULL); 1881 hotkey_dev_attributes = create_attr_set(12, NULL);
1028 if (!hotkey_dev_attributes) 1882 if (!hotkey_dev_attributes)
1029 return -ENOMEM; 1883 return -ENOMEM;
1030 res = add_many_to_attr_set(hotkey_dev_attributes, 1884 res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1038,15 +1892,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1038 for HKEY interface version 0x100 */ 1892 for HKEY interface version 0x100 */
1039 if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { 1893 if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
1040 if ((hkeyv >> 8) != 1) { 1894 if ((hkeyv >> 8) != 1) {
1041 printk(IBM_ERR "unknown version of the " 1895 printk(TPACPI_ERR "unknown version of the "
1042 "HKEY interface: 0x%x\n", hkeyv); 1896 "HKEY interface: 0x%x\n", hkeyv);
1043 printk(IBM_ERR "please report this to %s\n", 1897 printk(TPACPI_ERR "please report this to %s\n",
1044 IBM_MAIL); 1898 TPACPI_MAIL);
1045 } else { 1899 } else {
1046 /* 1900 /*
1047 * MHKV 0x100 in A31, R40, R40e, 1901 * MHKV 0x100 in A31, R40, R40e,
1048 * T4x, X31, and later 1902 * T4x, X31, and later
1049 * */ 1903 */
1050 tp_features.hotkey_mask = 1; 1904 tp_features.hotkey_mask = 1;
1051 } 1905 }
1052 } 1906 }
@@ -1057,25 +1911,46 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1057 if (tp_features.hotkey_mask) { 1911 if (tp_features.hotkey_mask) {
1058 if (!acpi_evalf(hkey_handle, &hotkey_all_mask, 1912 if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
1059 "MHKA", "qd")) { 1913 "MHKA", "qd")) {
1060 printk(IBM_ERR 1914 printk(TPACPI_ERR
1061 "missing MHKA handler, " 1915 "missing MHKA handler, "
1062 "please report this to %s\n", 1916 "please report this to %s\n",
1063 IBM_MAIL); 1917 TPACPI_MAIL);
1064 hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ 1918 /* FN+F12, FN+F4, FN+F3 */
1919 hotkey_all_mask = 0x080cU;
1065 } 1920 }
1066 } 1921 }
1067 1922
1068 res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); 1923 /* hotkey_source_mask *must* be zero for
1924 * the first hotkey_mask_get */
1925 res = hotkey_status_get(&hotkey_orig_status);
1069 if (!res && tp_features.hotkey_mask) { 1926 if (!res && tp_features.hotkey_mask) {
1070 res = add_many_to_attr_set(hotkey_dev_attributes, 1927 res = hotkey_mask_get();
1071 hotkey_mask_attributes, 1928 hotkey_orig_mask = hotkey_mask;
1072 ARRAY_SIZE(hotkey_mask_attributes)); 1929 if (!res) {
1930 res = add_many_to_attr_set(
1931 hotkey_dev_attributes,
1932 hotkey_mask_attributes,
1933 ARRAY_SIZE(hotkey_mask_attributes));
1934 }
1935 }
1936
1937#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1938 if (tp_features.hotkey_mask) {
1939 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
1940 & ~hotkey_all_mask;
1941 } else {
1942 hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
1073 } 1943 }
1074 1944
1945 vdbg_printk(TPACPI_DBG_INIT,
1946 "hotkey source mask 0x%08x, polling freq %d\n",
1947 hotkey_source_mask, hotkey_poll_freq);
1948#endif
1949
1075 /* Not all thinkpads have a hardware radio switch */ 1950 /* Not all thinkpads have a hardware radio switch */
1076 if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { 1951 if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
1077 tp_features.hotkey_wlsw = 1; 1952 tp_features.hotkey_wlsw = 1;
1078 printk(IBM_INFO 1953 printk(TPACPI_INFO
1079 "radio switch found; radios are %s\n", 1954 "radio switch found; radios are %s\n",
1080 enabled(status, 0)); 1955 enabled(status, 0));
1081 res = add_to_attr_set(hotkey_dev_attributes, 1956 res = add_to_attr_set(hotkey_dev_attributes,
@@ -1094,7 +1969,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1094 hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, 1969 hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
1095 GFP_KERNEL); 1970 GFP_KERNEL);
1096 if (!hotkey_keycode_map) { 1971 if (!hotkey_keycode_map) {
1097 printk(IBM_ERR "failed to allocate memory for key map\n"); 1972 printk(TPACPI_ERR
1973 "failed to allocate memory for key map\n");
1098 return -ENOMEM; 1974 return -ENOMEM;
1099 } 1975 }
1100 1976
@@ -1133,15 +2009,26 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1133 2009
1134 dbg_printk(TPACPI_DBG_INIT, 2010 dbg_printk(TPACPI_DBG_INIT,
1135 "enabling hot key handling\n"); 2011 "enabling hot key handling\n");
1136 res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) 2012 res = hotkey_status_set(1);
1137 | hotkey_orig_mask);
1138 if (res) 2013 if (res)
1139 return res; 2014 return res;
2015 res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
2016 & ~hotkey_reserved_mask)
2017 | hotkey_orig_mask);
2018 if (res < 0 && res != -ENXIO)
2019 return res;
1140 2020
1141 dbg_printk(TPACPI_DBG_INIT, 2021 dbg_printk(TPACPI_DBG_INIT,
1142 "legacy hot key reporting over procfs %s\n", 2022 "legacy hot key reporting over procfs %s\n",
1143 (hotkey_report_mode < 2) ? 2023 (hotkey_report_mode < 2) ?
1144 "enabled" : "disabled"); 2024 "enabled" : "disabled");
2025
2026#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
2027 tpacpi_inputdev->open = &hotkey_inputdev_open;
2028 tpacpi_inputdev->close = &hotkey_inputdev_close;
2029
2030 hotkey_poll_setup_safe(1);
2031#endif
1145 } 2032 }
1146 2033
1147 return (tp_features.hotkey)? 0 : 1; 2034 return (tp_features.hotkey)? 0 : 1;
@@ -1149,13 +2036,19 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
1149 2036
1150static void hotkey_exit(void) 2037static void hotkey_exit(void)
1151{ 2038{
1152 int res; 2039#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
2040 hotkey_poll_stop_sync();
2041#endif
1153 2042
1154 if (tp_features.hotkey) { 2043 if (tp_features.hotkey) {
1155 dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n"); 2044 dbg_printk(TPACPI_DBG_EXIT,
1156 res = hotkey_set(hotkey_orig_status, hotkey_orig_mask); 2045 "restoring original hot key mask\n");
1157 if (res) 2046 /* no short-circuit boolean operator below! */
1158 printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n"); 2047 if ((hotkey_mask_set(hotkey_orig_mask) |
2048 hotkey_status_set(hotkey_orig_status)) != 0)
2049 printk(TPACPI_ERR
2050 "failed to restore hot key mask "
2051 "to BIOS defaults\n");
1159 } 2052 }
1160 2053
1161 if (hotkey_dev_attributes) { 2054 if (hotkey_dev_attributes) {
@@ -1164,62 +2057,28 @@ static void hotkey_exit(void)
1164 } 2057 }
1165} 2058}
1166 2059
1167static void tpacpi_input_send_key(unsigned int scancode,
1168 unsigned int keycode)
1169{
1170 if (keycode != KEY_RESERVED) {
1171 mutex_lock(&tpacpi_inputdev_send_mutex);
1172
1173 input_report_key(tpacpi_inputdev, keycode, 1);
1174 if (keycode == KEY_UNKNOWN)
1175 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1176 scancode);
1177 input_sync(tpacpi_inputdev);
1178
1179 input_report_key(tpacpi_inputdev, keycode, 0);
1180 if (keycode == KEY_UNKNOWN)
1181 input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
1182 scancode);
1183 input_sync(tpacpi_inputdev);
1184
1185 mutex_unlock(&tpacpi_inputdev_send_mutex);
1186 }
1187}
1188
1189static void tpacpi_input_send_radiosw(void)
1190{
1191 int wlsw;
1192
1193 mutex_lock(&tpacpi_inputdev_send_mutex);
1194
1195 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
1196 input_report_switch(tpacpi_inputdev,
1197 SW_RADIO, !!wlsw);
1198 input_sync(tpacpi_inputdev);
1199 }
1200
1201 mutex_unlock(&tpacpi_inputdev_send_mutex);
1202}
1203
1204static void hotkey_notify(struct ibm_struct *ibm, u32 event) 2060static void hotkey_notify(struct ibm_struct *ibm, u32 event)
1205{ 2061{
1206 u32 hkey; 2062 u32 hkey;
1207 unsigned int keycode, scancode; 2063 unsigned int scancode;
1208 int send_acpi_ev; 2064 int send_acpi_ev;
1209 int ignore_acpi_ev; 2065 int ignore_acpi_ev;
2066 int unk_ev;
1210 2067
1211 if (event != 0x80) { 2068 if (event != 0x80) {
1212 printk(IBM_ERR "unknown HKEY notification event %d\n", event); 2069 printk(TPACPI_ERR
2070 "unknown HKEY notification event %d\n", event);
1213 /* forward it to userspace, maybe it knows how to handle it */ 2071 /* forward it to userspace, maybe it knows how to handle it */
1214 acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, 2072 acpi_bus_generate_netlink_event(
1215 ibm->acpi->device->dev.bus_id, 2073 ibm->acpi->device->pnp.device_class,
1216 event, 0); 2074 ibm->acpi->device->dev.bus_id,
2075 event, 0);
1217 return; 2076 return;
1218 } 2077 }
1219 2078
1220 while (1) { 2079 while (1) {
1221 if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { 2080 if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
1222 printk(IBM_ERR "failed to retrieve HKEY event\n"); 2081 printk(TPACPI_ERR "failed to retrieve HKEY event\n");
1223 return; 2082 return;
1224 } 2083 }
1225 2084
@@ -1228,8 +2087,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
1228 return; 2087 return;
1229 } 2088 }
1230 2089
1231 send_acpi_ev = 0; 2090 send_acpi_ev = 1;
1232 ignore_acpi_ev = 0; 2091 ignore_acpi_ev = 0;
2092 unk_ev = 0;
1233 2093
1234 switch (hkey >> 12) { 2094 switch (hkey >> 12) {
1235 case 1: 2095 case 1:
@@ -1237,104 +2097,139 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
1237 scancode = hkey & 0xfff; 2097 scancode = hkey & 0xfff;
1238 if (scancode > 0 && scancode < 0x21) { 2098 if (scancode > 0 && scancode < 0x21) {
1239 scancode--; 2099 scancode--;
1240 keycode = hotkey_keycode_map[scancode]; 2100 if (!(hotkey_source_mask & (1 << scancode))) {
1241 tpacpi_input_send_key(scancode, keycode); 2101 tpacpi_input_send_key(scancode);
2102 send_acpi_ev = 0;
2103 } else {
2104 ignore_acpi_ev = 1;
2105 }
1242 } else { 2106 } else {
1243 printk(IBM_ERR 2107 unk_ev = 1;
1244 "hotkey 0x%04x out of range for keyboard map\n",
1245 hkey);
1246 send_acpi_ev = 1;
1247 } 2108 }
1248 break; 2109 break;
1249 case 5: 2110 case 2:
1250 /* 0x5000-0x5FFF: LID */ 2111 /* Wakeup reason */
1251 /* we don't handle it through this path, just 2112 switch (hkey) {
1252 * eat up known LID events */ 2113 case 0x2304: /* suspend, undock */
1253 if (hkey != 0x5001 && hkey != 0x5002) { 2114 case 0x2404: /* hibernation, undock */
1254 printk(IBM_ERR 2115 hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
1255 "unknown LID-related HKEY event: 0x%04x\n", 2116 ignore_acpi_ev = 1;
1256 hkey); 2117 break;
1257 send_acpi_ev = 1; 2118 case 0x2305: /* suspend, bay eject */
2119 case 0x2405: /* hibernation, bay eject */
2120 hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
2121 ignore_acpi_ev = 1;
2122 break;
2123 default:
2124 unk_ev = 1;
2125 }
2126 if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
2127 printk(TPACPI_INFO
2128 "woke up due to a hot-unplug "
2129 "request...\n");
2130 hotkey_wakeup_reason_notify_change();
2131 }
2132 break;
2133 case 3:
2134 /* bay-related wakeups */
2135 if (hkey == 0x3003) {
2136 hotkey_autosleep_ack = 1;
2137 printk(TPACPI_INFO
2138 "bay ejected\n");
2139 hotkey_wakeup_hotunplug_complete_notify_change();
1258 } else { 2140 } else {
2141 unk_ev = 1;
2142 }
2143 break;
2144 case 4:
2145 /* dock-related wakeups */
2146 if (hkey == 0x4003) {
2147 hotkey_autosleep_ack = 1;
2148 printk(TPACPI_INFO
2149 "undocked\n");
2150 hotkey_wakeup_hotunplug_complete_notify_change();
2151 } else {
2152 unk_ev = 1;
2153 }
2154 break;
2155 case 5:
2156 /* 0x5000-0x5FFF: human interface helpers */
2157 switch (hkey) {
2158 case 0x5010: /* Lenovo new BIOS: brightness changed */
2159 case 0x5009: /* X61t: swivel up (tablet mode) */
2160 case 0x500a: /* X61t: swivel down (normal mode) */
2161 case 0x500b: /* X61t: tablet pen inserted into bay */
2162 case 0x500c: /* X61t: tablet pen removed from bay */
2163 break;
2164 case 0x5001:
2165 case 0x5002:
2166 /* LID switch events. Do not propagate */
1259 ignore_acpi_ev = 1; 2167 ignore_acpi_ev = 1;
2168 break;
2169 default:
2170 unk_ev = 1;
1260 } 2171 }
1261 break; 2172 break;
1262 case 7: 2173 case 7:
1263 /* 0x7000-0x7FFF: misc */ 2174 /* 0x7000-0x7FFF: misc */
1264 if (tp_features.hotkey_wlsw && hkey == 0x7000) { 2175 if (tp_features.hotkey_wlsw && hkey == 0x7000) {
1265 tpacpi_input_send_radiosw(); 2176 tpacpi_input_send_radiosw();
2177 hotkey_radio_sw_notify_change();
2178 send_acpi_ev = 0;
1266 break; 2179 break;
1267 } 2180 }
1268 /* fallthrough to default */ 2181 /* fallthrough to default */
1269 default: 2182 default:
1270 /* case 2: dock-related */ 2183 unk_ev = 1;
1271 /* 0x2305 - T43 waking up due to bay lever eject while aslept */ 2184 }
1272 /* case 3: ultra-bay related. maybe bay in dock? */ 2185 if (unk_ev) {
1273 /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ 2186 printk(TPACPI_NOTICE
1274 printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); 2187 "unhandled HKEY event 0x%04x\n", hkey);
1275 send_acpi_ev = 1;
1276 } 2188 }
1277 2189
1278 /* Legacy events */ 2190 /* Legacy events */
1279 if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { 2191 if (!ignore_acpi_ev &&
1280 acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); 2192 (send_acpi_ev || hotkey_report_mode < 2)) {
2193 acpi_bus_generate_proc_event(ibm->acpi->device,
2194 event, hkey);
1281 } 2195 }
1282 2196
1283 /* netlink events */ 2197 /* netlink events */
1284 if (!ignore_acpi_ev && send_acpi_ev) { 2198 if (!ignore_acpi_ev && send_acpi_ev) {
1285 acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, 2199 acpi_bus_generate_netlink_event(
1286 ibm->acpi->device->dev.bus_id, 2200 ibm->acpi->device->pnp.device_class,
1287 event, hkey); 2201 ibm->acpi->device->dev.bus_id,
2202 event, hkey);
1288 } 2203 }
1289 } 2204 }
1290} 2205}
1291 2206
1292static void hotkey_resume(void) 2207static void hotkey_suspend(pm_message_t state)
1293{ 2208{
1294 tpacpi_input_send_radiosw(); 2209 /* Do these on suspend, we get the events on early resume! */
2210 hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
2211 hotkey_autosleep_ack = 0;
1295} 2212}
1296 2213
1297/* 2214static void hotkey_resume(void)
1298 * Call with hotkey_mutex held
1299 */
1300static int hotkey_get(int *status, u32 *mask)
1301{
1302 if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
1303 return -EIO;
1304
1305 if (tp_features.hotkey_mask)
1306 if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
1307 return -EIO;
1308
1309 return 0;
1310}
1311
1312/*
1313 * Call with hotkey_mutex held
1314 */
1315static int hotkey_set(int status, u32 mask)
1316{ 2215{
1317 int i; 2216 if (hotkey_mask_get())
1318 2217 printk(TPACPI_ERR
1319 if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) 2218 "error while trying to read hot key mask "
1320 return -EIO; 2219 "from firmware\n");
1321 2220 tpacpi_input_send_radiosw();
1322 if (tp_features.hotkey_mask) 2221 hotkey_radio_sw_notify_change();
1323 for (i = 0; i < 32; i++) { 2222 hotkey_wakeup_reason_notify_change();
1324 int bit = ((1 << i) & mask) != 0; 2223 hotkey_wakeup_hotunplug_complete_notify_change();
1325 if (!acpi_evalf(hkey_handle, 2224#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
1326 NULL, "MHKM", "vdd", i + 1, bit)) 2225 hotkey_poll_setup_safe(0);
1327 return -EIO; 2226#endif
1328 }
1329
1330 return 0;
1331} 2227}
1332 2228
1333/* procfs -------------------------------------------------------------- */ 2229/* procfs -------------------------------------------------------------- */
1334static int hotkey_read(char *p) 2230static int hotkey_read(char *p)
1335{ 2231{
1336 int res, status; 2232 int res, status;
1337 u32 mask;
1338 int len = 0; 2233 int len = 0;
1339 2234
1340 if (!tp_features.hotkey) { 2235 if (!tp_features.hotkey) {
@@ -1344,14 +2239,16 @@ static int hotkey_read(char *p)
1344 2239
1345 if (mutex_lock_interruptible(&hotkey_mutex)) 2240 if (mutex_lock_interruptible(&hotkey_mutex))
1346 return -ERESTARTSYS; 2241 return -ERESTARTSYS;
1347 res = hotkey_get(&status, &mask); 2242 res = hotkey_status_get(&status);
2243 if (!res)
2244 res = hotkey_mask_get();
1348 mutex_unlock(&hotkey_mutex); 2245 mutex_unlock(&hotkey_mutex);
1349 if (res) 2246 if (res)
1350 return res; 2247 return res;
1351 2248
1352 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); 2249 len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
1353 if (tp_features.hotkey_mask) { 2250 if (tp_features.hotkey_mask) {
1354 len += sprintf(p + len, "mask:\t\t0x%08x\n", mask); 2251 len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_mask);
1355 len += sprintf(p + len, 2252 len += sprintf(p + len,
1356 "commands:\tenable, disable, reset, <mask>\n"); 2253 "commands:\tenable, disable, reset, <mask>\n");
1357 } else { 2254 } else {
@@ -1367,7 +2264,6 @@ static int hotkey_write(char *buf)
1367 int res, status; 2264 int res, status;
1368 u32 mask; 2265 u32 mask;
1369 char *cmd; 2266 char *cmd;
1370 int do_cmd = 0;
1371 2267
1372 if (!tp_features.hotkey) 2268 if (!tp_features.hotkey)
1373 return -ENODEV; 2269 return -ENODEV;
@@ -1375,9 +2271,8 @@ static int hotkey_write(char *buf)
1375 if (mutex_lock_interruptible(&hotkey_mutex)) 2271 if (mutex_lock_interruptible(&hotkey_mutex))
1376 return -ERESTARTSYS; 2272 return -ERESTARTSYS;
1377 2273
1378 res = hotkey_get(&status, &mask); 2274 status = -1;
1379 if (res) 2275 mask = hotkey_mask;
1380 goto errexit;
1381 2276
1382 res = 0; 2277 res = 0;
1383 while ((cmd = next_cmd(&buf))) { 2278 while ((cmd = next_cmd(&buf))) {
@@ -1396,11 +2291,12 @@ static int hotkey_write(char *buf)
1396 res = -EINVAL; 2291 res = -EINVAL;
1397 goto errexit; 2292 goto errexit;
1398 } 2293 }
1399 do_cmd = 1;
1400 } 2294 }
2295 if (status != -1)
2296 res = hotkey_status_set(status);
1401 2297
1402 if (do_cmd) 2298 if (!res && mask != hotkey_mask)
1403 res = hotkey_set(status, mask); 2299 res = hotkey_mask_set(mask);
1404 2300
1405errexit: 2301errexit:
1406 mutex_unlock(&hotkey_mutex); 2302 mutex_unlock(&hotkey_mutex);
@@ -1408,7 +2304,7 @@ errexit:
1408} 2304}
1409 2305
1410static const struct acpi_device_id ibm_htk_device_ids[] = { 2306static const struct acpi_device_id ibm_htk_device_ids[] = {
1411 {IBM_HKEY_HID, 0}, 2307 {TPACPI_ACPI_HKEY_HID, 0},
1412 {"", 0}, 2308 {"", 0},
1413}; 2309};
1414 2310
@@ -1425,6 +2321,7 @@ static struct ibm_struct hotkey_driver_data = {
1425 .write = hotkey_write, 2321 .write = hotkey_write,
1426 .exit = hotkey_exit, 2322 .exit = hotkey_exit,
1427 .resume = hotkey_resume, 2323 .resume = hotkey_resume,
2324 .suspend = hotkey_suspend,
1428 .acpi = &ibm_hotkey_acpidriver, 2325 .acpi = &ibm_hotkey_acpidriver,
1429}; 2326};
1430 2327
@@ -1432,6 +2329,16 @@ static struct ibm_struct hotkey_driver_data = {
1432 * Bluetooth subdriver 2329 * Bluetooth subdriver
1433 */ 2330 */
1434 2331
2332enum {
2333 /* ACPI GBDC/SBDC bits */
2334 TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
2335 TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
2336 TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
2337};
2338
2339static int bluetooth_get_radiosw(void);
2340static int bluetooth_set_radiosw(int radio_on);
2341
1435/* sysfs bluetooth enable ---------------------------------------------- */ 2342/* sysfs bluetooth enable ---------------------------------------------- */
1436static ssize_t bluetooth_enable_show(struct device *dev, 2343static ssize_t bluetooth_enable_show(struct device *dev,
1437 struct device_attribute *attr, 2344 struct device_attribute *attr,
@@ -1483,7 +2390,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
1483 2390
1484 vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); 2391 vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
1485 2392
1486 IBM_ACPIHANDLE_INIT(hkey); 2393 TPACPI_ACPIHANDLE_INIT(hkey);
1487 2394
1488 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, 2395 /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
1489 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ 2396 G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
@@ -1596,6 +2503,16 @@ static struct ibm_struct bluetooth_driver_data = {
1596 * Wan subdriver 2503 * Wan subdriver
1597 */ 2504 */
1598 2505
2506enum {
2507 /* ACPI GWAN/SWAN bits */
2508 TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
2509 TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
2510 TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
2511};
2512
2513static int wan_get_radiosw(void);
2514static int wan_set_radiosw(int radio_on);
2515
1599/* sysfs wan enable ---------------------------------------------------- */ 2516/* sysfs wan enable ---------------------------------------------------- */
1600static ssize_t wan_enable_show(struct device *dev, 2517static ssize_t wan_enable_show(struct device *dev,
1601 struct device_attribute *attr, 2518 struct device_attribute *attr,
@@ -1647,7 +2564,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
1647 2564
1648 vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); 2565 vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
1649 2566
1650 IBM_ACPIHANDLE_INIT(hkey); 2567 TPACPI_ACPIHANDLE_INIT(hkey);
1651 2568
1652 tp_features.wan = hkey_handle && 2569 tp_features.wan = hkey_handle &&
1653 acpi_evalf(hkey_handle, &status, "GWAN", "qd"); 2570 acpi_evalf(hkey_handle, &status, "GWAN", "qd");
@@ -1759,17 +2676,41 @@ static struct ibm_struct wan_driver_data = {
1759 * Video subdriver 2676 * Video subdriver
1760 */ 2677 */
1761 2678
2679enum video_access_mode {
2680 TPACPI_VIDEO_NONE = 0,
2681 TPACPI_VIDEO_570, /* 570 */
2682 TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
2683 TPACPI_VIDEO_NEW, /* all others */
2684};
2685
2686enum { /* video status flags, based on VIDEO_570 */
2687 TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
2688 TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
2689 TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
2690};
2691
2692enum { /* TPACPI_VIDEO_570 constants */
2693 TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
2694 TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
2695 * video_status_flags */
2696 TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
2697 TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
2698};
2699
1762static enum video_access_mode video_supported; 2700static enum video_access_mode video_supported;
1763static int video_orig_autosw; 2701static int video_orig_autosw;
1764 2702
1765IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ 2703static int video_autosw_get(void);
2704static int video_autosw_set(int enable);
2705
2706TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
1766 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */ 2707 "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
1767 "\\_SB.PCI0.VID0", /* 770e */ 2708 "\\_SB.PCI0.VID0", /* 770e */
1768 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */ 2709 "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
1769 "\\_SB.PCI0.AGP.VID", /* all others */ 2710 "\\_SB.PCI0.AGP.VID", /* all others */
1770 ); /* R30, R31 */ 2711 ); /* R30, R31 */
1771 2712
1772IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ 2713TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
1773 2714
1774static int __init video_init(struct ibm_init_struct *iibm) 2715static int __init video_init(struct ibm_init_struct *iibm)
1775{ 2716{
@@ -1777,8 +2718,8 @@ static int __init video_init(struct ibm_init_struct *iibm)
1777 2718
1778 vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); 2719 vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
1779 2720
1780 IBM_ACPIHANDLE_INIT(vid); 2721 TPACPI_ACPIHANDLE_INIT(vid);
1781 IBM_ACPIHANDLE_INIT(vid2); 2722 TPACPI_ACPIHANDLE_INIT(vid2);
1782 2723
1783 if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) 2724 if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
1784 /* G41, assume IVGA doesn't change */ 2725 /* G41, assume IVGA doesn't change */
@@ -1809,7 +2750,7 @@ static void video_exit(void)
1809 dbg_printk(TPACPI_DBG_EXIT, 2750 dbg_printk(TPACPI_DBG_EXIT,
1810 "restoring original video autoswitch mode\n"); 2751 "restoring original video autoswitch mode\n");
1811 if (video_autosw_set(video_orig_autosw)) 2752 if (video_autosw_set(video_orig_autosw))
1812 printk(IBM_ERR "error while trying to restore original " 2753 printk(TPACPI_ERR "error while trying to restore original "
1813 "video autoswitch mode\n"); 2754 "video autoswitch mode\n");
1814} 2755}
1815 2756
@@ -1882,13 +2823,14 @@ static int video_outputsw_set(int status)
1882 res = acpi_evalf(vid_handle, NULL, 2823 res = acpi_evalf(vid_handle, NULL,
1883 "ASWT", "vdd", status * 0x100, 0); 2824 "ASWT", "vdd", status * 0x100, 0);
1884 if (!autosw && video_autosw_set(autosw)) { 2825 if (!autosw && video_autosw_set(autosw)) {
1885 printk(IBM_ERR "video auto-switch left enabled due to error\n"); 2826 printk(TPACPI_ERR
2827 "video auto-switch left enabled due to error\n");
1886 return -EIO; 2828 return -EIO;
1887 } 2829 }
1888 break; 2830 break;
1889 case TPACPI_VIDEO_NEW: 2831 case TPACPI_VIDEO_NEW:
1890 res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && 2832 res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
1891 acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); 2833 acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
1892 break; 2834 break;
1893 default: 2835 default:
1894 return -ENOSYS; 2836 return -ENOSYS;
@@ -1951,7 +2893,8 @@ static int video_outputsw_cycle(void)
1951 return -ENOSYS; 2893 return -ENOSYS;
1952 } 2894 }
1953 if (!autosw && video_autosw_set(autosw)) { 2895 if (!autosw && video_autosw_set(autosw)) {
1954 printk(IBM_ERR "video auto-switch left enabled due to error\n"); 2896 printk(TPACPI_ERR
2897 "video auto-switch left enabled due to error\n");
1955 return -EIO; 2898 return -EIO;
1956 } 2899 }
1957 2900
@@ -2080,16 +3023,16 @@ static struct ibm_struct video_driver_data = {
2080 * Light (thinklight) subdriver 3023 * Light (thinklight) subdriver
2081 */ 3024 */
2082 3025
2083IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ 3026TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
2084IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ 3027TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
2085 3028
2086static int __init light_init(struct ibm_init_struct *iibm) 3029static int __init light_init(struct ibm_init_struct *iibm)
2087{ 3030{
2088 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); 3031 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
2089 3032
2090 IBM_ACPIHANDLE_INIT(ledb); 3033 TPACPI_ACPIHANDLE_INIT(ledb);
2091 IBM_ACPIHANDLE_INIT(lght); 3034 TPACPI_ACPIHANDLE_INIT(lght);
2092 IBM_ACPIHANDLE_INIT(cmos); 3035 TPACPI_ACPIHANDLE_INIT(cmos);
2093 3036
2094 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ 3037 /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
2095 tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; 3038 tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
@@ -2167,14 +3110,18 @@ static struct ibm_struct light_driver_data = {
2167 3110
2168#ifdef CONFIG_THINKPAD_ACPI_DOCK 3111#ifdef CONFIG_THINKPAD_ACPI_DOCK
2169 3112
2170IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ 3113static void dock_notify(struct ibm_struct *ibm, u32 event);
3114static int dock_read(char *p);
3115static int dock_write(char *buf);
3116
3117TPACPI_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
2171 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ 3118 "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
2172 "\\_SB.PCI0.PCI1.DOCK", /* all others */ 3119 "\\_SB.PCI0.PCI1.DOCK", /* all others */
2173 "\\_SB.PCI.ISA.SLCE", /* 570 */ 3120 "\\_SB.PCI.ISA.SLCE", /* 570 */
2174 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ 3121 ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
2175 3122
2176/* don't list other alternatives as we install a notify handler on the 570 */ 3123/* don't list other alternatives as we install a notify handler on the 570 */
2177IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ 3124TPACPI_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
2178 3125
2179static const struct acpi_device_id ibm_pci_device_ids[] = { 3126static const struct acpi_device_id ibm_pci_device_ids[] = {
2180 {PCI_ROOT_HID_STRING, 0}, 3127 {PCI_ROOT_HID_STRING, 0},
@@ -2217,7 +3164,7 @@ static int __init dock_init(struct ibm_init_struct *iibm)
2217{ 3164{
2218 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); 3165 vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
2219 3166
2220 IBM_ACPIHANDLE_INIT(dock); 3167 TPACPI_ACPIHANDLE_INIT(dock);
2221 3168
2222 vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n", 3169 vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
2223 str_supported(dock_handle != NULL)); 3170 str_supported(dock_handle != NULL));
@@ -2233,7 +3180,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm)
2233 3180
2234 if (dock_driver_data[0].flags.acpi_driver_registered && 3181 if (dock_driver_data[0].flags.acpi_driver_registered &&
2235 dock_driver_data[0].flags.acpi_notify_installed) { 3182 dock_driver_data[0].flags.acpi_notify_installed) {
2236 IBM_ACPIHANDLE_INIT(pci); 3183 TPACPI_ACPIHANDLE_INIT(pci);
2237 dock2_needed = (pci_handle != NULL); 3184 dock2_needed = (pci_handle != NULL);
2238 vdbg_printk(TPACPI_DBG_INIT, 3185 vdbg_printk(TPACPI_DBG_INIT,
2239 "dock PCI handler for the TP 570 is %s\n", 3186 "dock PCI handler for the TP 570 is %s\n",
@@ -2265,7 +3212,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event)
2265 else if (event == 0 && docked) 3212 else if (event == 0 && docked)
2266 data = 3; /* dock */ 3213 data = 3; /* dock */
2267 else { 3214 else {
2268 printk(IBM_ERR "unknown dock event %d, status %d\n", 3215 printk(TPACPI_ERR "unknown dock event %d, status %d\n",
2269 event, _sta(dock_handle)); 3216 event, _sta(dock_handle));
2270 data = 0; /* unknown */ 3217 data = 0; /* unknown */
2271 } 3218 }
@@ -2321,18 +3268,19 @@ static int dock_write(char *buf)
2321 */ 3268 */
2322 3269
2323#ifdef CONFIG_THINKPAD_ACPI_BAY 3270#ifdef CONFIG_THINKPAD_ACPI_BAY
2324IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ 3271
3272TPACPI_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
2325 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ 3273 "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
2326 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ 3274 "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
2327 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */ 3275 "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
2328 ); /* A21e, R30, R31 */ 3276 ); /* A21e, R30, R31 */
2329IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */ 3277TPACPI_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
2330 "_EJ0", /* all others */ 3278 "_EJ0", /* all others */
2331 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */ 3279 ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
2332IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */ 3280TPACPI_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
2333 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */ 3281 "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
2334 ); /* all others */ 3282 ); /* all others */
2335IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ 3283TPACPI_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
2336 "_EJ0", /* 770x */ 3284 "_EJ0", /* 770x */
2337 ); /* all others */ 3285 ); /* all others */
2338 3286
@@ -2340,12 +3288,12 @@ static int __init bay_init(struct ibm_init_struct *iibm)
2340{ 3288{
2341 vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); 3289 vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
2342 3290
2343 IBM_ACPIHANDLE_INIT(bay); 3291 TPACPI_ACPIHANDLE_INIT(bay);
2344 if (bay_handle) 3292 if (bay_handle)
2345 IBM_ACPIHANDLE_INIT(bay_ej); 3293 TPACPI_ACPIHANDLE_INIT(bay_ej);
2346 IBM_ACPIHANDLE_INIT(bay2); 3294 TPACPI_ACPIHANDLE_INIT(bay2);
2347 if (bay2_handle) 3295 if (bay2_handle)
2348 IBM_ACPIHANDLE_INIT(bay2_ej); 3296 TPACPI_ACPIHANDLE_INIT(bay2_ej);
2349 3297
2350 tp_features.bay_status = bay_handle && 3298 tp_features.bay_status = bay_handle &&
2351 acpi_evalf(bay_handle, NULL, "_STA", "qv"); 3299 acpi_evalf(bay_handle, NULL, "_STA", "qv");
@@ -2474,7 +3422,7 @@ static int __init cmos_init(struct ibm_init_struct *iibm)
2474 vdbg_printk(TPACPI_DBG_INIT, 3422 vdbg_printk(TPACPI_DBG_INIT,
2475 "initializing cmos commands subdriver\n"); 3423 "initializing cmos commands subdriver\n");
2476 3424
2477 IBM_ACPIHANDLE_INIT(cmos); 3425 TPACPI_ACPIHANDLE_INIT(cmos);
2478 3426
2479 vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", 3427 vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
2480 str_supported(cmos_handle != NULL)); 3428 str_supported(cmos_handle != NULL));
@@ -2538,10 +3486,24 @@ static struct ibm_struct cmos_driver_data = {
2538 * LED subdriver 3486 * LED subdriver
2539 */ 3487 */
2540 3488
3489enum led_access_mode {
3490 TPACPI_LED_NONE = 0,
3491 TPACPI_LED_570, /* 570 */
3492 TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
3493 TPACPI_LED_NEW, /* all others */
3494};
3495
3496enum { /* For TPACPI_LED_OLD */
3497 TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
3498 TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
3499 TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
3500};
3501
2541static enum led_access_mode led_supported; 3502static enum led_access_mode led_supported;
2542 3503
2543IBM_HANDLE(led, ec, "SLED", /* 570 */ 3504TPACPI_HANDLE(led, ec, "SLED", /* 570 */
2544 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ 3505 "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, */
3506 /* T20-22, X20-21 */
2545 "LED", /* all others */ 3507 "LED", /* all others */
2546 ); /* R30, R31 */ 3508 ); /* R30, R31 */
2547 3509
@@ -2549,7 +3511,7 @@ static int __init led_init(struct ibm_init_struct *iibm)
2549{ 3511{
2550 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); 3512 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
2551 3513
2552 IBM_ACPIHANDLE_INIT(led); 3514 TPACPI_ACPIHANDLE_INIT(led);
2553 3515
2554 if (!led_handle) 3516 if (!led_handle)
2555 /* led not supported on R30, R31 */ 3517 /* led not supported on R30, R31 */
@@ -2638,13 +3600,11 @@ static int led_write(char *buf)
2638 led = 1 << led; 3600 led = 1 << led;
2639 ret = ec_write(TPACPI_LED_EC_HLMS, led); 3601 ret = ec_write(TPACPI_LED_EC_HLMS, led);
2640 if (ret >= 0) 3602 if (ret >= 0)
2641 ret = 3603 ret = ec_write(TPACPI_LED_EC_HLBL,
2642 ec_write(TPACPI_LED_EC_HLBL, 3604 led * led_exp_hlbl[ind]);
2643 led * led_exp_hlbl[ind]);
2644 if (ret >= 0) 3605 if (ret >= 0)
2645 ret = 3606 ret = ec_write(TPACPI_LED_EC_HLCL,
2646 ec_write(TPACPI_LED_EC_HLCL, 3607 led * led_exp_hlcl[ind]);
2647 led * led_exp_hlcl[ind]);
2648 if (ret < 0) 3608 if (ret < 0)
2649 return ret; 3609 return ret;
2650 } else { 3610 } else {
@@ -2668,13 +3628,13 @@ static struct ibm_struct led_driver_data = {
2668 * Beep subdriver 3628 * Beep subdriver
2669 */ 3629 */
2670 3630
2671IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ 3631TPACPI_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
2672 3632
2673static int __init beep_init(struct ibm_init_struct *iibm) 3633static int __init beep_init(struct ibm_init_struct *iibm)
2674{ 3634{
2675 vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); 3635 vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
2676 3636
2677 IBM_ACPIHANDLE_INIT(beep); 3637 TPACPI_ACPIHANDLE_INIT(beep);
2678 3638
2679 vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", 3639 vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
2680 str_supported(beep_handle != NULL)); 3640 str_supported(beep_handle != NULL));
@@ -2727,8 +3687,109 @@ static struct ibm_struct beep_driver_data = {
2727 * Thermal subdriver 3687 * Thermal subdriver
2728 */ 3688 */
2729 3689
3690enum thermal_access_mode {
3691 TPACPI_THERMAL_NONE = 0, /* No thermal support */
3692 TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
3693 TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
3694 TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
3695 TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
3696};
3697
3698enum { /* TPACPI_THERMAL_TPEC_* */
3699 TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
3700 TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
3701 TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
3702};
3703
3704#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
3705struct ibm_thermal_sensors_struct {
3706 s32 temp[TPACPI_MAX_THERMAL_SENSORS];
3707};
3708
2730static enum thermal_access_mode thermal_read_mode; 3709static enum thermal_access_mode thermal_read_mode;
2731 3710
3711/* idx is zero-based */
3712static int thermal_get_sensor(int idx, s32 *value)
3713{
3714 int t;
3715 s8 tmp;
3716 char tmpi[5];
3717
3718 t = TP_EC_THERMAL_TMP0;
3719
3720 switch (thermal_read_mode) {
3721#if TPACPI_MAX_THERMAL_SENSORS >= 16
3722 case TPACPI_THERMAL_TPEC_16:
3723 if (idx >= 8 && idx <= 15) {
3724 t = TP_EC_THERMAL_TMP8;
3725 idx -= 8;
3726 }
3727 /* fallthrough */
3728#endif
3729 case TPACPI_THERMAL_TPEC_8:
3730 if (idx <= 7) {
3731 if (!acpi_ec_read(t + idx, &tmp))
3732 return -EIO;
3733 *value = tmp * 1000;
3734 return 0;
3735 }
3736 break;
3737
3738 case TPACPI_THERMAL_ACPI_UPDT:
3739 if (idx <= 7) {
3740 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
3741 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
3742 return -EIO;
3743 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
3744 return -EIO;
3745 *value = (t - 2732) * 100;
3746 return 0;
3747 }
3748 break;
3749
3750 case TPACPI_THERMAL_ACPI_TMP07:
3751 if (idx <= 7) {
3752 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
3753 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
3754 return -EIO;
3755 if (t > 127 || t < -127)
3756 t = TP_EC_THERMAL_TMP_NA;
3757 *value = t * 1000;
3758 return 0;
3759 }
3760 break;
3761
3762 case TPACPI_THERMAL_NONE:
3763 default:
3764 return -ENOSYS;
3765 }
3766
3767 return -EINVAL;
3768}
3769
3770static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
3771{
3772 int res, i;
3773 int n;
3774
3775 n = 8;
3776 i = 0;
3777
3778 if (!s)
3779 return -EINVAL;
3780
3781 if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
3782 n = 16;
3783
3784 for (i = 0 ; i < n; i++) {
3785 res = thermal_get_sensor(i, &s->temp[i]);
3786 if (res)
3787 return res;
3788 }
3789
3790 return n;
3791}
3792
2732/* sysfs temp##_input -------------------------------------------------- */ 3793/* sysfs temp##_input -------------------------------------------------- */
2733 3794
2734static ssize_t thermal_temp_input_show(struct device *dev, 3795static ssize_t thermal_temp_input_show(struct device *dev,
@@ -2751,7 +3812,8 @@ static ssize_t thermal_temp_input_show(struct device *dev,
2751} 3812}
2752 3813
2753#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ 3814#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
2754 SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB) 3815 SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, \
3816 thermal_temp_input_show, NULL, _idxB)
2755 3817
2756static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { 3818static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
2757 THERMAL_SENSOR_ATTR_TEMP(1, 0), 3819 THERMAL_SENSOR_ATTR_TEMP(1, 0),
@@ -2845,12 +3907,13 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
2845 if (ta1 == 0) { 3907 if (ta1 == 0) {
2846 /* This is sheer paranoia, but we handle it anyway */ 3908 /* This is sheer paranoia, but we handle it anyway */
2847 if (acpi_tmp7) { 3909 if (acpi_tmp7) {
2848 printk(IBM_ERR 3910 printk(TPACPI_ERR
2849 "ThinkPad ACPI EC access misbehaving, " 3911 "ThinkPad ACPI EC access misbehaving, "
2850 "falling back to ACPI TMPx access mode\n"); 3912 "falling back to ACPI TMPx access "
3913 "mode\n");
2851 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; 3914 thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
2852 } else { 3915 } else {
2853 printk(IBM_ERR 3916 printk(TPACPI_ERR
2854 "ThinkPad ACPI EC access misbehaving, " 3917 "ThinkPad ACPI EC access misbehaving, "
2855 "disabling thermal sensors access\n"); 3918 "disabling thermal sensors access\n");
2856 thermal_read_mode = TPACPI_THERMAL_NONE; 3919 thermal_read_mode = TPACPI_THERMAL_NONE;
@@ -2877,7 +3940,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
2877 str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), 3940 str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
2878 thermal_read_mode); 3941 thermal_read_mode);
2879 3942
2880 switch(thermal_read_mode) { 3943 switch (thermal_read_mode) {
2881 case TPACPI_THERMAL_TPEC_16: 3944 case TPACPI_THERMAL_TPEC_16:
2882 res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, 3945 res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
2883 &thermal_temp_input16_group); 3946 &thermal_temp_input16_group);
@@ -2902,7 +3965,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
2902 3965
2903static void thermal_exit(void) 3966static void thermal_exit(void)
2904{ 3967{
2905 switch(thermal_read_mode) { 3968 switch (thermal_read_mode) {
2906 case TPACPI_THERMAL_TPEC_16: 3969 case TPACPI_THERMAL_TPEC_16:
2907 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, 3970 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
2908 &thermal_temp_input16_group); 3971 &thermal_temp_input16_group);
@@ -2919,88 +3982,6 @@ static void thermal_exit(void)
2919 } 3982 }
2920} 3983}
2921 3984
2922/* idx is zero-based */
2923static int thermal_get_sensor(int idx, s32 *value)
2924{
2925 int t;
2926 s8 tmp;
2927 char tmpi[5];
2928
2929 t = TP_EC_THERMAL_TMP0;
2930
2931 switch (thermal_read_mode) {
2932#if TPACPI_MAX_THERMAL_SENSORS >= 16
2933 case TPACPI_THERMAL_TPEC_16:
2934 if (idx >= 8 && idx <= 15) {
2935 t = TP_EC_THERMAL_TMP8;
2936 idx -= 8;
2937 }
2938 /* fallthrough */
2939#endif
2940 case TPACPI_THERMAL_TPEC_8:
2941 if (idx <= 7) {
2942 if (!acpi_ec_read(t + idx, &tmp))
2943 return -EIO;
2944 *value = tmp * 1000;
2945 return 0;
2946 }
2947 break;
2948
2949 case TPACPI_THERMAL_ACPI_UPDT:
2950 if (idx <= 7) {
2951 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
2952 if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
2953 return -EIO;
2954 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
2955 return -EIO;
2956 *value = (t - 2732) * 100;
2957 return 0;
2958 }
2959 break;
2960
2961 case TPACPI_THERMAL_ACPI_TMP07:
2962 if (idx <= 7) {
2963 snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
2964 if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
2965 return -EIO;
2966 if (t > 127 || t < -127)
2967 t = TP_EC_THERMAL_TMP_NA;
2968 *value = t * 1000;
2969 return 0;
2970 }
2971 break;
2972
2973 case TPACPI_THERMAL_NONE:
2974 default:
2975 return -ENOSYS;
2976 }
2977
2978 return -EINVAL;
2979}
2980
2981static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
2982{
2983 int res, i;
2984 int n;
2985
2986 n = 8;
2987 i = 0;
2988
2989 if (!s)
2990 return -EINVAL;
2991
2992 if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
2993 n = 16;
2994
2995 for(i = 0 ; i < n; i++) {
2996 res = thermal_get_sensor(i, &s->temp[i]);
2997 if (res)
2998 return res;
2999 }
3000
3001 return n;
3002}
3003
3004static int thermal_read(char *p) 3985static int thermal_read(char *p)
3005{ 3986{
3006 int len = 0; 3987 int len = 0;
@@ -3103,14 +4084,110 @@ static struct ibm_struct ecdump_driver_data = {
3103 * Backlight/brightness subdriver 4084 * Backlight/brightness subdriver
3104 */ 4085 */
3105 4086
4087#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
4088
3106static struct backlight_device *ibm_backlight_device; 4089static struct backlight_device *ibm_backlight_device;
4090static int brightness_offset = 0x31;
4091static int brightness_mode;
4092static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
4093
4094static struct mutex brightness_mutex;
4095
4096/*
4097 * ThinkPads can read brightness from two places: EC 0x31, or
4098 * CMOS NVRAM byte 0x5E, bits 0-3.
4099 */
4100static int brightness_get(struct backlight_device *bd)
4101{
4102 u8 lec = 0, lcmos = 0, level = 0;
4103
4104 if (brightness_mode & 1) {
4105 if (!acpi_ec_read(brightness_offset, &lec))
4106 return -EIO;
4107 lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
4108 level = lec;
4109 };
4110 if (brightness_mode & 2) {
4111 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
4112 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
4113 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
4114 lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
4115 level = lcmos;
4116 }
4117
4118 if (brightness_mode == 3 && lec != lcmos) {
4119 printk(TPACPI_ERR
4120 "CMOS NVRAM (%u) and EC (%u) do not agree "
4121 "on display brightness level\n",
4122 (unsigned int) lcmos,
4123 (unsigned int) lec);
4124 return -EIO;
4125 }
4126
4127 return level;
4128}
4129
4130/* May return EINTR which can always be mapped to ERESTARTSYS */
4131static int brightness_set(int value)
4132{
4133 int cmos_cmd, inc, i, res;
4134 int current_value;
4135
4136 if (value > ((tp_features.bright_16levels)? 15 : 7))
4137 return -EINVAL;
4138
4139 res = mutex_lock_interruptible(&brightness_mutex);
4140 if (res < 0)
4141 return res;
4142
4143 current_value = brightness_get(NULL);
4144 if (current_value < 0) {
4145 res = current_value;
4146 goto errout;
4147 }
4148
4149 cmos_cmd = value > current_value ?
4150 TP_CMOS_BRIGHTNESS_UP :
4151 TP_CMOS_BRIGHTNESS_DOWN;
4152 inc = (value > current_value)? 1 : -1;
4153
4154 res = 0;
4155 for (i = current_value; i != value; i += inc) {
4156 if ((brightness_mode & 2) &&
4157 issue_thinkpad_cmos_command(cmos_cmd)) {
4158 res = -EIO;
4159 goto errout;
4160 }
4161 if ((brightness_mode & 1) &&
4162 !acpi_ec_write(brightness_offset, i + inc)) {
4163 res = -EIO;
4164 goto errout;;
4165 }
4166 }
4167
4168errout:
4169 mutex_unlock(&brightness_mutex);
4170 return res;
4171}
4172
4173/* sysfs backlight class ----------------------------------------------- */
4174
4175static int brightness_update_status(struct backlight_device *bd)
4176{
4177 /* it is the backlight class's job (caller) to handle
4178 * EINTR and other errors properly */
4179 return brightness_set(
4180 (bd->props.fb_blank == FB_BLANK_UNBLANK &&
4181 bd->props.power == FB_BLANK_UNBLANK) ?
4182 bd->props.brightness : 0);
4183}
3107 4184
3108static struct backlight_ops ibm_backlight_data = { 4185static struct backlight_ops ibm_backlight_data = {
3109 .get_brightness = brightness_get, 4186 .get_brightness = brightness_get,
3110 .update_status = brightness_update_status, 4187 .update_status = brightness_update_status,
3111}; 4188};
3112 4189
3113static struct mutex brightness_mutex; 4190/* --------------------------------------------------------------------- */
3114 4191
3115static int __init tpacpi_query_bcll_levels(acpi_handle handle) 4192static int __init tpacpi_query_bcll_levels(acpi_handle handle)
3116{ 4193{
@@ -3121,8 +4198,8 @@ static int __init tpacpi_query_bcll_levels(acpi_handle handle)
3121 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { 4198 if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
3122 obj = (union acpi_object *)buffer.pointer; 4199 obj = (union acpi_object *)buffer.pointer;
3123 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { 4200 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
3124 printk(IBM_ERR "Unknown BCLL data, " 4201 printk(TPACPI_ERR "Unknown BCLL data, "
3125 "please report this to %s\n", IBM_MAIL); 4202 "please report this to %s\n", TPACPI_MAIL);
3126 rc = 0; 4203 rc = 0;
3127 } else { 4204 } else {
3128 rc = obj->package.count; 4205 rc = obj->package.count;
@@ -3160,14 +4237,15 @@ static int __init brightness_check_levels(void)
3160 void *found_node = NULL; 4237 void *found_node = NULL;
3161 4238
3162 if (!vid_handle) { 4239 if (!vid_handle) {
3163 IBM_ACPIHANDLE_INIT(vid); 4240 TPACPI_ACPIHANDLE_INIT(vid);
3164 } 4241 }
3165 if (!vid_handle) 4242 if (!vid_handle)
3166 return 0; 4243 return 0;
3167 4244
3168 /* Search for a BCLL package with 16 levels */ 4245 /* Search for a BCLL package with 16 levels */
3169 status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3, 4246 status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
3170 brightness_find_bcll, NULL, &found_node); 4247 brightness_find_bcll, NULL,
4248 &found_node);
3171 4249
3172 return (ACPI_SUCCESS(status) && found_node != NULL); 4250 return (ACPI_SUCCESS(status) && found_node != NULL);
3173} 4251}
@@ -3193,14 +4271,14 @@ static int __init brightness_check_std_acpi_support(void)
3193 void *found_node = NULL; 4271 void *found_node = NULL;
3194 4272
3195 if (!vid_handle) { 4273 if (!vid_handle) {
3196 IBM_ACPIHANDLE_INIT(vid); 4274 TPACPI_ACPIHANDLE_INIT(vid);
3197 } 4275 }
3198 if (!vid_handle) 4276 if (!vid_handle)
3199 return 0; 4277 return 0;
3200 4278
3201 /* Search for a _BCL method, but don't execute it */ 4279 /* Search for a _BCL method, but don't execute it */
3202 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, 4280 status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
3203 brightness_find_bcl, NULL, &found_node); 4281 brightness_find_bcl, NULL, &found_node);
3204 4282
3205 return (ACPI_SUCCESS(status) && found_node != NULL); 4283 return (ACPI_SUCCESS(status) && found_node != NULL);
3206} 4284}
@@ -3215,12 +4293,14 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
3215 4293
3216 if (!brightness_enable) { 4294 if (!brightness_enable) {
3217 dbg_printk(TPACPI_DBG_INIT, 4295 dbg_printk(TPACPI_DBG_INIT,
3218 "brightness support disabled by module parameter\n"); 4296 "brightness support disabled by "
4297 "module parameter\n");
3219 return 1; 4298 return 1;
3220 } else if (brightness_enable > 1) { 4299 } else if (brightness_enable > 1) {
3221 if (brightness_check_std_acpi_support()) { 4300 if (brightness_check_std_acpi_support()) {
3222 printk(IBM_NOTICE 4301 printk(TPACPI_NOTICE
3223 "standard ACPI backlight interface available, not loading native one...\n"); 4302 "standard ACPI backlight interface "
4303 "available, not loading native one...\n");
3224 return 1; 4304 return 1;
3225 } 4305 }
3226 } 4306 }
@@ -3247,13 +4327,14 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
3247 return 1; 4327 return 1;
3248 4328
3249 if (tp_features.bright_16levels) 4329 if (tp_features.bright_16levels)
3250 printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n"); 4330 printk(TPACPI_INFO
4331 "detected a 16-level brightness capable ThinkPad\n");
3251 4332
3252 ibm_backlight_device = backlight_device_register( 4333 ibm_backlight_device = backlight_device_register(
3253 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, 4334 TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
3254 &ibm_backlight_data); 4335 &ibm_backlight_data);
3255 if (IS_ERR(ibm_backlight_device)) { 4336 if (IS_ERR(ibm_backlight_device)) {
3256 printk(IBM_ERR "Could not register backlight device\n"); 4337 printk(TPACPI_ERR "Could not register backlight device\n");
3257 return PTR_ERR(ibm_backlight_device); 4338 return PTR_ERR(ibm_backlight_device);
3258 } 4339 }
3259 vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); 4340 vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
@@ -3276,99 +4357,13 @@ static void brightness_exit(void)
3276 } 4357 }
3277} 4358}
3278 4359
3279static int brightness_update_status(struct backlight_device *bd)
3280{
3281 /* it is the backlight class's job (caller) to handle
3282 * EINTR and other errors properly */
3283 return brightness_set(
3284 (bd->props.fb_blank == FB_BLANK_UNBLANK &&
3285 bd->props.power == FB_BLANK_UNBLANK) ?
3286 bd->props.brightness : 0);
3287}
3288
3289/*
3290 * ThinkPads can read brightness from two places: EC 0x31, or
3291 * CMOS NVRAM byte 0x5E, bits 0-3.
3292 */
3293static int brightness_get(struct backlight_device *bd)
3294{
3295 u8 lec = 0, lcmos = 0, level = 0;
3296
3297 if (brightness_mode & 1) {
3298 if (!acpi_ec_read(brightness_offset, &lec))
3299 return -EIO;
3300 lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
3301 level = lec;
3302 };
3303 if (brightness_mode & 2) {
3304 lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
3305 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
3306 >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
3307 lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
3308 level = lcmos;
3309 }
3310
3311 if (brightness_mode == 3 && lec != lcmos) {
3312 printk(IBM_ERR
3313 "CMOS NVRAM (%u) and EC (%u) do not agree "
3314 "on display brightness level\n",
3315 (unsigned int) lcmos,
3316 (unsigned int) lec);
3317 return -EIO;
3318 }
3319
3320 return level;
3321}
3322
3323/* May return EINTR which can always be mapped to ERESTARTSYS */
3324static int brightness_set(int value)
3325{
3326 int cmos_cmd, inc, i, res;
3327 int current_value;
3328
3329 if (value > ((tp_features.bright_16levels)? 15 : 7))
3330 return -EINVAL;
3331
3332 res = mutex_lock_interruptible(&brightness_mutex);
3333 if (res < 0)
3334 return res;
3335
3336 current_value = brightness_get(NULL);
3337 if (current_value < 0) {
3338 res = current_value;
3339 goto errout;
3340 }
3341
3342 cmos_cmd = value > current_value ?
3343 TP_CMOS_BRIGHTNESS_UP :
3344 TP_CMOS_BRIGHTNESS_DOWN;
3345 inc = (value > current_value)? 1 : -1;
3346
3347 res = 0;
3348 for (i = current_value; i != value; i += inc) {
3349 if ((brightness_mode & 2) &&
3350 issue_thinkpad_cmos_command(cmos_cmd)) {
3351 res = -EIO;
3352 goto errout;
3353 }
3354 if ((brightness_mode & 1) &&
3355 !acpi_ec_write(brightness_offset, i + inc)) {
3356 res = -EIO;
3357 goto errout;;
3358 }
3359 }
3360
3361errout:
3362 mutex_unlock(&brightness_mutex);
3363 return res;
3364}
3365
3366static int brightness_read(char *p) 4360static int brightness_read(char *p)
3367{ 4361{
3368 int len = 0; 4362 int len = 0;
3369 int level; 4363 int level;
3370 4364
3371 if ((level = brightness_get(NULL)) < 0) { 4365 level = brightness_get(NULL);
4366 if (level < 0) {
3372 len += sprintf(p + len, "level:\t\tunreadable\n"); 4367 len += sprintf(p + len, "level:\t\tunreadable\n");
3373 } else { 4368 } else {
3374 len += sprintf(p + len, "level:\t\t%d\n", level); 4369 len += sprintf(p + len, "level:\t\t%d\n", level);
@@ -3425,6 +4420,8 @@ static struct ibm_struct brightness_driver_data = {
3425 * Volume subdriver 4420 * Volume subdriver
3426 */ 4421 */
3427 4422
4423static int volume_offset = 0x30;
4424
3428static int volume_read(char *p) 4425static int volume_read(char *p)
3429{ 4426{
3430 int len = 0; 4427 int len = 0;
@@ -3474,8 +4471,11 @@ static int volume_write(char *buf)
3474 } else 4471 } else
3475 return -EINVAL; 4472 return -EINVAL;
3476 4473
3477 if (new_level != level) { /* mute doesn't change */ 4474 if (new_level != level) {
3478 cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; 4475 /* mute doesn't change */
4476
4477 cmos_cmd = (new_level > level) ?
4478 TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
3479 inc = new_level > level ? 1 : -1; 4479 inc = new_level > level ? 1 : -1;
3480 4480
3481 if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || 4481 if (mute && (issue_thinkpad_cmos_command(cmos_cmd) ||
@@ -3487,14 +4487,18 @@ static int volume_write(char *buf)
3487 !acpi_ec_write(volume_offset, i + inc)) 4487 !acpi_ec_write(volume_offset, i + inc))
3488 return -EIO; 4488 return -EIO;
3489 4489
3490 if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || 4490 if (mute &&
3491 !acpi_ec_write(volume_offset, 4491 (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
3492 new_level + mute))) 4492 !acpi_ec_write(volume_offset, new_level + mute))) {
3493 return -EIO; 4493 return -EIO;
4494 }
3494 } 4495 }
3495 4496
3496 if (new_mute != mute) { /* level doesn't change */ 4497 if (new_mute != mute) {
3497 cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; 4498 /* level doesn't change */
4499
4500 cmos_cmd = (new_mute) ?
4501 TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
3498 4502
3499 if (issue_thinkpad_cmos_command(cmos_cmd) || 4503 if (issue_thinkpad_cmos_command(cmos_cmd) ||
3500 !acpi_ec_write(volume_offset, level + new_mute)) 4504 !acpi_ec_write(volume_offset, level + new_mute))
@@ -3616,26 +4620,377 @@ static struct ibm_struct volume_driver_data = {
3616 * but the ACPI tables just mention level 7. 4620 * but the ACPI tables just mention level 7.
3617 */ 4621 */
3618 4622
4623enum { /* Fan control constants */
4624 fan_status_offset = 0x2f, /* EC register 0x2f */
4625 fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
4626 * 0x84 must be read before 0x85 */
4627
4628 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
4629 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
4630
4631 TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
4632};
4633
4634enum fan_status_access_mode {
4635 TPACPI_FAN_NONE = 0, /* No fan status or control */
4636 TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
4637 TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
4638};
4639
4640enum fan_control_access_mode {
4641 TPACPI_FAN_WR_NONE = 0, /* No fan control */
4642 TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
4643 TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
4644 TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
4645};
4646
4647enum fan_control_commands {
4648 TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
4649 TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
4650 TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
4651 * and also watchdog cmd */
4652};
4653
4654static int fan_control_allowed;
4655
3619static enum fan_status_access_mode fan_status_access_mode; 4656static enum fan_status_access_mode fan_status_access_mode;
3620static enum fan_control_access_mode fan_control_access_mode; 4657static enum fan_control_access_mode fan_control_access_mode;
3621static enum fan_control_commands fan_control_commands; 4658static enum fan_control_commands fan_control_commands;
3622 4659
3623static u8 fan_control_initial_status; 4660static u8 fan_control_initial_status;
3624static u8 fan_control_desired_level; 4661static u8 fan_control_desired_level;
4662static int fan_watchdog_maxinterval;
4663
4664static struct mutex fan_mutex;
3625 4665
3626static void fan_watchdog_fire(struct work_struct *ignored); 4666static void fan_watchdog_fire(struct work_struct *ignored);
3627static int fan_watchdog_maxinterval;
3628static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); 4667static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
3629 4668
3630IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ 4669TPACPI_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
3631IBM_HANDLE(gfan, ec, "GFAN", /* 570 */ 4670TPACPI_HANDLE(gfan, ec, "GFAN", /* 570 */
3632 "\\FSPD", /* 600e/x, 770e, 770x */ 4671 "\\FSPD", /* 600e/x, 770e, 770x */
3633 ); /* all others */ 4672 ); /* all others */
3634IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ 4673TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */
3635 "JFNS", /* 770x-JL */ 4674 "JFNS", /* 770x-JL */
3636 ); /* all others */ 4675 ); /* all others */
3637 4676
3638/* 4677/*
4678 * Call with fan_mutex held
4679 */
4680static void fan_update_desired_level(u8 status)
4681{
4682 if ((status &
4683 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
4684 if (status > 7)
4685 fan_control_desired_level = 7;
4686 else
4687 fan_control_desired_level = status;
4688 }
4689}
4690
4691static int fan_get_status(u8 *status)
4692{
4693 u8 s;
4694
4695 /* TODO:
4696 * Add TPACPI_FAN_RD_ACPI_FANS ? */
4697
4698 switch (fan_status_access_mode) {
4699 case TPACPI_FAN_RD_ACPI_GFAN:
4700 /* 570, 600e/x, 770e, 770x */
4701
4702 if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
4703 return -EIO;
4704
4705 if (likely(status))
4706 *status = s & 0x07;
4707
4708 break;
4709
4710 case TPACPI_FAN_RD_TPEC:
4711 /* all except 570, 600e/x, 770e, 770x */
4712 if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
4713 return -EIO;
4714
4715 if (likely(status))
4716 *status = s;
4717
4718 break;
4719
4720 default:
4721 return -ENXIO;
4722 }
4723
4724 return 0;
4725}
4726
4727static int fan_get_status_safe(u8 *status)
4728{
4729 int rc;
4730 u8 s;
4731
4732 if (mutex_lock_interruptible(&fan_mutex))
4733 return -ERESTARTSYS;
4734 rc = fan_get_status(&s);
4735 if (!rc)
4736 fan_update_desired_level(s);
4737 mutex_unlock(&fan_mutex);
4738
4739 if (status)
4740 *status = s;
4741
4742 return rc;
4743}
4744
4745static int fan_get_speed(unsigned int *speed)
4746{
4747 u8 hi, lo;
4748
4749 switch (fan_status_access_mode) {
4750 case TPACPI_FAN_RD_TPEC:
4751 /* all except 570, 600e/x, 770e, 770x */
4752 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
4753 !acpi_ec_read(fan_rpm_offset + 1, &hi)))
4754 return -EIO;
4755
4756 if (likely(speed))
4757 *speed = (hi << 8) | lo;
4758
4759 break;
4760
4761 default:
4762 return -ENXIO;
4763 }
4764
4765 return 0;
4766}
4767
4768static int fan_set_level(int level)
4769{
4770 if (!fan_control_allowed)
4771 return -EPERM;
4772
4773 switch (fan_control_access_mode) {
4774 case TPACPI_FAN_WR_ACPI_SFAN:
4775 if (level >= 0 && level <= 7) {
4776 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
4777 return -EIO;
4778 } else
4779 return -EINVAL;
4780 break;
4781
4782 case TPACPI_FAN_WR_ACPI_FANS:
4783 case TPACPI_FAN_WR_TPEC:
4784 if ((level != TP_EC_FAN_AUTO) &&
4785 (level != TP_EC_FAN_FULLSPEED) &&
4786 ((level < 0) || (level > 7)))
4787 return -EINVAL;
4788
4789 /* safety net should the EC not support AUTO
4790 * or FULLSPEED mode bits and just ignore them */
4791 if (level & TP_EC_FAN_FULLSPEED)
4792 level |= 7; /* safety min speed 7 */
4793 else if (level & TP_EC_FAN_AUTO)
4794 level |= 4; /* safety min speed 4 */
4795
4796 if (!acpi_ec_write(fan_status_offset, level))
4797 return -EIO;
4798 else
4799 tp_features.fan_ctrl_status_undef = 0;
4800 break;
4801
4802 default:
4803 return -ENXIO;
4804 }
4805 return 0;
4806}
4807
4808static int fan_set_level_safe(int level)
4809{
4810 int rc;
4811
4812 if (!fan_control_allowed)
4813 return -EPERM;
4814
4815 if (mutex_lock_interruptible(&fan_mutex))
4816 return -ERESTARTSYS;
4817
4818 if (level == TPACPI_FAN_LAST_LEVEL)
4819 level = fan_control_desired_level;
4820
4821 rc = fan_set_level(level);
4822 if (!rc)
4823 fan_update_desired_level(level);
4824
4825 mutex_unlock(&fan_mutex);
4826 return rc;
4827}
4828
4829static int fan_set_enable(void)
4830{
4831 u8 s;
4832 int rc;
4833
4834 if (!fan_control_allowed)
4835 return -EPERM;
4836
4837 if (mutex_lock_interruptible(&fan_mutex))
4838 return -ERESTARTSYS;
4839
4840 switch (fan_control_access_mode) {
4841 case TPACPI_FAN_WR_ACPI_FANS:
4842 case TPACPI_FAN_WR_TPEC:
4843 rc = fan_get_status(&s);
4844 if (rc < 0)
4845 break;
4846
4847 /* Don't go out of emergency fan mode */
4848 if (s != 7) {
4849 s &= 0x07;
4850 s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
4851 }
4852
4853 if (!acpi_ec_write(fan_status_offset, s))
4854 rc = -EIO;
4855 else {
4856 tp_features.fan_ctrl_status_undef = 0;
4857 rc = 0;
4858 }
4859 break;
4860
4861 case TPACPI_FAN_WR_ACPI_SFAN:
4862 rc = fan_get_status(&s);
4863 if (rc < 0)
4864 break;
4865
4866 s &= 0x07;
4867
4868 /* Set fan to at least level 4 */
4869 s |= 4;
4870
4871 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
4872 rc = -EIO;
4873 else
4874 rc = 0;
4875 break;
4876
4877 default:
4878 rc = -ENXIO;
4879 }
4880
4881 mutex_unlock(&fan_mutex);
4882 return rc;
4883}
4884
4885static int fan_set_disable(void)
4886{
4887 int rc;
4888
4889 if (!fan_control_allowed)
4890 return -EPERM;
4891
4892 if (mutex_lock_interruptible(&fan_mutex))
4893 return -ERESTARTSYS;
4894
4895 rc = 0;
4896 switch (fan_control_access_mode) {
4897 case TPACPI_FAN_WR_ACPI_FANS:
4898 case TPACPI_FAN_WR_TPEC:
4899 if (!acpi_ec_write(fan_status_offset, 0x00))
4900 rc = -EIO;
4901 else {
4902 fan_control_desired_level = 0;
4903 tp_features.fan_ctrl_status_undef = 0;
4904 }
4905 break;
4906
4907 case TPACPI_FAN_WR_ACPI_SFAN:
4908 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
4909 rc = -EIO;
4910 else
4911 fan_control_desired_level = 0;
4912 break;
4913
4914 default:
4915 rc = -ENXIO;
4916 }
4917
4918
4919 mutex_unlock(&fan_mutex);
4920 return rc;
4921}
4922
4923static int fan_set_speed(int speed)
4924{
4925 int rc;
4926
4927 if (!fan_control_allowed)
4928 return -EPERM;
4929
4930 if (mutex_lock_interruptible(&fan_mutex))
4931 return -ERESTARTSYS;
4932
4933 rc = 0;
4934 switch (fan_control_access_mode) {
4935 case TPACPI_FAN_WR_ACPI_FANS:
4936 if (speed >= 0 && speed <= 65535) {
4937 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
4938 speed, speed, speed))
4939 rc = -EIO;
4940 } else
4941 rc = -EINVAL;
4942 break;
4943
4944 default:
4945 rc = -ENXIO;
4946 }
4947
4948 mutex_unlock(&fan_mutex);
4949 return rc;
4950}
4951
4952static void fan_watchdog_reset(void)
4953{
4954 static int fan_watchdog_active;
4955
4956 if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
4957 return;
4958
4959 if (fan_watchdog_active)
4960 cancel_delayed_work(&fan_watchdog_task);
4961
4962 if (fan_watchdog_maxinterval > 0 &&
4963 tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
4964 fan_watchdog_active = 1;
4965 if (!schedule_delayed_work(&fan_watchdog_task,
4966 msecs_to_jiffies(fan_watchdog_maxinterval
4967 * 1000))) {
4968 printk(TPACPI_ERR
4969 "failed to schedule the fan watchdog, "
4970 "watchdog will not trigger\n");
4971 }
4972 } else
4973 fan_watchdog_active = 0;
4974}
4975
4976static void fan_watchdog_fire(struct work_struct *ignored)
4977{
4978 int rc;
4979
4980 if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
4981 return;
4982
4983 printk(TPACPI_NOTICE "fan watchdog: enabling fan\n");
4984 rc = fan_set_enable();
4985 if (rc < 0) {
4986 printk(TPACPI_ERR "fan watchdog: error %d while enabling fan, "
4987 "will try again later...\n", -rc);
4988 /* reschedule for later */
4989 fan_watchdog_reset();
4990 }
4991}
4992
4993/*
3639 * SYSFS fan layout: hwmon compatible (device) 4994 * SYSFS fan layout: hwmon compatible (device)
3640 * 4995 *
3641 * pwm*_enable: 4996 * pwm*_enable:
@@ -3868,9 +5223,9 @@ static int __init fan_init(struct ibm_init_struct *iibm)
3868 tp_features.fan_ctrl_status_undef = 0; 5223 tp_features.fan_ctrl_status_undef = 0;
3869 fan_control_desired_level = 7; 5224 fan_control_desired_level = 7;
3870 5225
3871 IBM_ACPIHANDLE_INIT(fans); 5226 TPACPI_ACPIHANDLE_INIT(fans);
3872 IBM_ACPIHANDLE_INIT(gfan); 5227 TPACPI_ACPIHANDLE_INIT(gfan);
3873 IBM_ACPIHANDLE_INIT(sfan); 5228 TPACPI_ACPIHANDLE_INIT(sfan);
3874 5229
3875 if (gfan_handle) { 5230 if (gfan_handle) {
3876 /* 570, 600e/x, 770e, 770x */ 5231 /* 570, 600e/x, 770e, 770x */
@@ -3896,16 +5251,16 @@ static int __init fan_init(struct ibm_init_struct *iibm)
3896 case 0x3837: /* TP-78 */ 5251 case 0x3837: /* TP-78 */
3897 case 0x3637: /* TP-76 */ 5252 case 0x3637: /* TP-76 */
3898 case 0x3037: /* TP-70 */ 5253 case 0x3037: /* TP-70 */
3899 printk(IBM_NOTICE 5254 printk(TPACPI_NOTICE
3900 "fan_init: initial fan status is " 5255 "fan_init: initial fan status "
3901 "unknown, assuming it is in auto " 5256 "is unknown, assuming it is "
3902 "mode\n"); 5257 "in auto mode\n");
3903 tp_features.fan_ctrl_status_undef = 1; 5258 tp_features.fan_ctrl_status_undef = 1;
3904 ;; 5259 ;;
3905 } 5260 }
3906 } 5261 }
3907 } else { 5262 } else {
3908 printk(IBM_ERR 5263 printk(TPACPI_ERR
3909 "ThinkPad ACPI EC access misbehaving, " 5264 "ThinkPad ACPI EC access misbehaving, "
3910 "fan status and control unavailable\n"); 5265 "fan status and control unavailable\n");
3911 return 1; 5266 return 1;
@@ -3970,333 +5325,20 @@ static int __init fan_init(struct ibm_init_struct *iibm)
3970 return 1; 5325 return 1;
3971} 5326}
3972 5327
3973/*
3974 * Call with fan_mutex held
3975 */
3976static void fan_update_desired_level(u8 status)
3977{
3978 if ((status &
3979 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
3980 if (status > 7)
3981 fan_control_desired_level = 7;
3982 else
3983 fan_control_desired_level = status;
3984 }
3985}
3986
3987static int fan_get_status(u8 *status)
3988{
3989 u8 s;
3990
3991 /* TODO:
3992 * Add TPACPI_FAN_RD_ACPI_FANS ? */
3993
3994 switch (fan_status_access_mode) {
3995 case TPACPI_FAN_RD_ACPI_GFAN:
3996 /* 570, 600e/x, 770e, 770x */
3997
3998 if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
3999 return -EIO;
4000
4001 if (likely(status))
4002 *status = s & 0x07;
4003
4004 break;
4005
4006 case TPACPI_FAN_RD_TPEC:
4007 /* all except 570, 600e/x, 770e, 770x */
4008 if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
4009 return -EIO;
4010
4011 if (likely(status))
4012 *status = s;
4013
4014 break;
4015
4016 default:
4017 return -ENXIO;
4018 }
4019
4020 return 0;
4021}
4022
4023static int fan_get_status_safe(u8 *status)
4024{
4025 int rc;
4026 u8 s;
4027
4028 if (mutex_lock_interruptible(&fan_mutex))
4029 return -ERESTARTSYS;
4030 rc = fan_get_status(&s);
4031 if (!rc)
4032 fan_update_desired_level(s);
4033 mutex_unlock(&fan_mutex);
4034
4035 if (status)
4036 *status = s;
4037
4038 return rc;
4039}
4040
4041static void fan_exit(void) 5328static void fan_exit(void)
4042{ 5329{
4043 vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); 5330 vdbg_printk(TPACPI_DBG_EXIT,
5331 "cancelling any pending fan watchdog tasks\n");
4044 5332
4045 /* FIXME: can we really do this unconditionally? */ 5333 /* FIXME: can we really do this unconditionally? */
4046 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); 5334 sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
4047 driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); 5335 driver_remove_file(&tpacpi_hwmon_pdriver.driver,
5336 &driver_attr_fan_watchdog);
4048 5337
4049 cancel_delayed_work(&fan_watchdog_task); 5338 cancel_delayed_work(&fan_watchdog_task);
4050 flush_scheduled_work(); 5339 flush_scheduled_work();
4051} 5340}
4052 5341
4053static int fan_get_speed(unsigned int *speed)
4054{
4055 u8 hi, lo;
4056
4057 switch (fan_status_access_mode) {
4058 case TPACPI_FAN_RD_TPEC:
4059 /* all except 570, 600e/x, 770e, 770x */
4060 if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
4061 !acpi_ec_read(fan_rpm_offset + 1, &hi)))
4062 return -EIO;
4063
4064 if (likely(speed))
4065 *speed = (hi << 8) | lo;
4066
4067 break;
4068
4069 default:
4070 return -ENXIO;
4071 }
4072
4073 return 0;
4074}
4075
4076static void fan_watchdog_fire(struct work_struct *ignored)
4077{
4078 int rc;
4079
4080 if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
4081 return;
4082
4083 printk(IBM_NOTICE "fan watchdog: enabling fan\n");
4084 rc = fan_set_enable();
4085 if (rc < 0) {
4086 printk(IBM_ERR "fan watchdog: error %d while enabling fan, "
4087 "will try again later...\n", -rc);
4088 /* reschedule for later */
4089 fan_watchdog_reset();
4090 }
4091}
4092
4093static void fan_watchdog_reset(void)
4094{
4095 static int fan_watchdog_active;
4096
4097 if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
4098 return;
4099
4100 if (fan_watchdog_active)
4101 cancel_delayed_work(&fan_watchdog_task);
4102
4103 if (fan_watchdog_maxinterval > 0 &&
4104 tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
4105 fan_watchdog_active = 1;
4106 if (!schedule_delayed_work(&fan_watchdog_task,
4107 msecs_to_jiffies(fan_watchdog_maxinterval
4108 * 1000))) {
4109 printk(IBM_ERR "failed to schedule the fan watchdog, "
4110 "watchdog will not trigger\n");
4111 }
4112 } else
4113 fan_watchdog_active = 0;
4114}
4115
4116static int fan_set_level(int level)
4117{
4118 if (!fan_control_allowed)
4119 return -EPERM;
4120
4121 switch (fan_control_access_mode) {
4122 case TPACPI_FAN_WR_ACPI_SFAN:
4123 if (level >= 0 && level <= 7) {
4124 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
4125 return -EIO;
4126 } else
4127 return -EINVAL;
4128 break;
4129
4130 case TPACPI_FAN_WR_ACPI_FANS:
4131 case TPACPI_FAN_WR_TPEC:
4132 if ((level != TP_EC_FAN_AUTO) &&
4133 (level != TP_EC_FAN_FULLSPEED) &&
4134 ((level < 0) || (level > 7)))
4135 return -EINVAL;
4136
4137 /* safety net should the EC not support AUTO
4138 * or FULLSPEED mode bits and just ignore them */
4139 if (level & TP_EC_FAN_FULLSPEED)
4140 level |= 7; /* safety min speed 7 */
4141 else if (level & TP_EC_FAN_FULLSPEED)
4142 level |= 4; /* safety min speed 4 */
4143
4144 if (!acpi_ec_write(fan_status_offset, level))
4145 return -EIO;
4146 else
4147 tp_features.fan_ctrl_status_undef = 0;
4148 break;
4149
4150 default:
4151 return -ENXIO;
4152 }
4153 return 0;
4154}
4155
4156static int fan_set_level_safe(int level)
4157{
4158 int rc;
4159
4160 if (!fan_control_allowed)
4161 return -EPERM;
4162
4163 if (mutex_lock_interruptible(&fan_mutex))
4164 return -ERESTARTSYS;
4165
4166 if (level == TPACPI_FAN_LAST_LEVEL)
4167 level = fan_control_desired_level;
4168
4169 rc = fan_set_level(level);
4170 if (!rc)
4171 fan_update_desired_level(level);
4172
4173 mutex_unlock(&fan_mutex);
4174 return rc;
4175}
4176
4177static int fan_set_enable(void)
4178{
4179 u8 s;
4180 int rc;
4181
4182 if (!fan_control_allowed)
4183 return -EPERM;
4184
4185 if (mutex_lock_interruptible(&fan_mutex))
4186 return -ERESTARTSYS;
4187
4188 switch (fan_control_access_mode) {
4189 case TPACPI_FAN_WR_ACPI_FANS:
4190 case TPACPI_FAN_WR_TPEC:
4191 rc = fan_get_status(&s);
4192 if (rc < 0)
4193 break;
4194
4195 /* Don't go out of emergency fan mode */
4196 if (s != 7) {
4197 s &= 0x07;
4198 s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
4199 }
4200
4201 if (!acpi_ec_write(fan_status_offset, s))
4202 rc = -EIO;
4203 else {
4204 tp_features.fan_ctrl_status_undef = 0;
4205 rc = 0;
4206 }
4207 break;
4208
4209 case TPACPI_FAN_WR_ACPI_SFAN:
4210 rc = fan_get_status(&s);
4211 if (rc < 0)
4212 break;
4213
4214 s &= 0x07;
4215
4216 /* Set fan to at least level 4 */
4217 s |= 4;
4218
4219 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
4220 rc= -EIO;
4221 else
4222 rc = 0;
4223 break;
4224
4225 default:
4226 rc = -ENXIO;
4227 }
4228
4229 mutex_unlock(&fan_mutex);
4230 return rc;
4231}
4232
4233static int fan_set_disable(void)
4234{
4235 int rc;
4236
4237 if (!fan_control_allowed)
4238 return -EPERM;
4239
4240 if (mutex_lock_interruptible(&fan_mutex))
4241 return -ERESTARTSYS;
4242
4243 rc = 0;
4244 switch (fan_control_access_mode) {
4245 case TPACPI_FAN_WR_ACPI_FANS:
4246 case TPACPI_FAN_WR_TPEC:
4247 if (!acpi_ec_write(fan_status_offset, 0x00))
4248 rc = -EIO;
4249 else {
4250 fan_control_desired_level = 0;
4251 tp_features.fan_ctrl_status_undef = 0;
4252 }
4253 break;
4254
4255 case TPACPI_FAN_WR_ACPI_SFAN:
4256 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
4257 rc = -EIO;
4258 else
4259 fan_control_desired_level = 0;
4260 break;
4261
4262 default:
4263 rc = -ENXIO;
4264 }
4265
4266
4267 mutex_unlock(&fan_mutex);
4268 return rc;
4269}
4270
4271static int fan_set_speed(int speed)
4272{
4273 int rc;
4274
4275 if (!fan_control_allowed)
4276 return -EPERM;
4277
4278 if (mutex_lock_interruptible(&fan_mutex))
4279 return -ERESTARTSYS;
4280
4281 rc = 0;
4282 switch (fan_control_access_mode) {
4283 case TPACPI_FAN_WR_ACPI_FANS:
4284 if (speed >= 0 && speed <= 65535) {
4285 if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
4286 speed, speed, speed))
4287 rc = -EIO;
4288 } else
4289 rc = -EINVAL;
4290 break;
4291
4292 default:
4293 rc = -ENXIO;
4294 }
4295
4296 mutex_unlock(&fan_mutex);
4297 return rc;
4298}
4299
4300static int fan_read(char *p) 5342static int fan_read(char *p)
4301{ 5343{
4302 int len = 0; 5344 int len = 0;
@@ -4307,7 +5349,8 @@ static int fan_read(char *p)
4307 switch (fan_status_access_mode) { 5349 switch (fan_status_access_mode) {
4308 case TPACPI_FAN_RD_ACPI_GFAN: 5350 case TPACPI_FAN_RD_ACPI_GFAN:
4309 /* 570, 600e/x, 770e, 770x */ 5351 /* 570, 600e/x, 770e, 770x */
4310 if ((rc = fan_get_status_safe(&status)) < 0) 5352 rc = fan_get_status_safe(&status);
5353 if (rc < 0)
4311 return rc; 5354 return rc;
4312 5355
4313 len += sprintf(p + len, "status:\t\t%s\n" 5356 len += sprintf(p + len, "status:\t\t%s\n"
@@ -4317,7 +5360,8 @@ static int fan_read(char *p)
4317 5360
4318 case TPACPI_FAN_RD_TPEC: 5361 case TPACPI_FAN_RD_TPEC:
4319 /* all except 570, 600e/x, 770e, 770x */ 5362 /* all except 570, 600e/x, 770e, 770x */
4320 if ((rc = fan_get_status_safe(&status)) < 0) 5363 rc = fan_get_status_safe(&status);
5364 if (rc < 0)
4321 return rc; 5365 return rc;
4322 5366
4323 if (unlikely(tp_features.fan_ctrl_status_undef)) { 5367 if (unlikely(tp_features.fan_ctrl_status_undef)) {
@@ -4332,7 +5376,8 @@ static int fan_read(char *p)
4332 len += sprintf(p + len, "status:\t\t%s\n", 5376 len += sprintf(p + len, "status:\t\t%s\n",
4333 (status != 0) ? "enabled" : "disabled"); 5377 (status != 0) ? "enabled" : "disabled");
4334 5378
4335 if ((rc = fan_get_speed(&speed)) < 0) 5379 rc = fan_get_speed(&speed);
5380 if (rc < 0)
4336 return rc; 5381 return rc;
4337 5382
4338 len += sprintf(p + len, "speed:\t\t%d\n", speed); 5383 len += sprintf(p + len, "speed:\t\t%d\n", speed);
@@ -4368,8 +5413,8 @@ static int fan_read(char *p)
4368 5413
4369 if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) 5414 if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
4370 len += sprintf(p + len, "commands:\tenable, disable\n" 5415 len += sprintf(p + len, "commands:\tenable, disable\n"
4371 "commands:\twatchdog <timeout> (<timeout> is 0 (off), " 5416 "commands:\twatchdog <timeout> (<timeout> "
4372 "1-120 (seconds))\n"); 5417 "is 0 (off), 1-120 (seconds))\n");
4373 5418
4374 if (fan_control_commands & TPACPI_FAN_CMD_SPEED) 5419 if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
4375 len += sprintf(p + len, "commands:\tspeed <speed>" 5420 len += sprintf(p + len, "commands:\tspeed <speed>"
@@ -4385,13 +5430,14 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
4385 if (strlencmp(cmd, "level auto") == 0) 5430 if (strlencmp(cmd, "level auto") == 0)
4386 level = TP_EC_FAN_AUTO; 5431 level = TP_EC_FAN_AUTO;
4387 else if ((strlencmp(cmd, "level disengaged") == 0) | 5432 else if ((strlencmp(cmd, "level disengaged") == 0) |
4388 (strlencmp(cmd, "level full-speed") == 0)) 5433 (strlencmp(cmd, "level full-speed") == 0))
4389 level = TP_EC_FAN_FULLSPEED; 5434 level = TP_EC_FAN_FULLSPEED;
4390 else if (sscanf(cmd, "level %d", &level) != 1) 5435 else if (sscanf(cmd, "level %d", &level) != 1)
4391 return 0; 5436 return 0;
4392 5437
4393 if ((*rc = fan_set_level_safe(level)) == -ENXIO) 5438 *rc = fan_set_level_safe(level);
4394 printk(IBM_ERR "level command accepted for unsupported " 5439 if (*rc == -ENXIO)
5440 printk(TPACPI_ERR "level command accepted for unsupported "
4395 "access mode %d", fan_control_access_mode); 5441 "access mode %d", fan_control_access_mode);
4396 5442
4397 return 1; 5443 return 1;
@@ -4402,8 +5448,9 @@ static int fan_write_cmd_enable(const char *cmd, int *rc)
4402 if (strlencmp(cmd, "enable") != 0) 5448 if (strlencmp(cmd, "enable") != 0)
4403 return 0; 5449 return 0;
4404 5450
4405 if ((*rc = fan_set_enable()) == -ENXIO) 5451 *rc = fan_set_enable();
4406 printk(IBM_ERR "enable command accepted for unsupported " 5452 if (*rc == -ENXIO)
5453 printk(TPACPI_ERR "enable command accepted for unsupported "
4407 "access mode %d", fan_control_access_mode); 5454 "access mode %d", fan_control_access_mode);
4408 5455
4409 return 1; 5456 return 1;
@@ -4414,8 +5461,9 @@ static int fan_write_cmd_disable(const char *cmd, int *rc)
4414 if (strlencmp(cmd, "disable") != 0) 5461 if (strlencmp(cmd, "disable") != 0)
4415 return 0; 5462 return 0;
4416 5463
4417 if ((*rc = fan_set_disable()) == -ENXIO) 5464 *rc = fan_set_disable();
4418 printk(IBM_ERR "disable command accepted for unsupported " 5465 if (*rc == -ENXIO)
5466 printk(TPACPI_ERR "disable command accepted for unsupported "
4419 "access mode %d", fan_control_access_mode); 5467 "access mode %d", fan_control_access_mode);
4420 5468
4421 return 1; 5469 return 1;
@@ -4431,8 +5479,9 @@ static int fan_write_cmd_speed(const char *cmd, int *rc)
4431 if (sscanf(cmd, "speed %d", &speed) != 1) 5479 if (sscanf(cmd, "speed %d", &speed) != 1)
4432 return 0; 5480 return 0;
4433 5481
4434 if ((*rc = fan_set_speed(speed)) == -ENXIO) 5482 *rc = fan_set_speed(speed);
4435 printk(IBM_ERR "speed command accepted for unsupported " 5483 if (*rc == -ENXIO)
5484 printk(TPACPI_ERR "speed command accepted for unsupported "
4436 "access mode %d", fan_control_access_mode); 5485 "access mode %d", fan_control_access_mode);
4437 5486
4438 return 1; 5487 return 1;
@@ -4496,7 +5545,7 @@ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev,
4496 struct device_attribute *attr, 5545 struct device_attribute *attr,
4497 char *buf) 5546 char *buf)
4498{ 5547{
4499 return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME); 5548 return snprintf(buf, PAGE_SIZE, "%s\n", TPACPI_NAME);
4500} 5549}
4501 5550
4502static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = 5551static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
@@ -4507,14 +5556,12 @@ static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
4507/* /proc support */ 5556/* /proc support */
4508static struct proc_dir_entry *proc_dir; 5557static struct proc_dir_entry *proc_dir;
4509 5558
4510/* Subdriver registry */
4511static LIST_HEAD(tpacpi_all_drivers);
4512
4513
4514/* 5559/*
4515 * Module and infrastructure proble, init and exit handling 5560 * Module and infrastructure proble, init and exit handling
4516 */ 5561 */
4517 5562
5563static int force_load;
5564
4518#ifdef CONFIG_THINKPAD_ACPI_DEBUG 5565#ifdef CONFIG_THINKPAD_ACPI_DEBUG
4519static const char * __init str_supported(int is_supported) 5566static const char * __init str_supported(int is_supported)
4520{ 5567{
@@ -4524,6 +5571,48 @@ static const char * __init str_supported(int is_supported)
4524} 5571}
4525#endif /* CONFIG_THINKPAD_ACPI_DEBUG */ 5572#endif /* CONFIG_THINKPAD_ACPI_DEBUG */
4526 5573
5574static void ibm_exit(struct ibm_struct *ibm)
5575{
5576 dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
5577
5578 list_del_init(&ibm->all_drivers);
5579
5580 if (ibm->flags.acpi_notify_installed) {
5581 dbg_printk(TPACPI_DBG_EXIT,
5582 "%s: acpi_remove_notify_handler\n", ibm->name);
5583 BUG_ON(!ibm->acpi);
5584 acpi_remove_notify_handler(*ibm->acpi->handle,
5585 ibm->acpi->type,
5586 dispatch_acpi_notify);
5587 ibm->flags.acpi_notify_installed = 0;
5588 ibm->flags.acpi_notify_installed = 0;
5589 }
5590
5591 if (ibm->flags.proc_created) {
5592 dbg_printk(TPACPI_DBG_EXIT,
5593 "%s: remove_proc_entry\n", ibm->name);
5594 remove_proc_entry(ibm->name, proc_dir);
5595 ibm->flags.proc_created = 0;
5596 }
5597
5598 if (ibm->flags.acpi_driver_registered) {
5599 dbg_printk(TPACPI_DBG_EXIT,
5600 "%s: acpi_bus_unregister_driver\n", ibm->name);
5601 BUG_ON(!ibm->acpi);
5602 acpi_bus_unregister_driver(ibm->acpi->driver);
5603 kfree(ibm->acpi->driver);
5604 ibm->acpi->driver = NULL;
5605 ibm->flags.acpi_driver_registered = 0;
5606 }
5607
5608 if (ibm->flags.init_called && ibm->exit) {
5609 ibm->exit();
5610 ibm->flags.init_called = 0;
5611 }
5612
5613 dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
5614}
5615
4527static int __init ibm_init(struct ibm_init_struct *iibm) 5616static int __init ibm_init(struct ibm_init_struct *iibm)
4528{ 5617{
4529 int ret; 5618 int ret;
@@ -4560,7 +5649,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
4560 if (ibm->acpi->notify) { 5649 if (ibm->acpi->notify) {
4561 ret = setup_acpi_notify(ibm); 5650 ret = setup_acpi_notify(ibm);
4562 if (ret == -ENODEV) { 5651 if (ret == -ENODEV) {
4563 printk(IBM_NOTICE "disabling subdriver %s\n", 5652 printk(TPACPI_NOTICE "disabling subdriver %s\n",
4564 ibm->name); 5653 ibm->name);
4565 ret = 0; 5654 ret = 0;
4566 goto err_out; 5655 goto err_out;
@@ -4578,7 +5667,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm)
4578 S_IFREG | S_IRUGO | S_IWUSR, 5667 S_IFREG | S_IRUGO | S_IWUSR,
4579 proc_dir); 5668 proc_dir);
4580 if (!entry) { 5669 if (!entry) {
4581 printk(IBM_ERR "unable to create proc entry %s\n", 5670 printk(TPACPI_ERR "unable to create proc entry %s\n",
4582 ibm->name); 5671 ibm->name);
4583 ret = -ENODEV; 5672 ret = -ENODEV;
4584 goto err_out; 5673 goto err_out;
@@ -4604,48 +5693,6 @@ err_out:
4604 return (ret < 0)? ret : 0; 5693 return (ret < 0)? ret : 0;
4605} 5694}
4606 5695
4607static void ibm_exit(struct ibm_struct *ibm)
4608{
4609 dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
4610
4611 list_del_init(&ibm->all_drivers);
4612
4613 if (ibm->flags.acpi_notify_installed) {
4614 dbg_printk(TPACPI_DBG_EXIT,
4615 "%s: acpi_remove_notify_handler\n", ibm->name);
4616 BUG_ON(!ibm->acpi);
4617 acpi_remove_notify_handler(*ibm->acpi->handle,
4618 ibm->acpi->type,
4619 dispatch_acpi_notify);
4620 ibm->flags.acpi_notify_installed = 0;
4621 ibm->flags.acpi_notify_installed = 0;
4622 }
4623
4624 if (ibm->flags.proc_created) {
4625 dbg_printk(TPACPI_DBG_EXIT,
4626 "%s: remove_proc_entry\n", ibm->name);
4627 remove_proc_entry(ibm->name, proc_dir);
4628 ibm->flags.proc_created = 0;
4629 }
4630
4631 if (ibm->flags.acpi_driver_registered) {
4632 dbg_printk(TPACPI_DBG_EXIT,
4633 "%s: acpi_bus_unregister_driver\n", ibm->name);
4634 BUG_ON(!ibm->acpi);
4635 acpi_bus_unregister_driver(ibm->acpi->driver);
4636 kfree(ibm->acpi->driver);
4637 ibm->acpi->driver = NULL;
4638 ibm->flags.acpi_driver_registered = 0;
4639 }
4640
4641 if (ibm->flags.init_called && ibm->exit) {
4642 ibm->exit();
4643 ibm->flags.init_called = 0;
4644 }
4645
4646 dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
4647}
4648
4649/* Probing */ 5696/* Probing */
4650 5697
4651static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) 5698static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
@@ -4715,10 +5762,10 @@ static int __init probe_for_thinkpad(void)
4715 is_thinkpad = (thinkpad_id.model_str != NULL); 5762 is_thinkpad = (thinkpad_id.model_str != NULL);
4716 5763
4717 /* ec is required because many other handles are relative to it */ 5764 /* ec is required because many other handles are relative to it */
4718 IBM_ACPIHANDLE_INIT(ec); 5765 TPACPI_ACPIHANDLE_INIT(ec);
4719 if (!ec_handle) { 5766 if (!ec_handle) {
4720 if (is_thinkpad) 5767 if (is_thinkpad)
4721 printk(IBM_ERR 5768 printk(TPACPI_ERR
4722 "Not yet supported ThinkPad detected!\n"); 5769 "Not yet supported ThinkPad detected!\n");
4723 return -ENODEV; 5770 return -ENODEV;
4724 } 5771 }
@@ -4839,47 +5886,110 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp)
4839 return -EINVAL; 5886 return -EINVAL;
4840} 5887}
4841 5888
4842static int experimental;
4843module_param(experimental, int, 0); 5889module_param(experimental, int, 0);
5890MODULE_PARM_DESC(experimental,
5891 "Enables experimental features when non-zero");
4844 5892
4845static u32 dbg_level;
4846module_param_named(debug, dbg_level, uint, 0); 5893module_param_named(debug, dbg_level, uint, 0);
5894MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
4847 5895
4848static int force_load;
4849module_param(force_load, bool, 0); 5896module_param(force_load, bool, 0);
5897MODULE_PARM_DESC(force_load,
5898 "Attempts to load the driver even on a "
5899 "mis-identified ThinkPad when true");
4850 5900
4851static int fan_control_allowed;
4852module_param_named(fan_control, fan_control_allowed, bool, 0); 5901module_param_named(fan_control, fan_control_allowed, bool, 0);
5902MODULE_PARM_DESC(fan_control,
5903 "Enables setting fan parameters features when true");
4853 5904
4854static int brightness_mode;
4855module_param_named(brightness_mode, brightness_mode, int, 0); 5905module_param_named(brightness_mode, brightness_mode, int, 0);
5906MODULE_PARM_DESC(brightness_mode,
5907 "Selects brightness control strategy: "
5908 "0=auto, 1=EC, 2=CMOS, 3=both");
4856 5909
4857static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
4858module_param(brightness_enable, uint, 0); 5910module_param(brightness_enable, uint, 0);
5911MODULE_PARM_DESC(brightness_enable,
5912 "Enables backlight control when 1, disables when 0");
4859 5913
4860static unsigned int hotkey_report_mode;
4861module_param(hotkey_report_mode, uint, 0); 5914module_param(hotkey_report_mode, uint, 0);
4862 5915MODULE_PARM_DESC(hotkey_report_mode,
4863#define IBM_PARAM(feature) \ 5916 "used for backwards compatibility with userspace, "
4864 module_param_call(feature, set_ibm_param, NULL, NULL, 0) 5917 "see documentation");
4865 5918
4866IBM_PARAM(hotkey); 5919#define TPACPI_PARAM(feature) \
4867IBM_PARAM(bluetooth); 5920 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
4868IBM_PARAM(video); 5921 MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \
4869IBM_PARAM(light); 5922 "at module load, see documentation")
5923
5924TPACPI_PARAM(hotkey);
5925TPACPI_PARAM(bluetooth);
5926TPACPI_PARAM(video);
5927TPACPI_PARAM(light);
4870#ifdef CONFIG_THINKPAD_ACPI_DOCK 5928#ifdef CONFIG_THINKPAD_ACPI_DOCK
4871IBM_PARAM(dock); 5929TPACPI_PARAM(dock);
4872#endif 5930#endif
4873#ifdef CONFIG_THINKPAD_ACPI_BAY 5931#ifdef CONFIG_THINKPAD_ACPI_BAY
4874IBM_PARAM(bay); 5932TPACPI_PARAM(bay);
4875#endif /* CONFIG_THINKPAD_ACPI_BAY */ 5933#endif /* CONFIG_THINKPAD_ACPI_BAY */
4876IBM_PARAM(cmos); 5934TPACPI_PARAM(cmos);
4877IBM_PARAM(led); 5935TPACPI_PARAM(led);
4878IBM_PARAM(beep); 5936TPACPI_PARAM(beep);
4879IBM_PARAM(ecdump); 5937TPACPI_PARAM(ecdump);
4880IBM_PARAM(brightness); 5938TPACPI_PARAM(brightness);
4881IBM_PARAM(volume); 5939TPACPI_PARAM(volume);
4882IBM_PARAM(fan); 5940TPACPI_PARAM(fan);
5941
5942static void thinkpad_acpi_module_exit(void)
5943{
5944 struct ibm_struct *ibm, *itmp;
5945
5946 tpacpi_lifecycle = TPACPI_LIFE_EXITING;
5947
5948 list_for_each_entry_safe_reverse(ibm, itmp,
5949 &tpacpi_all_drivers,
5950 all_drivers) {
5951 ibm_exit(ibm);
5952 }
5953
5954 dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
5955
5956 if (tpacpi_inputdev) {
5957 if (tp_features.input_device_registered)
5958 input_unregister_device(tpacpi_inputdev);
5959 else
5960 input_free_device(tpacpi_inputdev);
5961 }
5962
5963 if (tpacpi_hwmon)
5964 hwmon_device_unregister(tpacpi_hwmon);
5965
5966 if (tp_features.sensors_pdev_attrs_registered)
5967 device_remove_file(&tpacpi_sensors_pdev->dev,
5968 &dev_attr_thinkpad_acpi_pdev_name);
5969 if (tpacpi_sensors_pdev)
5970 platform_device_unregister(tpacpi_sensors_pdev);
5971 if (tpacpi_pdev)
5972 platform_device_unregister(tpacpi_pdev);
5973
5974 if (tp_features.sensors_pdrv_attrs_registered)
5975 tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
5976 if (tp_features.platform_drv_attrs_registered)
5977 tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
5978
5979 if (tp_features.sensors_pdrv_registered)
5980 platform_driver_unregister(&tpacpi_hwmon_pdriver);
5981
5982 if (tp_features.platform_drv_registered)
5983 platform_driver_unregister(&tpacpi_pdriver);
5984
5985 if (proc_dir)
5986 remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
5987
5988 kfree(thinkpad_id.bios_version_str);
5989 kfree(thinkpad_id.ec_version_str);
5990 kfree(thinkpad_id.model_str);
5991}
5992
4883 5993
4884static int __init thinkpad_acpi_module_init(void) 5994static int __init thinkpad_acpi_module_init(void)
4885{ 5995{
@@ -4902,12 +6012,13 @@ static int __init thinkpad_acpi_module_init(void)
4902 6012
4903 /* Driver initialization */ 6013 /* Driver initialization */
4904 6014
4905 IBM_ACPIHANDLE_INIT(ecrd); 6015 TPACPI_ACPIHANDLE_INIT(ecrd);
4906 IBM_ACPIHANDLE_INIT(ecwr); 6016 TPACPI_ACPIHANDLE_INIT(ecwr);
4907 6017
4908 proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir); 6018 proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir);
4909 if (!proc_dir) { 6019 if (!proc_dir) {
4910 printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR); 6020 printk(TPACPI_ERR
6021 "unable to create proc dir " TPACPI_PROC_DIR);
4911 thinkpad_acpi_module_exit(); 6022 thinkpad_acpi_module_exit();
4912 return -ENODEV; 6023 return -ENODEV;
4913 } 6024 }
@@ -4915,7 +6026,8 @@ static int __init thinkpad_acpi_module_init(void)
4915 6026
4916 ret = platform_driver_register(&tpacpi_pdriver); 6027 ret = platform_driver_register(&tpacpi_pdriver);
4917 if (ret) { 6028 if (ret) {
4918 printk(IBM_ERR "unable to register main platform driver\n"); 6029 printk(TPACPI_ERR
6030 "unable to register main platform driver\n");
4919 thinkpad_acpi_module_exit(); 6031 thinkpad_acpi_module_exit();
4920 return ret; 6032 return ret;
4921 } 6033 }
@@ -4923,7 +6035,8 @@ static int __init thinkpad_acpi_module_init(void)
4923 6035
4924 ret = platform_driver_register(&tpacpi_hwmon_pdriver); 6036 ret = platform_driver_register(&tpacpi_hwmon_pdriver);
4925 if (ret) { 6037 if (ret) {
4926 printk(IBM_ERR "unable to register hwmon platform driver\n"); 6038 printk(TPACPI_ERR
6039 "unable to register hwmon platform driver\n");
4927 thinkpad_acpi_module_exit(); 6040 thinkpad_acpi_module_exit();
4928 return ret; 6041 return ret;
4929 } 6042 }
@@ -4932,10 +6045,12 @@ static int __init thinkpad_acpi_module_init(void)
4932 ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); 6045 ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
4933 if (!ret) { 6046 if (!ret) {
4934 tp_features.platform_drv_attrs_registered = 1; 6047 tp_features.platform_drv_attrs_registered = 1;
4935 ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver); 6048 ret = tpacpi_create_driver_attributes(
6049 &tpacpi_hwmon_pdriver.driver);
4936 } 6050 }
4937 if (ret) { 6051 if (ret) {
4938 printk(IBM_ERR "unable to create sysfs driver attributes\n"); 6052 printk(TPACPI_ERR
6053 "unable to create sysfs driver attributes\n");
4939 thinkpad_acpi_module_exit(); 6054 thinkpad_acpi_module_exit();
4940 return ret; 6055 return ret;
4941 } 6056 }
@@ -4943,30 +6058,31 @@ static int __init thinkpad_acpi_module_init(void)
4943 6058
4944 6059
4945 /* Device initialization */ 6060 /* Device initialization */
4946 tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1, 6061 tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1,
4947 NULL, 0); 6062 NULL, 0);
4948 if (IS_ERR(tpacpi_pdev)) { 6063 if (IS_ERR(tpacpi_pdev)) {
4949 ret = PTR_ERR(tpacpi_pdev); 6064 ret = PTR_ERR(tpacpi_pdev);
4950 tpacpi_pdev = NULL; 6065 tpacpi_pdev = NULL;
4951 printk(IBM_ERR "unable to register platform device\n"); 6066 printk(TPACPI_ERR "unable to register platform device\n");
4952 thinkpad_acpi_module_exit(); 6067 thinkpad_acpi_module_exit();
4953 return ret; 6068 return ret;
4954 } 6069 }
4955 tpacpi_sensors_pdev = platform_device_register_simple( 6070 tpacpi_sensors_pdev = platform_device_register_simple(
4956 IBM_HWMON_DRVR_NAME, 6071 TPACPI_HWMON_DRVR_NAME,
4957 -1, NULL, 0); 6072 -1, NULL, 0);
4958 if (IS_ERR(tpacpi_sensors_pdev)) { 6073 if (IS_ERR(tpacpi_sensors_pdev)) {
4959 ret = PTR_ERR(tpacpi_sensors_pdev); 6074 ret = PTR_ERR(tpacpi_sensors_pdev);
4960 tpacpi_sensors_pdev = NULL; 6075 tpacpi_sensors_pdev = NULL;
4961 printk(IBM_ERR "unable to register hwmon platform device\n"); 6076 printk(TPACPI_ERR
6077 "unable to register hwmon platform device\n");
4962 thinkpad_acpi_module_exit(); 6078 thinkpad_acpi_module_exit();
4963 return ret; 6079 return ret;
4964 } 6080 }
4965 ret = device_create_file(&tpacpi_sensors_pdev->dev, 6081 ret = device_create_file(&tpacpi_sensors_pdev->dev,
4966 &dev_attr_thinkpad_acpi_pdev_name); 6082 &dev_attr_thinkpad_acpi_pdev_name);
4967 if (ret) { 6083 if (ret) {
4968 printk(IBM_ERR 6084 printk(TPACPI_ERR
4969 "unable to create sysfs hwmon device attributes\n"); 6085 "unable to create sysfs hwmon device attributes\n");
4970 thinkpad_acpi_module_exit(); 6086 thinkpad_acpi_module_exit();
4971 return ret; 6087 return ret;
4972 } 6088 }
@@ -4975,20 +6091,20 @@ static int __init thinkpad_acpi_module_init(void)
4975 if (IS_ERR(tpacpi_hwmon)) { 6091 if (IS_ERR(tpacpi_hwmon)) {
4976 ret = PTR_ERR(tpacpi_hwmon); 6092 ret = PTR_ERR(tpacpi_hwmon);
4977 tpacpi_hwmon = NULL; 6093 tpacpi_hwmon = NULL;
4978 printk(IBM_ERR "unable to register hwmon device\n"); 6094 printk(TPACPI_ERR "unable to register hwmon device\n");
4979 thinkpad_acpi_module_exit(); 6095 thinkpad_acpi_module_exit();
4980 return ret; 6096 return ret;
4981 } 6097 }
4982 mutex_init(&tpacpi_inputdev_send_mutex); 6098 mutex_init(&tpacpi_inputdev_send_mutex);
4983 tpacpi_inputdev = input_allocate_device(); 6099 tpacpi_inputdev = input_allocate_device();
4984 if (!tpacpi_inputdev) { 6100 if (!tpacpi_inputdev) {
4985 printk(IBM_ERR "unable to allocate input device\n"); 6101 printk(TPACPI_ERR "unable to allocate input device\n");
4986 thinkpad_acpi_module_exit(); 6102 thinkpad_acpi_module_exit();
4987 return -ENOMEM; 6103 return -ENOMEM;
4988 } else { 6104 } else {
4989 /* Prepare input device, but don't register */ 6105 /* Prepare input device, but don't register */
4990 tpacpi_inputdev->name = "ThinkPad Extra Buttons"; 6106 tpacpi_inputdev->name = "ThinkPad Extra Buttons";
4991 tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0"; 6107 tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0";
4992 tpacpi_inputdev->id.bustype = BUS_HOST; 6108 tpacpi_inputdev->id.bustype = BUS_HOST;
4993 tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? 6109 tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
4994 thinkpad_id.vendor : 6110 thinkpad_id.vendor :
@@ -5007,7 +6123,7 @@ static int __init thinkpad_acpi_module_init(void)
5007 } 6123 }
5008 ret = input_register_device(tpacpi_inputdev); 6124 ret = input_register_device(tpacpi_inputdev);
5009 if (ret < 0) { 6125 if (ret < 0) {
5010 printk(IBM_ERR "unable to register input device\n"); 6126 printk(TPACPI_ERR "unable to register input device\n");
5011 thinkpad_acpi_module_exit(); 6127 thinkpad_acpi_module_exit();
5012 return ret; 6128 return ret;
5013 } else { 6129 } else {
@@ -5018,56 +6134,36 @@ static int __init thinkpad_acpi_module_init(void)
5018 return 0; 6134 return 0;
5019} 6135}
5020 6136
5021static void thinkpad_acpi_module_exit(void) 6137/* Please remove this in year 2009 */
5022{ 6138MODULE_ALIAS("ibm_acpi");
5023 struct ibm_struct *ibm, *itmp;
5024
5025 tpacpi_lifecycle = TPACPI_LIFE_EXITING;
5026
5027 list_for_each_entry_safe_reverse(ibm, itmp,
5028 &tpacpi_all_drivers,
5029 all_drivers) {
5030 ibm_exit(ibm);
5031 }
5032
5033 dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
5034
5035 if (tpacpi_inputdev) {
5036 if (tp_features.input_device_registered)
5037 input_unregister_device(tpacpi_inputdev);
5038 else
5039 input_free_device(tpacpi_inputdev);
5040 }
5041
5042 if (tpacpi_hwmon)
5043 hwmon_device_unregister(tpacpi_hwmon);
5044
5045 if (tp_features.sensors_pdev_attrs_registered)
5046 device_remove_file(&tpacpi_sensors_pdev->dev,
5047 &dev_attr_thinkpad_acpi_pdev_name);
5048 if (tpacpi_sensors_pdev)
5049 platform_device_unregister(tpacpi_sensors_pdev);
5050 if (tpacpi_pdev)
5051 platform_device_unregister(tpacpi_pdev);
5052
5053 if (tp_features.sensors_pdrv_attrs_registered)
5054 tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
5055 if (tp_features.platform_drv_attrs_registered)
5056 tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
5057 6139
5058 if (tp_features.sensors_pdrv_registered) 6140/*
5059 platform_driver_unregister(&tpacpi_hwmon_pdriver); 6141 * DMI matching for module autoloading
6142 *
6143 * See http://thinkwiki.org/wiki/List_of_DMI_IDs
6144 * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
6145 *
6146 * Only models listed in thinkwiki will be supported, so add yours
6147 * if it is not there yet.
6148 */
6149#define IBM_BIOS_MODULE_ALIAS(__type) \
6150 MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
5060 6151
5061 if (tp_features.platform_drv_registered) 6152/* Non-ancient thinkpads */
5062 platform_driver_unregister(&tpacpi_pdriver); 6153MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
6154MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
5063 6155
5064 if (proc_dir) 6156/* Ancient thinkpad BIOSes have to be identified by
5065 remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); 6157 * BIOS type or model number, and there are far less
6158 * BIOS types than model numbers... */
6159IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
6160IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
6161IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
5066 6162
5067 kfree(thinkpad_id.bios_version_str); 6163MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
5068 kfree(thinkpad_id.ec_version_str); 6164MODULE_DESCRIPTION(TPACPI_DESC);
5069 kfree(thinkpad_id.model_str); 6165MODULE_VERSION(TPACPI_VERSION);
5070} 6166MODULE_LICENSE("GPL");
5071 6167
5072module_init(thinkpad_acpi_module_init); 6168module_init(thinkpad_acpi_module_init);
5073module_exit(thinkpad_acpi_module_exit); 6169module_exit(thinkpad_acpi_module_exit);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
deleted file mode 100644
index 8fba2bbe345e..000000000000
--- a/drivers/misc/thinkpad_acpi.h
+++ /dev/null
@@ -1,606 +0,0 @@
1/*
2 * thinkpad_acpi.h - ThinkPad ACPI Extras
3 *
4 *
5 * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
6 * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#ifndef __THINKPAD_ACPI_H__
25#define __THINKPAD_ACPI_H__
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/types.h>
31#include <linux/string.h>
32#include <linux/list.h>
33#include <linux/mutex.h>
34
35#include <linux/nvram.h>
36#include <linux/proc_fs.h>
37#include <linux/sysfs.h>
38#include <linux/backlight.h>
39#include <linux/fb.h>
40#include <linux/platform_device.h>
41#include <linux/hwmon.h>
42#include <linux/hwmon-sysfs.h>
43#include <linux/input.h>
44#include <asm/uaccess.h>
45
46#include <linux/dmi.h>
47#include <linux/jiffies.h>
48#include <linux/workqueue.h>
49
50#include <acpi/acpi_drivers.h>
51#include <acpi/acnamesp.h>
52
53#include <linux/pci_ids.h>
54
55/****************************************************************************
56 * Main driver
57 */
58
59#define IBM_NAME "thinkpad"
60#define IBM_DESC "ThinkPad ACPI Extras"
61#define IBM_FILE IBM_NAME "_acpi"
62#define IBM_URL "http://ibm-acpi.sf.net/"
63#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
64
65#define IBM_PROC_DIR "ibm"
66#define IBM_ACPI_EVENT_PREFIX "ibm"
67#define IBM_DRVR_NAME IBM_FILE
68#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon"
69
70#define IBM_LOG IBM_FILE ": "
71#define IBM_ERR KERN_ERR IBM_LOG
72#define IBM_NOTICE KERN_NOTICE IBM_LOG
73#define IBM_INFO KERN_INFO IBM_LOG
74#define IBM_DEBUG KERN_DEBUG IBM_LOG
75
76#define IBM_MAX_ACPI_ARGS 3
77
78/* ThinkPad CMOS commands */
79#define TP_CMOS_VOLUME_DOWN 0
80#define TP_CMOS_VOLUME_UP 1
81#define TP_CMOS_VOLUME_MUTE 2
82#define TP_CMOS_BRIGHTNESS_UP 4
83#define TP_CMOS_BRIGHTNESS_DOWN 5
84
85/* ThinkPad CMOS NVRAM constants */
86#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
87#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f
88#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
89
90#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
91#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
92#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
93
94/* Debugging */
95#define TPACPI_DBG_ALL 0xffff
96#define TPACPI_DBG_ALL 0xffff
97#define TPACPI_DBG_INIT 0x0001
98#define TPACPI_DBG_EXIT 0x0002
99#define dbg_printk(a_dbg_level, format, arg...) \
100 do { if (dbg_level & a_dbg_level) \
101 printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
102#ifdef CONFIG_THINKPAD_ACPI_DEBUG
103#define vdbg_printk(a_dbg_level, format, arg...) \
104 dbg_printk(a_dbg_level, format, ## arg)
105static const char *str_supported(int is_supported);
106#else
107#define vdbg_printk(a_dbg_level, format, arg...)
108#endif
109
110/* Input IDs */
111#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM
112#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
113#define TPACPI_HKEY_INPUT_VERSION 0x4101
114
115/* ACPI HIDs */
116#define IBM_HKEY_HID "IBM0068"
117
118/* ACPI helpers */
119static int __must_check acpi_evalf(acpi_handle handle,
120 void *res, char *method, char *fmt, ...);
121static int __must_check acpi_ec_read(int i, u8 * p);
122static int __must_check acpi_ec_write(int i, u8 v);
123static int __must_check _sta(acpi_handle handle);
124
125/* ACPI handles */
126static acpi_handle root_handle; /* root namespace */
127static acpi_handle ec_handle; /* EC */
128static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */
129static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */
130
131static void drv_acpi_handle_init(char *name,
132 acpi_handle *handle, acpi_handle parent,
133 char **paths, int num_paths, char **path);
134#define IBM_ACPIHANDLE_INIT(object) \
135 drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
136 object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
137
138/* ThinkPad ACPI helpers */
139static int issue_thinkpad_cmos_command(int cmos_cmd);
140
141/* procfs support */
142static struct proc_dir_entry *proc_dir;
143
144/* procfs helpers */
145static int dispatch_procfs_read(char *page, char **start, off_t off,
146 int count, int *eof, void *data);
147static int dispatch_procfs_write(struct file *file,
148 const char __user * userbuf,
149 unsigned long count, void *data);
150static char *next_cmd(char **cmds);
151
152/* sysfs support */
153struct attribute_set {
154 unsigned int members, max_members;
155 struct attribute_group group;
156};
157
158static struct attribute_set *create_attr_set(unsigned int max_members,
159 const char* name);
160#define destroy_attr_set(_set) \
161 kfree(_set);
162static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
163static int add_many_to_attr_set(struct attribute_set* s,
164 struct attribute **attr,
165 unsigned int count);
166#define register_attr_set_with_sysfs(_attr_set, _kobj) \
167 sysfs_create_group(_kobj, &_attr_set->group)
168static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
169
170static int parse_strtoul(const char *buf, unsigned long max,
171 unsigned long *value);
172
173/* Device model */
174static struct platform_device *tpacpi_pdev;
175static struct platform_device *tpacpi_sensors_pdev;
176static struct device *tpacpi_hwmon;
177static struct platform_driver tpacpi_pdriver;
178static struct input_dev *tpacpi_inputdev;
179static int tpacpi_create_driver_attributes(struct device_driver *drv);
180static void tpacpi_remove_driver_attributes(struct device_driver *drv);
181
182/* Module */
183static int experimental;
184static u32 dbg_level;
185static int force_load;
186static unsigned int hotkey_report_mode;
187
188static int thinkpad_acpi_module_init(void);
189static void thinkpad_acpi_module_exit(void);
190
191
192/****************************************************************************
193 * Subdrivers
194 */
195
196struct ibm_struct;
197
198struct tp_acpi_drv_struct {
199 const struct acpi_device_id *hid;
200 struct acpi_driver *driver;
201
202 void (*notify) (struct ibm_struct *, u32);
203 acpi_handle *handle;
204 u32 type;
205 struct acpi_device *device;
206};
207
208struct ibm_struct {
209 char *name;
210
211 int (*read) (char *);
212 int (*write) (char *);
213 void (*exit) (void);
214 void (*resume) (void);
215
216 struct list_head all_drivers;
217
218 struct tp_acpi_drv_struct *acpi;
219
220 struct {
221 u8 acpi_driver_registered:1;
222 u8 acpi_notify_installed:1;
223 u8 proc_created:1;
224 u8 init_called:1;
225 u8 experimental:1;
226 } flags;
227};
228
229struct ibm_init_struct {
230 char param[32];
231
232 int (*init) (struct ibm_init_struct *);
233 struct ibm_struct *data;
234};
235
236static struct {
237#ifdef CONFIG_THINKPAD_ACPI_BAY
238 u32 bay_status:1;
239 u32 bay_eject:1;
240 u32 bay_status2:1;
241 u32 bay_eject2:1;
242#endif
243 u32 bluetooth:1;
244 u32 hotkey:1;
245 u32 hotkey_mask:1;
246 u32 hotkey_wlsw:1;
247 u32 light:1;
248 u32 light_status:1;
249 u32 bright_16levels:1;
250 u32 wan:1;
251 u32 fan_ctrl_status_undef:1;
252 u32 input_device_registered:1;
253 u32 platform_drv_registered:1;
254 u32 platform_drv_attrs_registered:1;
255 u32 sensors_pdrv_registered:1;
256 u32 sensors_pdrv_attrs_registered:1;
257 u32 sensors_pdev_attrs_registered:1;
258} tp_features;
259
260struct thinkpad_id_data {
261 unsigned int vendor; /* ThinkPad vendor:
262 * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
263
264 char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
265 char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
266
267 u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
268 u16 ec_model;
269
270 char *model_str;
271};
272
273static struct thinkpad_id_data thinkpad_id;
274
275static struct list_head tpacpi_all_drivers;
276
277static struct ibm_init_struct ibms_init[];
278static int set_ibm_param(const char *val, struct kernel_param *kp);
279static int ibm_init(struct ibm_init_struct *iibm);
280static void ibm_exit(struct ibm_struct *ibm);
281
282
283/*
284 * procfs master subdriver
285 */
286static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
287static int thinkpad_acpi_driver_read(char *p);
288
289
290/*
291 * Bay subdriver
292 */
293
294#ifdef CONFIG_THINKPAD_ACPI_BAY
295static acpi_handle bay_handle, bay_ej_handle;
296static acpi_handle bay2_handle, bay2_ej_handle;
297
298static int bay_init(struct ibm_init_struct *iibm);
299static void bay_notify(struct ibm_struct *ibm, u32 event);
300static int bay_read(char *p);
301static int bay_write(char *buf);
302#endif /* CONFIG_THINKPAD_ACPI_BAY */
303
304
305/*
306 * Beep subdriver
307 */
308
309static acpi_handle beep_handle;
310
311static int beep_read(char *p);
312static int beep_write(char *buf);
313
314
315/*
316 * Bluetooth subdriver
317 */
318
319enum {
320 /* ACPI GBDC/SBDC bits */
321 TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
322 TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
323 TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
324};
325
326static int bluetooth_init(struct ibm_init_struct *iibm);
327static int bluetooth_get_radiosw(void);
328static int bluetooth_set_radiosw(int radio_on);
329static int bluetooth_read(char *p);
330static int bluetooth_write(char *buf);
331
332
333/*
334 * Brightness (backlight) subdriver
335 */
336
337#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
338
339static struct backlight_device *ibm_backlight_device;
340static int brightness_offset = 0x31;
341static int brightness_mode;
342static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */
343
344static int brightness_init(struct ibm_init_struct *iibm);
345static void brightness_exit(void);
346static int brightness_get(struct backlight_device *bd);
347static int brightness_set(int value);
348static int brightness_update_status(struct backlight_device *bd);
349static int brightness_read(char *p);
350static int brightness_write(char *buf);
351
352
353/*
354 * CMOS subdriver
355 */
356
357static int cmos_read(char *p);
358static int cmos_write(char *buf);
359
360
361/*
362 * Dock subdriver
363 */
364
365#ifdef CONFIG_THINKPAD_ACPI_DOCK
366static acpi_handle pci_handle;
367static acpi_handle dock_handle;
368
369static void dock_notify(struct ibm_struct *ibm, u32 event);
370static int dock_read(char *p);
371static int dock_write(char *buf);
372#endif /* CONFIG_THINKPAD_ACPI_DOCK */
373
374
375/*
376 * EC dump subdriver
377 */
378
379static int ecdump_read(char *p) ;
380static int ecdump_write(char *buf);
381
382
383/*
384 * Fan subdriver
385 */
386
387enum { /* Fan control constants */
388 fan_status_offset = 0x2f, /* EC register 0x2f */
389 fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
390 * 0x84 must be read before 0x85 */
391
392 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
393 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
394
395 TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
396};
397
398enum fan_status_access_mode {
399 TPACPI_FAN_NONE = 0, /* No fan status or control */
400 TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
401 TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
402};
403
404enum fan_control_access_mode {
405 TPACPI_FAN_WR_NONE = 0, /* No fan control */
406 TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
407 TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
408 TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
409};
410
411enum fan_control_commands {
412 TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
413 TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
414 TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
415 * and also watchdog cmd */
416};
417
418static int fan_control_allowed;
419
420static enum fan_status_access_mode fan_status_access_mode;
421static enum fan_control_access_mode fan_control_access_mode;
422static enum fan_control_commands fan_control_commands;
423static u8 fan_control_initial_status;
424static u8 fan_control_desired_level;
425static int fan_watchdog_maxinterval;
426
427static struct mutex fan_mutex;
428
429static acpi_handle fans_handle, gfan_handle, sfan_handle;
430
431static int fan_init(struct ibm_init_struct *iibm);
432static void fan_exit(void);
433static int fan_get_status(u8 *status);
434static int fan_get_status_safe(u8 *status);
435static int fan_get_speed(unsigned int *speed);
436static void fan_update_desired_level(u8 status);
437static void fan_watchdog_fire(struct work_struct *ignored);
438static void fan_watchdog_reset(void);
439static int fan_set_level(int level);
440static int fan_set_level_safe(int level);
441static int fan_set_enable(void);
442static int fan_set_disable(void);
443static int fan_set_speed(int speed);
444static int fan_read(char *p);
445static int fan_write(char *buf);
446static int fan_write_cmd_level(const char *cmd, int *rc);
447static int fan_write_cmd_enable(const char *cmd, int *rc);
448static int fan_write_cmd_disable(const char *cmd, int *rc);
449static int fan_write_cmd_speed(const char *cmd, int *rc);
450static int fan_write_cmd_watchdog(const char *cmd, int *rc);
451
452
453/*
454 * Hotkey subdriver
455 */
456
457static int hotkey_orig_status;
458static u32 hotkey_orig_mask;
459
460static struct mutex hotkey_mutex;
461
462static int hotkey_init(struct ibm_init_struct *iibm);
463static void hotkey_exit(void);
464static int hotkey_get(int *status, u32 *mask);
465static int hotkey_set(int status, u32 mask);
466static void hotkey_notify(struct ibm_struct *ibm, u32 event);
467static int hotkey_read(char *p);
468static int hotkey_write(char *buf);
469
470
471/*
472 * LED subdriver
473 */
474
475enum led_access_mode {
476 TPACPI_LED_NONE = 0,
477 TPACPI_LED_570, /* 570 */
478 TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
479 TPACPI_LED_NEW, /* all others */
480};
481
482enum { /* For TPACPI_LED_OLD */
483 TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
484 TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
485 TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
486};
487
488static enum led_access_mode led_supported;
489static acpi_handle led_handle;
490
491static int led_init(struct ibm_init_struct *iibm);
492static int led_read(char *p);
493static int led_write(char *buf);
494
495/*
496 * Light (thinklight) subdriver
497 */
498
499static acpi_handle lght_handle, ledb_handle;
500
501static int light_init(struct ibm_init_struct *iibm);
502static int light_read(char *p);
503static int light_write(char *buf);
504
505
506/*
507 * Thermal subdriver
508 */
509
510enum thermal_access_mode {
511 TPACPI_THERMAL_NONE = 0, /* No thermal support */
512 TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
513 TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
514 TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
515 TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
516};
517
518enum { /* TPACPI_THERMAL_TPEC_* */
519 TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
520 TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
521 TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
522};
523
524#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
525struct ibm_thermal_sensors_struct {
526 s32 temp[TPACPI_MAX_THERMAL_SENSORS];
527};
528
529static enum thermal_access_mode thermal_read_mode;
530
531static int thermal_init(struct ibm_init_struct *iibm);
532static int thermal_get_sensor(int idx, s32 *value);
533static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
534static int thermal_read(char *p);
535
536
537/*
538 * Video subdriver
539 */
540
541enum video_access_mode {
542 TPACPI_VIDEO_NONE = 0,
543 TPACPI_VIDEO_570, /* 570 */
544 TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
545 TPACPI_VIDEO_NEW, /* all others */
546};
547
548enum { /* video status flags, based on VIDEO_570 */
549 TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
550 TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
551 TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
552};
553
554enum { /* TPACPI_VIDEO_570 constants */
555 TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
556 TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
557 * video_status_flags */
558 TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
559 TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
560};
561
562static enum video_access_mode video_supported;
563static int video_orig_autosw;
564static acpi_handle vid_handle, vid2_handle;
565
566static int video_init(struct ibm_init_struct *iibm);
567static void video_exit(void);
568static int video_outputsw_get(void);
569static int video_outputsw_set(int status);
570static int video_autosw_get(void);
571static int video_autosw_set(int enable);
572static int video_outputsw_cycle(void);
573static int video_expand_toggle(void);
574static int video_read(char *p);
575static int video_write(char *buf);
576
577
578/*
579 * Volume subdriver
580 */
581
582static int volume_offset = 0x30;
583
584static int volume_read(char *p);
585static int volume_write(char *buf);
586
587
588/*
589 * Wan subdriver
590 */
591
592enum {
593 /* ACPI GWAN/SWAN bits */
594 TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
595 TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
596 TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
597};
598
599static int wan_init(struct ibm_init_struct *iibm);
600static int wan_get_radiosw(void);
601static int wan_set_radiosw(int radio_on);
602static int wan_read(char *p);
603static int wan_write(char *buf);
604
605
606#endif /* __THINKPAD_ACPI_H */
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index dada89906314..662b4c279cfc 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -183,7 +183,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
183 if (ACPI_SUCCESS(status)) 183 if (ACPI_SUCCESS(status))
184 dev->capabilities |= PNP_CONFIGURABLE; 184 dev->capabilities |= PNP_CONFIGURABLE;
185 dev->capabilities |= PNP_READ; 185 dev->capabilities |= PNP_READ;
186 if (device->flags.dynamic_status) 186 if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE))
187 dev->capabilities |= PNP_WRITE; 187 dev->capabilities |= PNP_WRITE;
188 if (device->flags.removable) 188 if (device->flags.removable)
189 dev->capabilities |= PNP_REMOVABLE; 189 dev->capabilities |= PNP_REMOVABLE;
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 13399d133b94..c444d6b10c58 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -115,6 +115,7 @@ static struct device_attribute power_supply_attrs[] = {
115 /* Properties of type `const char *' */ 115 /* Properties of type `const char *' */
116 POWER_SUPPLY_ATTR(model_name), 116 POWER_SUPPLY_ATTR(model_name),
117 POWER_SUPPLY_ATTR(manufacturer), 117 POWER_SUPPLY_ATTR(manufacturer),
118 POWER_SUPPLY_ATTR(serial_number),
118}; 119};
119 120
120static ssize_t power_supply_show_static_attrs(struct device *dev, 121static ssize_t power_supply_show_static_attrs(struct device *dev,
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
new file mode 100644
index 000000000000..9b3f61200000
--- /dev/null
+++ b/drivers/thermal/Kconfig
@@ -0,0 +1,15 @@
1#
2# Generic thermal sysfs drivers configuration
3#
4
5menuconfig THERMAL
6 bool "Generic Thermal sysfs driver"
7 default y
8 help
9 Generic Thermal Sysfs driver offers a generic mechanism for
10 thermal management. Usually it's made up of one or more thermal
11 zone and cooling device.
12 each thermal zone contains its own temperature, trip points,
13 cooling devices.
14 All platforms with ACPI thermal support can use this driver.
15 If you want this support, you should say Y here
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
new file mode 100644
index 000000000000..8ef1232de376
--- /dev/null
+++ b/drivers/thermal/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for sensor chip drivers.
3#
4
5obj-$(CONFIG_THERMAL) += thermal.o
diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c
new file mode 100644
index 000000000000..3273e348fd14
--- /dev/null
+++ b/drivers/thermal/thermal.c
@@ -0,0 +1,714 @@
1/*
2 * thermal.c - Generic Thermal Management Sysfs support.
3 *
4 * Copyright (C) 2008 Intel Corp
5 * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
6 * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
7 *
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 */
25
26#include <linux/module.h>
27#include <linux/device.h>
28#include <linux/err.h>
29#include <linux/kdev_t.h>
30#include <linux/idr.h>
31#include <linux/thermal.h>
32#include <linux/spinlock.h>
33
34MODULE_AUTHOR("Zhang Rui")
35MODULE_DESCRIPTION("Generic thermal management sysfs support");
36MODULE_LICENSE("GPL");
37
38#define PREFIX "Thermal: "
39
40struct thermal_cooling_device_instance {
41 int id;
42 char name[THERMAL_NAME_LENGTH];
43 struct thermal_zone_device *tz;
44 struct thermal_cooling_device *cdev;
45 int trip;
46 char attr_name[THERMAL_NAME_LENGTH];
47 struct device_attribute attr;
48 struct list_head node;
49};
50
51static DEFINE_IDR(thermal_tz_idr);
52static DEFINE_IDR(thermal_cdev_idr);
53static DEFINE_MUTEX(thermal_idr_lock);
54
55static LIST_HEAD(thermal_tz_list);
56static LIST_HEAD(thermal_cdev_list);
57static DEFINE_MUTEX(thermal_list_lock);
58
59static int get_idr(struct idr *idr, struct mutex *lock, int *id)
60{
61 int err;
62
63 again:
64 if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
65 return -ENOMEM;
66
67 if (lock)
68 mutex_lock(lock);
69 err = idr_get_new(idr, NULL, id);
70 if (lock)
71 mutex_unlock(lock);
72 if (unlikely(err == -EAGAIN))
73 goto again;
74 else if (unlikely(err))
75 return err;
76
77 *id = *id & MAX_ID_MASK;
78 return 0;
79}
80
81static void release_idr(struct idr *idr, struct mutex *lock, int id)
82{
83 if (lock)
84 mutex_lock(lock);
85 idr_remove(idr, id);
86 if (lock)
87 mutex_unlock(lock);
88}
89
90/* sys I/F for thermal zone */
91
92#define to_thermal_zone(_dev) \
93 container_of(_dev, struct thermal_zone_device, device)
94
95static ssize_t
96type_show(struct device *dev, struct device_attribute *attr, char *buf)
97{
98 struct thermal_zone_device *tz = to_thermal_zone(dev);
99
100 return sprintf(buf, "%s\n", tz->type);
101}
102
103static ssize_t
104temp_show(struct device *dev, struct device_attribute *attr, char *buf)
105{
106 struct thermal_zone_device *tz = to_thermal_zone(dev);
107
108 if (!tz->ops->get_temp)
109 return -EPERM;
110
111 return tz->ops->get_temp(tz, buf);
112}
113
114static ssize_t
115mode_show(struct device *dev, struct device_attribute *attr, char *buf)
116{
117 struct thermal_zone_device *tz = to_thermal_zone(dev);
118
119 if (!tz->ops->get_mode)
120 return -EPERM;
121
122 return tz->ops->get_mode(tz, buf);
123}
124
125static ssize_t
126mode_store(struct device *dev, struct device_attribute *attr,
127 const char *buf, size_t count)
128{
129 struct thermal_zone_device *tz = to_thermal_zone(dev);
130 int result;
131
132 if (!tz->ops->set_mode)
133 return -EPERM;
134
135 result = tz->ops->set_mode(tz, buf);
136 if (result)
137 return result;
138
139 return count;
140}
141
142static ssize_t
143trip_point_type_show(struct device *dev, struct device_attribute *attr,
144 char *buf)
145{
146 struct thermal_zone_device *tz = to_thermal_zone(dev);
147 int trip;
148
149 if (!tz->ops->get_trip_type)
150 return -EPERM;
151
152 if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
153 return -EINVAL;
154
155 return tz->ops->get_trip_type(tz, trip, buf);
156}
157
158static ssize_t
159trip_point_temp_show(struct device *dev, struct device_attribute *attr,
160 char *buf)
161{
162 struct thermal_zone_device *tz = to_thermal_zone(dev);
163 int trip;
164
165 if (!tz->ops->get_trip_temp)
166 return -EPERM;
167
168 if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
169 return -EINVAL;
170
171 return tz->ops->get_trip_temp(tz, trip, buf);
172}
173
174static DEVICE_ATTR(type, 0444, type_show, NULL);
175static DEVICE_ATTR(temp, 0444, temp_show, NULL);
176static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
177
178static struct device_attribute trip_point_attrs[] = {
179 __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
180 __ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL),
181 __ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL),
182 __ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL),
183 __ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL),
184 __ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL),
185 __ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL),
186 __ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL),
187 __ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL),
188 __ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL),
189 __ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL),
190 __ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL),
191 __ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL),
192 __ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL),
193 __ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL),
194 __ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL),
195 __ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL),
196 __ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL),
197 __ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL),
198 __ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL),
199};
200
201#define TRIP_POINT_ATTR_ADD(_dev, _index, result) \
202do { \
203 result = device_create_file(_dev, \
204 &trip_point_attrs[_index * 2]); \
205 if (result) \
206 break; \
207 result = device_create_file(_dev, \
208 &trip_point_attrs[_index * 2 + 1]); \
209} while (0)
210
211#define TRIP_POINT_ATTR_REMOVE(_dev, _index) \
212do { \
213 device_remove_file(_dev, &trip_point_attrs[_index * 2]); \
214 device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \
215} while (0)
216
217/* sys I/F for cooling device */
218#define to_cooling_device(_dev) \
219 container_of(_dev, struct thermal_cooling_device, device)
220
221static ssize_t
222thermal_cooling_device_type_show(struct device *dev,
223 struct device_attribute *attr, char *buf)
224{
225 struct thermal_cooling_device *cdev = to_cooling_device(dev);
226
227 return sprintf(buf, "%s\n", cdev->type);
228}
229
230static ssize_t
231thermal_cooling_device_max_state_show(struct device *dev,
232 struct device_attribute *attr, char *buf)
233{
234 struct thermal_cooling_device *cdev = to_cooling_device(dev);
235
236 return cdev->ops->get_max_state(cdev, buf);
237}
238
239static ssize_t
240thermal_cooling_device_cur_state_show(struct device *dev,
241 struct device_attribute *attr, char *buf)
242{
243 struct thermal_cooling_device *cdev = to_cooling_device(dev);
244
245 return cdev->ops->get_cur_state(cdev, buf);
246}
247
248static ssize_t
249thermal_cooling_device_cur_state_store(struct device *dev,
250 struct device_attribute *attr,
251 const char *buf, size_t count)
252{
253 struct thermal_cooling_device *cdev = to_cooling_device(dev);
254 int state;
255 int result;
256
257 if (!sscanf(buf, "%d\n", &state))
258 return -EINVAL;
259
260 if (state < 0)
261 return -EINVAL;
262
263 result = cdev->ops->set_cur_state(cdev, state);
264 if (result)
265 return result;
266 return count;
267}
268
269static struct device_attribute dev_attr_cdev_type =
270 __ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
271static DEVICE_ATTR(max_state, 0444,
272 thermal_cooling_device_max_state_show, NULL);
273static DEVICE_ATTR(cur_state, 0644,
274 thermal_cooling_device_cur_state_show,
275 thermal_cooling_device_cur_state_store);
276
277static ssize_t
278thermal_cooling_device_trip_point_show(struct device *dev,
279 struct device_attribute *attr, char *buf)
280{
281 struct thermal_cooling_device_instance *instance;
282
283 instance =
284 container_of(attr, struct thermal_cooling_device_instance, attr);
285
286 if (instance->trip == THERMAL_TRIPS_NONE)
287 return sprintf(buf, "-1\n");
288 else
289 return sprintf(buf, "%d\n", instance->trip);
290}
291
292/* Device management */
293
294/**
295 * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
296 * this function is usually called in the thermal zone device .bind callback.
297 * @tz: thermal zone device
298 * @trip: indicates which trip point the cooling devices is
299 * associated with in this thermal zone.
300 * @cdev: thermal cooling device
301 */
302int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
303 int trip,
304 struct thermal_cooling_device *cdev)
305{
306 struct thermal_cooling_device_instance *dev;
307 struct thermal_cooling_device_instance *pos;
308 int result;
309
310 if (trip >= tz->trips ||
311 (trip < 0 && trip != THERMAL_TRIPS_NONE))
312 return -EINVAL;
313
314 if (!tz || !cdev)
315 return -EINVAL;
316
317 dev =
318 kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL);
319 if (!dev)
320 return -ENOMEM;
321 dev->tz = tz;
322 dev->cdev = cdev;
323 dev->trip = trip;
324 result = get_idr(&tz->idr, &tz->lock, &dev->id);
325 if (result)
326 goto free_mem;
327
328 sprintf(dev->name, "cdev%d", dev->id);
329 result =
330 sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
331 if (result)
332 goto release_idr;
333
334 sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
335 dev->attr.attr.name = dev->attr_name;
336 dev->attr.attr.mode = 0444;
337 dev->attr.show = thermal_cooling_device_trip_point_show;
338 result = device_create_file(&tz->device, &dev->attr);
339 if (result)
340 goto remove_symbol_link;
341
342 mutex_lock(&tz->lock);
343 list_for_each_entry(pos, &tz->cooling_devices, node)
344 if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
345 result = -EEXIST;
346 break;
347 }
348 if (!result)
349 list_add_tail(&dev->node, &tz->cooling_devices);
350 mutex_unlock(&tz->lock);
351
352 if (!result)
353 return 0;
354
355 device_remove_file(&tz->device, &dev->attr);
356 remove_symbol_link:
357 sysfs_remove_link(&tz->device.kobj, dev->name);
358 release_idr:
359 release_idr(&tz->idr, &tz->lock, dev->id);
360 free_mem:
361 kfree(dev);
362 return result;
363}
364EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
365
366/**
367 * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
368 * this function is usually called in the thermal zone device .unbind callback.
369 * @tz: thermal zone device
370 * @trip: indicates which trip point the cooling devices is
371 * associated with in this thermal zone.
372 * @cdev: thermal cooling device
373 */
374int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
375 int trip,
376 struct thermal_cooling_device *cdev)
377{
378 struct thermal_cooling_device_instance *pos, *next;
379
380 mutex_lock(&tz->lock);
381 list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) {
382 if (pos->tz == tz && pos->trip == trip
383 && pos->cdev == cdev) {
384 list_del(&pos->node);
385 mutex_unlock(&tz->lock);
386 goto unbind;
387 }
388 }
389 mutex_unlock(&tz->lock);
390
391 return -ENODEV;
392
393 unbind:
394 device_remove_file(&tz->device, &pos->attr);
395 sysfs_remove_link(&tz->device.kobj, pos->name);
396 release_idr(&tz->idr, &tz->lock, pos->id);
397 kfree(pos);
398 return 0;
399}
400EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
401
402static void thermal_release(struct device *dev)
403{
404 struct thermal_zone_device *tz;
405 struct thermal_cooling_device *cdev;
406
407 if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) {
408 tz = to_thermal_zone(dev);
409 kfree(tz);
410 } else {
411 cdev = to_cooling_device(dev);
412 kfree(cdev);
413 }
414}
415
416static struct class thermal_class = {
417 .name = "thermal",
418 .dev_release = thermal_release,
419};
420
421/**
422 * thermal_cooling_device_register - register a new thermal cooling device
423 * @type: the thermal cooling device type.
424 * @devdata: device private data.
425 * @ops: standard thermal cooling devices callbacks.
426 */
427struct thermal_cooling_device *thermal_cooling_device_register(char *type,
428 void *devdata, struct thermal_cooling_device_ops *ops)
429{
430 struct thermal_cooling_device *cdev;
431 struct thermal_zone_device *pos;
432 int result;
433
434 if (strlen(type) >= THERMAL_NAME_LENGTH)
435 return NULL;
436
437 if (!ops || !ops->get_max_state || !ops->get_cur_state ||
438 !ops->set_cur_state)
439 return NULL;
440
441 cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
442 if (!cdev)
443 return NULL;
444
445 result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
446 if (result) {
447 kfree(cdev);
448 return NULL;
449 }
450
451 strcpy(cdev->type, type);
452 cdev->ops = ops;
453 cdev->device.class = &thermal_class;
454 cdev->devdata = devdata;
455 sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id);
456 result = device_register(&cdev->device);
457 if (result) {
458 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
459 kfree(cdev);
460 return NULL;
461 }
462
463 /* sys I/F */
464 if (type) {
465 result = device_create_file(&cdev->device,
466 &dev_attr_cdev_type);
467 if (result)
468 goto unregister;
469 }
470
471 result = device_create_file(&cdev->device, &dev_attr_max_state);
472 if (result)
473 goto unregister;
474
475 result = device_create_file(&cdev->device, &dev_attr_cur_state);
476 if (result)
477 goto unregister;
478
479 mutex_lock(&thermal_list_lock);
480 list_add(&cdev->node, &thermal_cdev_list);
481 list_for_each_entry(pos, &thermal_tz_list, node) {
482 if (!pos->ops->bind)
483 continue;
484 result = pos->ops->bind(pos, cdev);
485 if (result)
486 break;
487
488 }
489 mutex_unlock(&thermal_list_lock);
490
491 if (!result)
492 return cdev;
493
494 unregister:
495 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
496 device_unregister(&cdev->device);
497 return NULL;
498}
499EXPORT_SYMBOL(thermal_cooling_device_register);
500
501/**
502 * thermal_cooling_device_unregister - removes the registered thermal cooling device
503 *
504 * @cdev: the thermal cooling device to remove.
505 *
506 * thermal_cooling_device_unregister() must be called when the device is no
507 * longer needed.
508 */
509void thermal_cooling_device_unregister(struct
510 thermal_cooling_device
511 *cdev)
512{
513 struct thermal_zone_device *tz;
514 struct thermal_cooling_device *pos = NULL;
515
516 if (!cdev)
517 return;
518
519 mutex_lock(&thermal_list_lock);
520 list_for_each_entry(pos, &thermal_cdev_list, node)
521 if (pos == cdev)
522 break;
523 if (pos != cdev) {
524 /* thermal cooling device not found */
525 mutex_unlock(&thermal_list_lock);
526 return;
527 }
528 list_del(&cdev->node);
529 list_for_each_entry(tz, &thermal_tz_list, node) {
530 if (!tz->ops->unbind)
531 continue;
532 tz->ops->unbind(tz, cdev);
533 }
534 mutex_unlock(&thermal_list_lock);
535 if (cdev->type[0])
536 device_remove_file(&cdev->device,
537 &dev_attr_cdev_type);
538 device_remove_file(&cdev->device, &dev_attr_max_state);
539 device_remove_file(&cdev->device, &dev_attr_cur_state);
540
541 release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
542 device_unregister(&cdev->device);
543 return;
544}
545EXPORT_SYMBOL(thermal_cooling_device_unregister);
546
547/**
548 * thermal_zone_device_register - register a new thermal zone device
549 * @type: the thermal zone device type
550 * @trips: the number of trip points the thermal zone support
551 * @devdata: private device data
552 * @ops: standard thermal zone device callbacks
553 *
554 * thermal_zone_device_unregister() must be called when the device is no
555 * longer needed.
556 */
557struct thermal_zone_device *thermal_zone_device_register(char *type,
558 int trips, void *devdata,
559 struct thermal_zone_device_ops *ops)
560{
561 struct thermal_zone_device *tz;
562 struct thermal_cooling_device *pos;
563 int result;
564 int count;
565
566 if (strlen(type) >= THERMAL_NAME_LENGTH)
567 return NULL;
568
569 if (trips > THERMAL_MAX_TRIPS || trips < 0)
570 return NULL;
571
572 if (!ops || !ops->get_temp)
573 return NULL;
574
575 tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
576 if (!tz)
577 return NULL;
578
579 INIT_LIST_HEAD(&tz->cooling_devices);
580 idr_init(&tz->idr);
581 mutex_init(&tz->lock);
582 result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
583 if (result) {
584 kfree(tz);
585 return NULL;
586 }
587
588 strcpy(tz->type, type);
589 tz->ops = ops;
590 tz->device.class = &thermal_class;
591 tz->devdata = devdata;
592 tz->trips = trips;
593 sprintf(tz->device.bus_id, "thermal_zone%d", tz->id);
594 result = device_register(&tz->device);
595 if (result) {
596 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
597 kfree(tz);
598 return NULL;
599 }
600
601 /* sys I/F */
602 if (type) {
603 result = device_create_file(&tz->device, &dev_attr_type);
604 if (result)
605 goto unregister;
606 }
607
608 result = device_create_file(&tz->device, &dev_attr_temp);
609 if (result)
610 goto unregister;
611
612 if (ops->get_mode) {
613 result = device_create_file(&tz->device, &dev_attr_mode);
614 if (result)
615 goto unregister;
616 }
617
618 for (count = 0; count < trips; count++) {
619 TRIP_POINT_ATTR_ADD(&tz->device, count, result);
620 if (result)
621 goto unregister;
622 }
623
624 mutex_lock(&thermal_list_lock);
625 list_add_tail(&tz->node, &thermal_tz_list);
626 if (ops->bind)
627 list_for_each_entry(pos, &thermal_cdev_list, node) {
628 result = ops->bind(tz, pos);
629 if (result)
630 break;
631 }
632 mutex_unlock(&thermal_list_lock);
633
634 if (!result)
635 return tz;
636
637 unregister:
638 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
639 device_unregister(&tz->device);
640 return NULL;
641}
642EXPORT_SYMBOL(thermal_zone_device_register);
643
644/**
645 * thermal_device_unregister - removes the registered thermal zone device
646 *
647 * @tz: the thermal zone device to remove
648 */
649void thermal_zone_device_unregister(struct thermal_zone_device *tz)
650{
651 struct thermal_cooling_device *cdev;
652 struct thermal_zone_device *pos = NULL;
653 int count;
654
655 if (!tz)
656 return;
657
658 mutex_lock(&thermal_list_lock);
659 list_for_each_entry(pos, &thermal_tz_list, node)
660 if (pos == tz)
661 break;
662 if (pos != tz) {
663 /* thermal zone device not found */
664 mutex_unlock(&thermal_list_lock);
665 return;
666 }
667 list_del(&tz->node);
668 if (tz->ops->unbind)
669 list_for_each_entry(cdev, &thermal_cdev_list, node)
670 tz->ops->unbind(tz, cdev);
671 mutex_unlock(&thermal_list_lock);
672
673 if (tz->type[0])
674 device_remove_file(&tz->device, &dev_attr_type);
675 device_remove_file(&tz->device, &dev_attr_temp);
676 if (tz->ops->get_mode)
677 device_remove_file(&tz->device, &dev_attr_mode);
678
679 for (count = 0; count < tz->trips; count++)
680 TRIP_POINT_ATTR_REMOVE(&tz->device, count);
681
682 release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
683 idr_destroy(&tz->idr);
684 mutex_destroy(&tz->lock);
685 device_unregister(&tz->device);
686 return;
687}
688EXPORT_SYMBOL(thermal_zone_device_unregister);
689
690static int __init thermal_init(void)
691{
692 int result = 0;
693
694 result = class_register(&thermal_class);
695 if (result) {
696 idr_destroy(&thermal_tz_idr);
697 idr_destroy(&thermal_cdev_idr);
698 mutex_destroy(&thermal_idr_lock);
699 mutex_destroy(&thermal_list_lock);
700 }
701 return result;
702}
703
704static void __exit thermal_exit(void)
705{
706 class_unregister(&thermal_class);
707 idr_destroy(&thermal_tz_idr);
708 idr_destroy(&thermal_cdev_idr);
709 mutex_destroy(&thermal_idr_lock);
710 mutex_destroy(&thermal_list_lock);
711}
712
713subsys_initcall(thermal_init);
714module_exit(thermal_exit);