diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-19 16:12:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-19 16:12:46 -0400 |
commit | c4ec20717313daafba59225f812db89595952b83 (patch) | |
tree | 253337453b1dc965c40668e4949337ed1c46cab7 /drivers/misc | |
parent | ec2626815bf9a9922e49820b03e670e833f3ca3c (diff) | |
parent | 00a2b433557f10736e8a02de619b3e9052556c12 (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: (41 commits)
ACPICA: hw: Don't carry spinlock over suspend
ACPICA: hw: remove use_lock flag from acpi_hw_register_{read, write}
ACPI: cpuidle: port idle timer suspend/resume workaround to cpuidle
ACPI: clean up acpi_enter_sleep_state_prep
Hibernation: Make sure that ACPI is enabled in acpi_hibernation_finish
ACPI: suppress uninitialized var warning
cpuidle: consolidate 2.6.22 cpuidle branch into one patch
ACPI: thinkpad-acpi: skip blanks before the data when parsing sysfs
ACPI: AC: Add sysfs interface
ACPI: SBS: Add sysfs alarm
ACPI: SBS: Add ACPI_PROCFS around procfs handling code.
ACPI: SBS: Add support for power_supply class (and sysfs)
ACPI: SBS: Make SBS reads table-driven.
ACPI: SBS: Simplify data structures in SBS
ACPI: SBS: Split host controller (ACPI0001) from SBS driver (ACPI0002)
ACPI: EC: Add new query handler to list head.
ACPI: Add acpi_bus_generate_event4() function
ACPI: Battery: add sysfs alarm
ACPI: Battery: Add sysfs support
ACPI: Battery: Misc clean-ups, no functional changes
...
Fix up conflicts in drivers/misc/thinkpad_acpi.[ch] manually
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 17 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/fujitsu-laptop.c | 358 | ||||
-rw-r--r-- | drivers/misc/sony-laptop.c | 204 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 207 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.h | 37 |
6 files changed, 715 insertions, 109 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 346c44eff95e..cf02ddc3436f 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -111,6 +111,21 @@ config ASUS_LAPTOP | |||
111 | 111 | ||
112 | If you have an ACPI-compatible ASUS laptop, say Y or M here. | 112 | If you have an ACPI-compatible ASUS laptop, say Y or M here. |
113 | 113 | ||
114 | config FUJITSU_LAPTOP | ||
115 | tristate "Fujitsu Laptop Extras" | ||
116 | depends on X86 | ||
117 | depends on ACPI | ||
118 | depends on BACKLIGHT_CLASS_DEVICE | ||
119 | ---help--- | ||
120 | This is a driver for laptops built by Fujitsu: | ||
121 | |||
122 | * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks | ||
123 | * Possibly other Fujitsu laptop models | ||
124 | |||
125 | It adds support for LCD brightness control. | ||
126 | |||
127 | If you have a Fujitsu laptop, say Y or M here. | ||
128 | |||
114 | config MSI_LAPTOP | 129 | config MSI_LAPTOP |
115 | tristate "MSI Laptop Extras" | 130 | tristate "MSI Laptop Extras" |
116 | depends on X86 | 131 | depends on X86 |
@@ -134,6 +149,7 @@ config SONY_LAPTOP | |||
134 | tristate "Sony Laptop Extras" | 149 | tristate "Sony Laptop Extras" |
135 | depends on X86 && ACPI | 150 | depends on X86 && ACPI |
136 | select BACKLIGHT_CLASS_DEVICE | 151 | select BACKLIGHT_CLASS_DEVICE |
152 | depends on INPUT | ||
137 | ---help--- | 153 | ---help--- |
138 | This mini-driver drives the SNC and SPIC devices present in the ACPI | 154 | This mini-driver drives the SNC and SPIC devices present in the ACPI |
139 | BIOS of the Sony Vaio laptops. | 155 | BIOS of the Sony Vaio laptops. |
@@ -156,6 +172,7 @@ config THINKPAD_ACPI | |||
156 | select BACKLIGHT_CLASS_DEVICE | 172 | select BACKLIGHT_CLASS_DEVICE |
157 | select HWMON | 173 | select HWMON |
158 | select NVRAM | 174 | select NVRAM |
175 | depends on INPUT | ||
159 | ---help--- | 176 | ---help--- |
160 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds | 177 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds |
161 | support for Fn-Fx key combinations, Bluetooth control, video | 178 | support for Fn-Fx key combinations, Bluetooth control, video |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index a24c61475c2f..87f2685d728f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -15,4 +15,5 @@ obj-$(CONFIG_PHANTOM) += phantom.o | |||
15 | obj-$(CONFIG_SGI_IOC4) += ioc4.o | 15 | obj-$(CONFIG_SGI_IOC4) += ioc4.o |
16 | obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o | 16 | obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o |
17 | obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o | 17 | obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o |
18 | obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o | ||
18 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o | 19 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o |
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c new file mode 100644 index 000000000000..d366a6cc1fd9 --- /dev/null +++ b/drivers/misc/fujitsu-laptop.c | |||
@@ -0,0 +1,358 @@ | |||
1 | /*-*-linux-c-*-*/ | ||
2 | |||
3 | /* | ||
4 | Copyright (C) 2007 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> | ||
5 | Based on earlier work: | ||
6 | Copyright (C) 2003 Shane Spencer <shane@bogomip.com> | ||
7 | Adrian Yee <brewt-fujitsu@brewt.org> | ||
8 | |||
9 | Templated from msi-laptop.c which is copyright by its respective authors. | ||
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 | ||
14 | (at 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 | ||
22 | along with this program; if not, write to the Free Software | ||
23 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
24 | 02110-1301, USA. | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional | ||
29 | * features made available on a range of Fujitsu laptops including the | ||
30 | * P2xxx/P5xxx/S6xxx/S7xxx series. | ||
31 | * | ||
32 | * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/; | ||
33 | * others may be added at a later date. | ||
34 | * | ||
35 | * lcd_level - Screen brightness: contains a single integer in the | ||
36 | * range 0..7. (rw) | ||
37 | * | ||
38 | * In addition to these platform device attributes the driver | ||
39 | * registers itself in the Linux backlight control subsystem and is | ||
40 | * available to userspace under /sys/class/backlight/fujitsu-laptop/. | ||
41 | * | ||
42 | * This driver has been tested on a Fujitsu Lifebook S7020. It should | ||
43 | * work on most P-series and S-series Lifebooks, but YMMV. | ||
44 | */ | ||
45 | |||
46 | #include <linux/module.h> | ||
47 | #include <linux/kernel.h> | ||
48 | #include <linux/init.h> | ||
49 | #include <linux/acpi.h> | ||
50 | #include <linux/dmi.h> | ||
51 | #include <linux/backlight.h> | ||
52 | #include <linux/platform_device.h> | ||
53 | #include <linux/autoconf.h> | ||
54 | |||
55 | #define FUJITSU_DRIVER_VERSION "0.3" | ||
56 | |||
57 | #define FUJITSU_LCD_N_LEVELS 8 | ||
58 | |||
59 | #define ACPI_FUJITSU_CLASS "fujitsu" | ||
60 | #define ACPI_FUJITSU_HID "FUJ02B1" | ||
61 | #define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI extras driver" | ||
62 | #define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1" | ||
63 | |||
64 | struct fujitsu_t { | ||
65 | acpi_handle acpi_handle; | ||
66 | struct backlight_device *bl_device; | ||
67 | struct platform_device *pf_device; | ||
68 | |||
69 | unsigned long fuj02b1_state; | ||
70 | unsigned int brightness_changed; | ||
71 | unsigned int brightness_level; | ||
72 | }; | ||
73 | |||
74 | static struct fujitsu_t *fujitsu; | ||
75 | |||
76 | /* Hardware access */ | ||
77 | |||
78 | static int set_lcd_level(int level) | ||
79 | { | ||
80 | acpi_status status = AE_OK; | ||
81 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | ||
82 | struct acpi_object_list arg_list = { 1, &arg0 }; | ||
83 | acpi_handle handle = NULL; | ||
84 | |||
85 | if (level < 0 || level >= FUJITSU_LCD_N_LEVELS) | ||
86 | return -EINVAL; | ||
87 | |||
88 | if (!fujitsu) | ||
89 | return -EINVAL; | ||
90 | |||
91 | status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); | ||
92 | if (ACPI_FAILURE(status)) { | ||
93 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SBLL not present\n")); | ||
94 | return -ENODEV; | ||
95 | } | ||
96 | |||
97 | arg0.integer.value = level; | ||
98 | |||
99 | status = acpi_evaluate_object(handle, NULL, &arg_list, NULL); | ||
100 | if (ACPI_FAILURE(status)) | ||
101 | return -ENODEV; | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int get_lcd_level(void) | ||
107 | { | ||
108 | unsigned long state = 0; | ||
109 | acpi_status status = AE_OK; | ||
110 | |||
111 | // Get the Brightness | ||
112 | status = | ||
113 | acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); | ||
114 | if (status < 0) | ||
115 | return status; | ||
116 | |||
117 | fujitsu->fuj02b1_state = state; | ||
118 | fujitsu->brightness_level = state & 0x0fffffff; | ||
119 | |||
120 | if (state & 0x80000000) | ||
121 | fujitsu->brightness_changed = 1; | ||
122 | else | ||
123 | fujitsu->brightness_changed = 0; | ||
124 | |||
125 | if (status < 0) | ||
126 | return status; | ||
127 | |||
128 | return fujitsu->brightness_level; | ||
129 | } | ||
130 | |||
131 | /* Backlight device stuff */ | ||
132 | |||
133 | static int bl_get_brightness(struct backlight_device *b) | ||
134 | { | ||
135 | return get_lcd_level(); | ||
136 | } | ||
137 | |||
138 | static int bl_update_status(struct backlight_device *b) | ||
139 | { | ||
140 | return set_lcd_level(b->props.brightness); | ||
141 | } | ||
142 | |||
143 | static struct backlight_ops fujitsubl_ops = { | ||
144 | .get_brightness = bl_get_brightness, | ||
145 | .update_status = bl_update_status, | ||
146 | }; | ||
147 | |||
148 | /* Platform device */ | ||
149 | |||
150 | static ssize_t show_lcd_level(struct device *dev, | ||
151 | struct device_attribute *attr, char *buf) | ||
152 | { | ||
153 | |||
154 | int ret; | ||
155 | |||
156 | ret = get_lcd_level(); | ||
157 | if (ret < 0) | ||
158 | return ret; | ||
159 | |||
160 | return sprintf(buf, "%i\n", ret); | ||
161 | } | ||
162 | |||
163 | static ssize_t store_lcd_level(struct device *dev, | ||
164 | struct device_attribute *attr, const char *buf, | ||
165 | size_t count) | ||
166 | { | ||
167 | |||
168 | int level, ret; | ||
169 | |||
170 | if (sscanf(buf, "%i", &level) != 1 | ||
171 | || (level < 0 || level >= FUJITSU_LCD_N_LEVELS)) | ||
172 | return -EINVAL; | ||
173 | |||
174 | ret = set_lcd_level(level); | ||
175 | if (ret < 0) | ||
176 | return ret; | ||
177 | |||
178 | return count; | ||
179 | } | ||
180 | |||
181 | static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); | ||
182 | |||
183 | static struct attribute *fujitsupf_attributes[] = { | ||
184 | &dev_attr_lcd_level.attr, | ||
185 | NULL | ||
186 | }; | ||
187 | |||
188 | static struct attribute_group fujitsupf_attribute_group = { | ||
189 | .attrs = fujitsupf_attributes | ||
190 | }; | ||
191 | |||
192 | static struct platform_driver fujitsupf_driver = { | ||
193 | .driver = { | ||
194 | .name = "fujitsu-laptop", | ||
195 | .owner = THIS_MODULE, | ||
196 | } | ||
197 | }; | ||
198 | |||
199 | /* ACPI device */ | ||
200 | |||
201 | int acpi_fujitsu_add(struct acpi_device *device) | ||
202 | { | ||
203 | int result = 0; | ||
204 | int state = 0; | ||
205 | |||
206 | ACPI_FUNCTION_TRACE("acpi_fujitsu_add"); | ||
207 | |||
208 | if (!device) | ||
209 | return -EINVAL; | ||
210 | |||
211 | fujitsu->acpi_handle = device->handle; | ||
212 | sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME); | ||
213 | sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); | ||
214 | acpi_driver_data(device) = fujitsu; | ||
215 | |||
216 | result = acpi_bus_get_power(fujitsu->acpi_handle, &state); | ||
217 | if (result) { | ||
218 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
219 | "Error reading power state\n")); | ||
220 | goto end; | ||
221 | } | ||
222 | |||
223 | printk(KERN_INFO PREFIX "%s [%s] (%s)\n", | ||
224 | acpi_device_name(device), acpi_device_bid(device), | ||
225 | !device->power.state ? "on" : "off"); | ||
226 | |||
227 | end: | ||
228 | |||
229 | return result; | ||
230 | } | ||
231 | |||
232 | int acpi_fujitsu_remove(struct acpi_device *device, int type) | ||
233 | { | ||
234 | ACPI_FUNCTION_TRACE("acpi_fujitsu_remove"); | ||
235 | |||
236 | if (!device || !acpi_driver_data(device)) | ||
237 | return -EINVAL; | ||
238 | fujitsu->acpi_handle = 0; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static const struct acpi_device_id fujitsu_device_ids[] = { | ||
244 | {ACPI_FUJITSU_HID, 0}, | ||
245 | {"", 0}, | ||
246 | }; | ||
247 | |||
248 | static struct acpi_driver acpi_fujitsu_driver = { | ||
249 | .name = ACPI_FUJITSU_DRIVER_NAME, | ||
250 | .class = ACPI_FUJITSU_CLASS, | ||
251 | .ids = fujitsu_device_ids, | ||
252 | .ops = { | ||
253 | .add = acpi_fujitsu_add, | ||
254 | .remove = acpi_fujitsu_remove, | ||
255 | }, | ||
256 | }; | ||
257 | |||
258 | /* Initialization */ | ||
259 | |||
260 | static int __init fujitsu_init(void) | ||
261 | { | ||
262 | int ret, result; | ||
263 | |||
264 | if (acpi_disabled) | ||
265 | return -ENODEV; | ||
266 | |||
267 | fujitsu = kmalloc(sizeof(struct fujitsu_t), GFP_KERNEL); | ||
268 | if (!fujitsu) | ||
269 | return -ENOMEM; | ||
270 | memset(fujitsu, 0, sizeof(struct fujitsu_t)); | ||
271 | |||
272 | result = acpi_bus_register_driver(&acpi_fujitsu_driver); | ||
273 | if (result < 0) { | ||
274 | ret = -ENODEV; | ||
275 | goto fail_acpi; | ||
276 | } | ||
277 | |||
278 | /* Register backlight stuff */ | ||
279 | |||
280 | fujitsu->bl_device = | ||
281 | backlight_device_register("fujitsu-laptop", NULL, NULL, | ||
282 | &fujitsubl_ops); | ||
283 | if (IS_ERR(fujitsu->bl_device)) | ||
284 | return PTR_ERR(fujitsu->bl_device); | ||
285 | |||
286 | fujitsu->bl_device->props.max_brightness = FUJITSU_LCD_N_LEVELS - 1; | ||
287 | ret = platform_driver_register(&fujitsupf_driver); | ||
288 | if (ret) | ||
289 | goto fail_backlight; | ||
290 | |||
291 | /* Register platform stuff */ | ||
292 | |||
293 | fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1); | ||
294 | if (!fujitsu->pf_device) { | ||
295 | ret = -ENOMEM; | ||
296 | goto fail_platform_driver; | ||
297 | } | ||
298 | |||
299 | ret = platform_device_add(fujitsu->pf_device); | ||
300 | if (ret) | ||
301 | goto fail_platform_device1; | ||
302 | |||
303 | ret = | ||
304 | sysfs_create_group(&fujitsu->pf_device->dev.kobj, | ||
305 | &fujitsupf_attribute_group); | ||
306 | if (ret) | ||
307 | goto fail_platform_device2; | ||
308 | |||
309 | printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION | ||
310 | " successfully loaded.\n"); | ||
311 | |||
312 | return 0; | ||
313 | |||
314 | fail_platform_device2: | ||
315 | |||
316 | platform_device_del(fujitsu->pf_device); | ||
317 | |||
318 | fail_platform_device1: | ||
319 | |||
320 | platform_device_put(fujitsu->pf_device); | ||
321 | |||
322 | fail_platform_driver: | ||
323 | |||
324 | platform_driver_unregister(&fujitsupf_driver); | ||
325 | |||
326 | fail_backlight: | ||
327 | |||
328 | backlight_device_unregister(fujitsu->bl_device); | ||
329 | |||
330 | fail_acpi: | ||
331 | |||
332 | kfree(fujitsu); | ||
333 | |||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | static void __exit fujitsu_cleanup(void) | ||
338 | { | ||
339 | sysfs_remove_group(&fujitsu->pf_device->dev.kobj, | ||
340 | &fujitsupf_attribute_group); | ||
341 | platform_device_unregister(fujitsu->pf_device); | ||
342 | platform_driver_unregister(&fujitsupf_driver); | ||
343 | backlight_device_unregister(fujitsu->bl_device); | ||
344 | |||
345 | acpi_bus_unregister_driver(&acpi_fujitsu_driver); | ||
346 | |||
347 | kfree(fujitsu); | ||
348 | |||
349 | printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n"); | ||
350 | } | ||
351 | |||
352 | module_init(fujitsu_init); | ||
353 | module_exit(fujitsu_cleanup); | ||
354 | |||
355 | MODULE_AUTHOR("Jonathan Woithe"); | ||
356 | MODULE_DESCRIPTION("Fujitsu laptop extras support"); | ||
357 | MODULE_VERSION(FUJITSU_DRIVER_VERSION); | ||
358 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 86da96becd28..1bfbb87e5793 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c | |||
@@ -1173,7 +1173,8 @@ static struct acpi_driver sony_nc_driver = { | |||
1173 | #define SONYPI_TYPE3_OFFSET 0x12 | 1173 | #define SONYPI_TYPE3_OFFSET 0x12 |
1174 | 1174 | ||
1175 | struct sony_pic_ioport { | 1175 | struct sony_pic_ioport { |
1176 | struct acpi_resource_io io; | 1176 | struct acpi_resource_io io1; |
1177 | struct acpi_resource_io io2; | ||
1177 | struct list_head list; | 1178 | struct list_head list; |
1178 | }; | 1179 | }; |
1179 | 1180 | ||
@@ -1443,11 +1444,11 @@ static u8 sony_pic_call1(u8 dev) | |||
1443 | { | 1444 | { |
1444 | u8 v1, v2; | 1445 | u8 v1, v2; |
1445 | 1446 | ||
1446 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, | 1447 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, |
1447 | ITERATIONS_LONG); | 1448 | ITERATIONS_LONG); |
1448 | outb(dev, spic_dev.cur_ioport->io.minimum + 4); | 1449 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); |
1449 | v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4); | 1450 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); |
1450 | v2 = inb_p(spic_dev.cur_ioport->io.minimum); | 1451 | v2 = inb_p(spic_dev.cur_ioport->io1.minimum); |
1451 | dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); | 1452 | dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); |
1452 | return v2; | 1453 | return v2; |
1453 | } | 1454 | } |
@@ -1456,13 +1457,13 @@ static u8 sony_pic_call2(u8 dev, u8 fn) | |||
1456 | { | 1457 | { |
1457 | u8 v1; | 1458 | u8 v1; |
1458 | 1459 | ||
1459 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, | 1460 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, |
1460 | ITERATIONS_LONG); | 1461 | ITERATIONS_LONG); |
1461 | outb(dev, spic_dev.cur_ioport->io.minimum + 4); | 1462 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); |
1462 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, | 1463 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, |
1463 | ITERATIONS_LONG); | 1464 | ITERATIONS_LONG); |
1464 | outb(fn, spic_dev.cur_ioport->io.minimum); | 1465 | outb(fn, spic_dev.cur_ioport->io1.minimum); |
1465 | v1 = inb_p(spic_dev.cur_ioport->io.minimum); | 1466 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum); |
1466 | dprintk("sony_pic_call2: 0x%.4x\n", v1); | 1467 | dprintk("sony_pic_call2: 0x%.4x\n", v1); |
1467 | return v1; | 1468 | return v1; |
1468 | } | 1469 | } |
@@ -1471,13 +1472,13 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) | |||
1471 | { | 1472 | { |
1472 | u8 v1; | 1473 | u8 v1; |
1473 | 1474 | ||
1474 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); | 1475 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); |
1475 | outb(dev, spic_dev.cur_ioport->io.minimum + 4); | 1476 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); |
1476 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); | 1477 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); |
1477 | outb(fn, spic_dev.cur_ioport->io.minimum); | 1478 | outb(fn, spic_dev.cur_ioport->io1.minimum); |
1478 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); | 1479 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); |
1479 | outb(v, spic_dev.cur_ioport->io.minimum); | 1480 | outb(v, spic_dev.cur_ioport->io1.minimum); |
1480 | v1 = inb_p(spic_dev.cur_ioport->io.minimum); | 1481 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum); |
1481 | dprintk("sony_pic_call3: 0x%.4x\n", v1); | 1482 | dprintk("sony_pic_call3: 0x%.4x\n", v1); |
1482 | return v1; | 1483 | return v1; |
1483 | } | 1484 | } |
@@ -2074,7 +2075,18 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
2074 | 2075 | ||
2075 | switch (resource->type) { | 2076 | switch (resource->type) { |
2076 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | 2077 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
2078 | { | ||
2079 | /* start IO enumeration */ | ||
2080 | struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); | ||
2081 | if (!ioport) | ||
2082 | return AE_ERROR; | ||
2083 | |||
2084 | list_add(&ioport->list, &dev->ioports); | ||
2085 | return AE_OK; | ||
2086 | } | ||
2087 | |||
2077 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | 2088 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: |
2089 | /* end IO enumeration */ | ||
2078 | return AE_OK; | 2090 | return AE_OK; |
2079 | 2091 | ||
2080 | case ACPI_RESOURCE_TYPE_IRQ: | 2092 | case ACPI_RESOURCE_TYPE_IRQ: |
@@ -2101,7 +2113,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
2101 | if (!interrupt) | 2113 | if (!interrupt) |
2102 | return AE_ERROR; | 2114 | return AE_ERROR; |
2103 | 2115 | ||
2104 | list_add_tail(&interrupt->list, &dev->interrupts); | 2116 | list_add(&interrupt->list, &dev->interrupts); |
2105 | interrupt->irq.triggering = p->triggering; | 2117 | interrupt->irq.triggering = p->triggering; |
2106 | interrupt->irq.polarity = p->polarity; | 2118 | interrupt->irq.polarity = p->polarity; |
2107 | interrupt->irq.sharable = p->sharable; | 2119 | interrupt->irq.sharable = p->sharable; |
@@ -2113,18 +2125,27 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
2113 | case ACPI_RESOURCE_TYPE_IO: | 2125 | case ACPI_RESOURCE_TYPE_IO: |
2114 | { | 2126 | { |
2115 | struct acpi_resource_io *io = &resource->data.io; | 2127 | struct acpi_resource_io *io = &resource->data.io; |
2116 | struct sony_pic_ioport *ioport = NULL; | 2128 | struct sony_pic_ioport *ioport = |
2129 | list_first_entry(&dev->ioports, struct sony_pic_ioport, list); | ||
2117 | if (!io) { | 2130 | if (!io) { |
2118 | dprintk("Blank IO resource\n"); | 2131 | dprintk("Blank IO resource\n"); |
2119 | return AE_OK; | 2132 | return AE_OK; |
2120 | } | 2133 | } |
2121 | 2134 | ||
2122 | ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); | 2135 | if (!ioport->io1.minimum) { |
2123 | if (!ioport) | 2136 | memcpy(&ioport->io1, io, sizeof(*io)); |
2137 | dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum, | ||
2138 | ioport->io1.address_length); | ||
2139 | } | ||
2140 | else if (!ioport->io2.minimum) { | ||
2141 | memcpy(&ioport->io2, io, sizeof(*io)); | ||
2142 | dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum, | ||
2143 | ioport->io2.address_length); | ||
2144 | } | ||
2145 | else { | ||
2146 | printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); | ||
2124 | return AE_ERROR; | 2147 | return AE_ERROR; |
2125 | 2148 | } | |
2126 | list_add_tail(&ioport->list, &dev->ioports); | ||
2127 | memcpy(&ioport->io, io, sizeof(*io)); | ||
2128 | return AE_OK; | 2149 | return AE_OK; |
2129 | } | 2150 | } |
2130 | default: | 2151 | default: |
@@ -2199,10 +2220,22 @@ static int sony_pic_enable(struct acpi_device *device, | |||
2199 | { | 2220 | { |
2200 | acpi_status status; | 2221 | acpi_status status; |
2201 | int result = 0; | 2222 | int result = 0; |
2223 | /* Type 1 resource layout is: | ||
2224 | * IO | ||
2225 | * IO | ||
2226 | * IRQNoFlags | ||
2227 | * End | ||
2228 | * | ||
2229 | * Type 2 and 3 resource layout is: | ||
2230 | * IO | ||
2231 | * IRQNoFlags | ||
2232 | * End | ||
2233 | */ | ||
2202 | struct { | 2234 | struct { |
2203 | struct acpi_resource io_res; | 2235 | struct acpi_resource res1; |
2204 | struct acpi_resource irq_res; | 2236 | struct acpi_resource res2; |
2205 | struct acpi_resource end; | 2237 | struct acpi_resource res3; |
2238 | struct acpi_resource res4; | ||
2206 | } *resource; | 2239 | } *resource; |
2207 | struct acpi_buffer buffer = { 0, NULL }; | 2240 | struct acpi_buffer buffer = { 0, NULL }; |
2208 | 2241 | ||
@@ -2217,21 +2250,49 @@ static int sony_pic_enable(struct acpi_device *device, | |||
2217 | buffer.length = sizeof(*resource) + 1; | 2250 | buffer.length = sizeof(*resource) + 1; |
2218 | buffer.pointer = resource; | 2251 | buffer.pointer = resource; |
2219 | 2252 | ||
2220 | /* setup io resource */ | 2253 | /* setup Type 1 resources */ |
2221 | resource->io_res.type = ACPI_RESOURCE_TYPE_IO; | 2254 | if (spic_dev.model == SONYPI_DEVICE_TYPE1) { |
2222 | resource->io_res.length = sizeof(struct acpi_resource); | ||
2223 | memcpy(&resource->io_res.data.io, &ioport->io, | ||
2224 | sizeof(struct acpi_resource_io)); | ||
2225 | 2255 | ||
2226 | /* setup irq resource */ | 2256 | /* setup io resources */ |
2227 | resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ; | 2257 | resource->res1.type = ACPI_RESOURCE_TYPE_IO; |
2228 | resource->irq_res.length = sizeof(struct acpi_resource); | 2258 | resource->res1.length = sizeof(struct acpi_resource); |
2229 | memcpy(&resource->irq_res.data.irq, &irq->irq, | 2259 | memcpy(&resource->res1.data.io, &ioport->io1, |
2230 | sizeof(struct acpi_resource_irq)); | 2260 | sizeof(struct acpi_resource_io)); |
2231 | /* we requested a shared irq */ | ||
2232 | resource->irq_res.data.irq.sharable = ACPI_SHARED; | ||
2233 | 2261 | ||
2234 | resource->end.type = ACPI_RESOURCE_TYPE_END_TAG; | 2262 | resource->res2.type = ACPI_RESOURCE_TYPE_IO; |
2263 | resource->res2.length = sizeof(struct acpi_resource); | ||
2264 | memcpy(&resource->res2.data.io, &ioport->io2, | ||
2265 | sizeof(struct acpi_resource_io)); | ||
2266 | |||
2267 | /* setup irq resource */ | ||
2268 | resource->res3.type = ACPI_RESOURCE_TYPE_IRQ; | ||
2269 | resource->res3.length = sizeof(struct acpi_resource); | ||
2270 | memcpy(&resource->res3.data.irq, &irq->irq, | ||
2271 | sizeof(struct acpi_resource_irq)); | ||
2272 | /* we requested a shared irq */ | ||
2273 | resource->res3.data.irq.sharable = ACPI_SHARED; | ||
2274 | |||
2275 | resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG; | ||
2276 | |||
2277 | } | ||
2278 | /* setup Type 2/3 resources */ | ||
2279 | else { | ||
2280 | /* setup io resource */ | ||
2281 | resource->res1.type = ACPI_RESOURCE_TYPE_IO; | ||
2282 | resource->res1.length = sizeof(struct acpi_resource); | ||
2283 | memcpy(&resource->res1.data.io, &ioport->io1, | ||
2284 | sizeof(struct acpi_resource_io)); | ||
2285 | |||
2286 | /* setup irq resource */ | ||
2287 | resource->res2.type = ACPI_RESOURCE_TYPE_IRQ; | ||
2288 | resource->res2.length = sizeof(struct acpi_resource); | ||
2289 | memcpy(&resource->res2.data.irq, &irq->irq, | ||
2290 | sizeof(struct acpi_resource_irq)); | ||
2291 | /* we requested a shared irq */ | ||
2292 | resource->res2.data.irq.sharable = ACPI_SHARED; | ||
2293 | |||
2294 | resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG; | ||
2295 | } | ||
2235 | 2296 | ||
2236 | /* Attempt to set the resource */ | 2297 | /* Attempt to set the resource */ |
2237 | dprintk("Evaluating _SRS\n"); | 2298 | dprintk("Evaluating _SRS\n"); |
@@ -2239,7 +2300,7 @@ static int sony_pic_enable(struct acpi_device *device, | |||
2239 | 2300 | ||
2240 | /* check for total failure */ | 2301 | /* check for total failure */ |
2241 | if (ACPI_FAILURE(status)) { | 2302 | if (ACPI_FAILURE(status)) { |
2242 | printk(KERN_ERR DRV_PFX "Error evaluating _SRS"); | 2303 | printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); |
2243 | result = -ENODEV; | 2304 | result = -ENODEV; |
2244 | goto end; | 2305 | goto end; |
2245 | } | 2306 | } |
@@ -2268,11 +2329,14 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) | |||
2268 | 2329 | ||
2269 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; | 2330 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; |
2270 | 2331 | ||
2271 | ev = inb_p(dev->cur_ioport->io.minimum); | 2332 | ev = inb_p(dev->cur_ioport->io1.minimum); |
2272 | data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset); | 2333 | if (dev->cur_ioport->io2.minimum) |
2334 | data_mask = inb_p(dev->cur_ioport->io2.minimum); | ||
2335 | else | ||
2336 | data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset); | ||
2273 | 2337 | ||
2274 | dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", | 2338 | dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", |
2275 | ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset); | 2339 | ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset); |
2276 | 2340 | ||
2277 | if (ev == 0x00 || ev == 0xff) | 2341 | if (ev == 0x00 || ev == 0xff) |
2278 | return IRQ_HANDLED; | 2342 | return IRQ_HANDLED; |
@@ -2323,8 +2387,11 @@ static int sony_pic_remove(struct acpi_device *device, int type) | |||
2323 | } | 2387 | } |
2324 | 2388 | ||
2325 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); | 2389 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); |
2326 | release_region(spic_dev.cur_ioport->io.minimum, | 2390 | release_region(spic_dev.cur_ioport->io1.minimum, |
2327 | spic_dev.cur_ioport->io.address_length); | 2391 | spic_dev.cur_ioport->io1.address_length); |
2392 | if (spic_dev.cur_ioport->io2.minimum) | ||
2393 | release_region(spic_dev.cur_ioport->io2.minimum, | ||
2394 | spic_dev.cur_ioport->io2.address_length); | ||
2328 | 2395 | ||
2329 | sonypi_compat_exit(); | 2396 | sonypi_compat_exit(); |
2330 | 2397 | ||
@@ -2397,14 +2464,36 @@ static int sony_pic_add(struct acpi_device *device) | |||
2397 | goto err_remove_input; | 2464 | goto err_remove_input; |
2398 | 2465 | ||
2399 | /* request io port */ | 2466 | /* request io port */ |
2400 | list_for_each_entry(io, &spic_dev.ioports, list) { | 2467 | list_for_each_entry_reverse(io, &spic_dev.ioports, list) { |
2401 | if (request_region(io->io.minimum, io->io.address_length, | 2468 | if (request_region(io->io1.minimum, io->io1.address_length, |
2402 | "Sony Programable I/O Device")) { | 2469 | "Sony Programable I/O Device")) { |
2403 | dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n", | 2470 | dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", |
2404 | io->io.minimum, io->io.maximum, | 2471 | io->io1.minimum, io->io1.maximum, |
2405 | io->io.address_length); | 2472 | io->io1.address_length); |
2406 | spic_dev.cur_ioport = io; | 2473 | /* Type 1 have 2 ioports */ |
2407 | break; | 2474 | if (io->io2.minimum) { |
2475 | if (request_region(io->io2.minimum, | ||
2476 | io->io2.address_length, | ||
2477 | "Sony Programable I/O Device")) { | ||
2478 | dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", | ||
2479 | io->io2.minimum, io->io2.maximum, | ||
2480 | io->io2.address_length); | ||
2481 | spic_dev.cur_ioport = io; | ||
2482 | break; | ||
2483 | } | ||
2484 | else { | ||
2485 | dprintk("Unable to get I/O port2: " | ||
2486 | "0x%.4x (0x%.4x) + 0x%.2x\n", | ||
2487 | io->io2.minimum, io->io2.maximum, | ||
2488 | io->io2.address_length); | ||
2489 | release_region(io->io1.minimum, | ||
2490 | io->io1.address_length); | ||
2491 | } | ||
2492 | } | ||
2493 | else { | ||
2494 | spic_dev.cur_ioport = io; | ||
2495 | break; | ||
2496 | } | ||
2408 | } | 2497 | } |
2409 | } | 2498 | } |
2410 | if (!spic_dev.cur_ioport) { | 2499 | if (!spic_dev.cur_ioport) { |
@@ -2414,7 +2503,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
2414 | } | 2503 | } |
2415 | 2504 | ||
2416 | /* request IRQ */ | 2505 | /* request IRQ */ |
2417 | list_for_each_entry(irq, &spic_dev.interrupts, list) { | 2506 | list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) { |
2418 | if (!request_irq(irq->irq.interrupts[0], sony_pic_irq, | 2507 | if (!request_irq(irq->irq.interrupts[0], sony_pic_irq, |
2419 | IRQF_SHARED, "sony-laptop", &spic_dev)) { | 2508 | IRQF_SHARED, "sony-laptop", &spic_dev)) { |
2420 | dprintk("IRQ: %d - triggering: %d - " | 2509 | dprintk("IRQ: %d - triggering: %d - " |
@@ -2462,8 +2551,11 @@ err_free_irq: | |||
2462 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); | 2551 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); |
2463 | 2552 | ||
2464 | err_release_region: | 2553 | err_release_region: |
2465 | release_region(spic_dev.cur_ioport->io.minimum, | 2554 | release_region(spic_dev.cur_ioport->io1.minimum, |
2466 | spic_dev.cur_ioport->io.address_length); | 2555 | spic_dev.cur_ioport->io1.address_length); |
2556 | if (spic_dev.cur_ioport->io2.minimum) | ||
2557 | release_region(spic_dev.cur_ioport->io2.minimum, | ||
2558 | spic_dev.cur_ioport->io2.address_length); | ||
2467 | 2559 | ||
2468 | err_remove_compat: | 2560 | err_remove_compat: |
2469 | sonypi_compat_exit(); | 2561 | sonypi_compat_exit(); |
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 81e068fa7ac5..e953276664a0 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -22,7 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define IBM_VERSION "0.16" | 24 | #define IBM_VERSION "0.16" |
25 | #define TPACPI_SYSFS_VERSION 0x010000 | 25 | #define TPACPI_SYSFS_VERSION 0x020000 |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Changelog: | 28 | * Changelog: |
@@ -117,6 +117,12 @@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); | |||
117 | 117 | ||
118 | #define __unused __attribute__ ((unused)) | 118 | #define __unused __attribute__ ((unused)) |
119 | 119 | ||
120 | static enum { | ||
121 | TPACPI_LIFE_INIT = 0, | ||
122 | TPACPI_LIFE_RUNNING, | ||
123 | TPACPI_LIFE_EXITING, | ||
124 | } tpacpi_lifecycle; | ||
125 | |||
120 | /**************************************************************************** | 126 | /**************************************************************************** |
121 | **************************************************************************** | 127 | **************************************************************************** |
122 | * | 128 | * |
@@ -342,6 +348,9 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) | |||
342 | { | 348 | { |
343 | struct ibm_struct *ibm = data; | 349 | struct ibm_struct *ibm = data; |
344 | 350 | ||
351 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | ||
352 | return; | ||
353 | |||
345 | if (!ibm || !ibm->acpi || !ibm->acpi->notify) | 354 | if (!ibm || !ibm->acpi || !ibm->acpi->notify) |
346 | return; | 355 | return; |
347 | 356 | ||
@@ -517,8 +526,10 @@ static char *next_cmd(char **cmds) | |||
517 | ****************************************************************************/ | 526 | ****************************************************************************/ |
518 | 527 | ||
519 | static struct platform_device *tpacpi_pdev; | 528 | static struct platform_device *tpacpi_pdev; |
529 | static struct platform_device *tpacpi_sensors_pdev; | ||
520 | static struct device *tpacpi_hwmon; | 530 | static struct device *tpacpi_hwmon; |
521 | static struct input_dev *tpacpi_inputdev; | 531 | static struct input_dev *tpacpi_inputdev; |
532 | static struct mutex tpacpi_inputdev_send_mutex; | ||
522 | 533 | ||
523 | 534 | ||
524 | static int tpacpi_resume_handler(struct platform_device *pdev) | 535 | static int tpacpi_resume_handler(struct platform_device *pdev) |
@@ -543,6 +554,12 @@ static struct platform_driver tpacpi_pdriver = { | |||
543 | .resume = tpacpi_resume_handler, | 554 | .resume = tpacpi_resume_handler, |
544 | }; | 555 | }; |
545 | 556 | ||
557 | static struct platform_driver tpacpi_hwmon_pdriver = { | ||
558 | .driver = { | ||
559 | .name = IBM_HWMON_DRVR_NAME, | ||
560 | .owner = THIS_MODULE, | ||
561 | }, | ||
562 | }; | ||
546 | 563 | ||
547 | /************************************************************************* | 564 | /************************************************************************* |
548 | * thinkpad-acpi driver attributes | 565 | * thinkpad-acpi driver attributes |
@@ -692,6 +709,8 @@ static int parse_strtoul(const char *buf, | |||
692 | { | 709 | { |
693 | char *endp; | 710 | char *endp; |
694 | 711 | ||
712 | while (*buf && isspace(*buf)) | ||
713 | buf++; | ||
695 | *value = simple_strtoul(buf, &endp, 0); | 714 | *value = simple_strtoul(buf, &endp, 0); |
696 | while (*endp && isspace(*endp)) | 715 | while (*endp && isspace(*endp)) |
697 | endp++; | 716 | endp++; |
@@ -989,6 +1008,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
989 | 1008 | ||
990 | int res, i; | 1009 | int res, i; |
991 | int status; | 1010 | int status; |
1011 | int hkeyv; | ||
992 | 1012 | ||
993 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); | 1013 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); |
994 | 1014 | ||
@@ -1014,18 +1034,35 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1014 | return res; | 1034 | return res; |
1015 | 1035 | ||
1016 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 1036 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
1017 | A30, R30, R31, T20-22, X20-21, X22-24 */ | 1037 | A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking |
1018 | tp_features.hotkey_mask = | 1038 | for HKEY interface version 0x100 */ |
1019 | acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); | 1039 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { |
1040 | if ((hkeyv >> 8) != 1) { | ||
1041 | printk(IBM_ERR "unknown version of the " | ||
1042 | "HKEY interface: 0x%x\n", hkeyv); | ||
1043 | printk(IBM_ERR "please report this to %s\n", | ||
1044 | IBM_MAIL); | ||
1045 | } else { | ||
1046 | /* | ||
1047 | * MHKV 0x100 in A31, R40, R40e, | ||
1048 | * T4x, X31, and later | ||
1049 | * */ | ||
1050 | tp_features.hotkey_mask = 1; | ||
1051 | } | ||
1052 | } | ||
1020 | 1053 | ||
1021 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", | 1054 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", |
1022 | str_supported(tp_features.hotkey_mask)); | 1055 | str_supported(tp_features.hotkey_mask)); |
1023 | 1056 | ||
1024 | if (tp_features.hotkey_mask) { | 1057 | if (tp_features.hotkey_mask) { |
1025 | /* MHKA available in A31, R40, R40e, T4x, X31, and later */ | ||
1026 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, | 1058 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, |
1027 | "MHKA", "qd")) | 1059 | "MHKA", "qd")) { |
1060 | printk(IBM_ERR | ||
1061 | "missing MHKA handler, " | ||
1062 | "please report this to %s\n", | ||
1063 | IBM_MAIL); | ||
1028 | hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ | 1064 | hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ |
1065 | } | ||
1029 | } | 1066 | } |
1030 | 1067 | ||
1031 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); | 1068 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); |
@@ -1131,6 +1168,8 @@ static void tpacpi_input_send_key(unsigned int scancode, | |||
1131 | unsigned int keycode) | 1168 | unsigned int keycode) |
1132 | { | 1169 | { |
1133 | if (keycode != KEY_RESERVED) { | 1170 | if (keycode != KEY_RESERVED) { |
1171 | mutex_lock(&tpacpi_inputdev_send_mutex); | ||
1172 | |||
1134 | input_report_key(tpacpi_inputdev, keycode, 1); | 1173 | input_report_key(tpacpi_inputdev, keycode, 1); |
1135 | if (keycode == KEY_UNKNOWN) | 1174 | if (keycode == KEY_UNKNOWN) |
1136 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | 1175 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, |
@@ -1142,6 +1181,8 @@ static void tpacpi_input_send_key(unsigned int scancode, | |||
1142 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | 1181 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, |
1143 | scancode); | 1182 | scancode); |
1144 | input_sync(tpacpi_inputdev); | 1183 | input_sync(tpacpi_inputdev); |
1184 | |||
1185 | mutex_unlock(&tpacpi_inputdev_send_mutex); | ||
1145 | } | 1186 | } |
1146 | } | 1187 | } |
1147 | 1188 | ||
@@ -1149,18 +1190,47 @@ static void tpacpi_input_send_radiosw(void) | |||
1149 | { | 1190 | { |
1150 | int wlsw; | 1191 | int wlsw; |
1151 | 1192 | ||
1152 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) | 1193 | mutex_lock(&tpacpi_inputdev_send_mutex); |
1194 | |||
1195 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { | ||
1153 | input_report_switch(tpacpi_inputdev, | 1196 | input_report_switch(tpacpi_inputdev, |
1154 | SW_RADIO, !!wlsw); | 1197 | SW_RADIO, !!wlsw); |
1198 | input_sync(tpacpi_inputdev); | ||
1199 | } | ||
1200 | |||
1201 | mutex_unlock(&tpacpi_inputdev_send_mutex); | ||
1155 | } | 1202 | } |
1156 | 1203 | ||
1157 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 1204 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
1158 | { | 1205 | { |
1159 | u32 hkey; | 1206 | u32 hkey; |
1160 | unsigned int keycode, scancode; | 1207 | unsigned int keycode, scancode; |
1161 | int send_acpi_ev = 0; | 1208 | int send_acpi_ev; |
1209 | int ignore_acpi_ev; | ||
1210 | |||
1211 | if (event != 0x80) { | ||
1212 | printk(IBM_ERR "unknown HKEY notification event %d\n", event); | ||
1213 | /* forward it to userspace, maybe it knows how to handle it */ | ||
1214 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | ||
1215 | ibm->acpi->device->dev.bus_id, | ||
1216 | event, 0); | ||
1217 | return; | ||
1218 | } | ||
1219 | |||
1220 | while (1) { | ||
1221 | if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | ||
1222 | printk(IBM_ERR "failed to retrieve HKEY event\n"); | ||
1223 | return; | ||
1224 | } | ||
1225 | |||
1226 | if (hkey == 0) { | ||
1227 | /* queue empty */ | ||
1228 | return; | ||
1229 | } | ||
1230 | |||
1231 | send_acpi_ev = 0; | ||
1232 | ignore_acpi_ev = 0; | ||
1162 | 1233 | ||
1163 | if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | ||
1164 | switch (hkey >> 12) { | 1234 | switch (hkey >> 12) { |
1165 | case 1: | 1235 | case 1: |
1166 | /* 0x1000-0x1FFF: key presses */ | 1236 | /* 0x1000-0x1FFF: key presses */ |
@@ -1182,9 +1252,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
1182 | * eat up known LID events */ | 1252 | * eat up known LID events */ |
1183 | if (hkey != 0x5001 && hkey != 0x5002) { | 1253 | if (hkey != 0x5001 && hkey != 0x5002) { |
1184 | printk(IBM_ERR | 1254 | printk(IBM_ERR |
1185 | "unknown LID-related hotkey event: 0x%04x\n", | 1255 | "unknown LID-related HKEY event: 0x%04x\n", |
1186 | hkey); | 1256 | hkey); |
1187 | send_acpi_ev = 1; | 1257 | send_acpi_ev = 1; |
1258 | } else { | ||
1259 | ignore_acpi_ev = 1; | ||
1188 | } | 1260 | } |
1189 | break; | 1261 | break; |
1190 | case 7: | 1262 | case 7: |
@@ -1202,21 +1274,18 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) | |||
1202 | printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); | 1274 | printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); |
1203 | send_acpi_ev = 1; | 1275 | send_acpi_ev = 1; |
1204 | } | 1276 | } |
1205 | } else { | ||
1206 | printk(IBM_ERR "unknown hotkey notification event %d\n", event); | ||
1207 | hkey = 0; | ||
1208 | send_acpi_ev = 1; | ||
1209 | } | ||
1210 | 1277 | ||
1211 | /* Legacy events */ | 1278 | /* Legacy events */ |
1212 | if (send_acpi_ev || hotkey_report_mode < 2) | 1279 | if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { |
1213 | acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); | 1280 | acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); |
1281 | } | ||
1214 | 1282 | ||
1215 | /* netlink events */ | 1283 | /* netlink events */ |
1216 | if (send_acpi_ev) { | 1284 | if (!ignore_acpi_ev && send_acpi_ev) { |
1217 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | 1285 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, |
1218 | ibm->acpi->device->dev.bus_id, | 1286 | ibm->acpi->device->dev.bus_id, |
1219 | event, hkey); | 1287 | event, hkey); |
1288 | } | ||
1220 | } | 1289 | } |
1221 | } | 1290 | } |
1222 | 1291 | ||
@@ -2812,7 +2881,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
2812 | 2881 | ||
2813 | switch(thermal_read_mode) { | 2882 | switch(thermal_read_mode) { |
2814 | case TPACPI_THERMAL_TPEC_16: | 2883 | case TPACPI_THERMAL_TPEC_16: |
2815 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 2884 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
2816 | &thermal_temp_input16_group); | 2885 | &thermal_temp_input16_group); |
2817 | if (res) | 2886 | if (res) |
2818 | return res; | 2887 | return res; |
@@ -2820,7 +2889,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
2820 | case TPACPI_THERMAL_TPEC_8: | 2889 | case TPACPI_THERMAL_TPEC_8: |
2821 | case TPACPI_THERMAL_ACPI_TMP07: | 2890 | case TPACPI_THERMAL_ACPI_TMP07: |
2822 | case TPACPI_THERMAL_ACPI_UPDT: | 2891 | case TPACPI_THERMAL_ACPI_UPDT: |
2823 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 2892 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
2824 | &thermal_temp_input8_group); | 2893 | &thermal_temp_input8_group); |
2825 | if (res) | 2894 | if (res) |
2826 | return res; | 2895 | return res; |
@@ -2837,13 +2906,13 @@ static void thermal_exit(void) | |||
2837 | { | 2906 | { |
2838 | switch(thermal_read_mode) { | 2907 | switch(thermal_read_mode) { |
2839 | case TPACPI_THERMAL_TPEC_16: | 2908 | case TPACPI_THERMAL_TPEC_16: |
2840 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 2909 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, |
2841 | &thermal_temp_input16_group); | 2910 | &thermal_temp_input16_group); |
2842 | break; | 2911 | break; |
2843 | case TPACPI_THERMAL_TPEC_8: | 2912 | case TPACPI_THERMAL_TPEC_8: |
2844 | case TPACPI_THERMAL_ACPI_TMP07: | 2913 | case TPACPI_THERMAL_ACPI_TMP07: |
2845 | case TPACPI_THERMAL_ACPI_UPDT: | 2914 | case TPACPI_THERMAL_ACPI_UPDT: |
2846 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 2915 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, |
2847 | &thermal_temp_input16_group); | 2916 | &thermal_temp_input16_group); |
2848 | break; | 2917 | break; |
2849 | case TPACPI_THERMAL_NONE: | 2918 | case TPACPI_THERMAL_NONE: |
@@ -3626,7 +3695,7 @@ static struct device_attribute dev_attr_fan_fan1_input = | |||
3626 | __ATTR(fan1_input, S_IRUGO, | 3695 | __ATTR(fan1_input, S_IRUGO, |
3627 | fan_fan1_input_show, NULL); | 3696 | fan_fan1_input_show, NULL); |
3628 | 3697 | ||
3629 | /* sysfs fan fan_watchdog (driver) ------------------------------------- */ | 3698 | /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ |
3630 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, | 3699 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, |
3631 | char *buf) | 3700 | char *buf) |
3632 | { | 3701 | { |
@@ -3768,10 +3837,10 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
3768 | 3837 | ||
3769 | if (fan_status_access_mode != TPACPI_FAN_NONE || | 3838 | if (fan_status_access_mode != TPACPI_FAN_NONE || |
3770 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { | 3839 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { |
3771 | rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 3840 | rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
3772 | &fan_attr_group); | 3841 | &fan_attr_group); |
3773 | if (!(rc < 0)) | 3842 | if (!(rc < 0)) |
3774 | rc = driver_create_file(&tpacpi_pdriver.driver, | 3843 | rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, |
3775 | &driver_attr_fan_watchdog); | 3844 | &driver_attr_fan_watchdog); |
3776 | if (rc < 0) | 3845 | if (rc < 0) |
3777 | return rc; | 3846 | return rc; |
@@ -3854,8 +3923,8 @@ static void fan_exit(void) | |||
3854 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); | 3923 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); |
3855 | 3924 | ||
3856 | /* FIXME: can we really do this unconditionally? */ | 3925 | /* FIXME: can we really do this unconditionally? */ |
3857 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); | 3926 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); |
3858 | driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); | 3927 | driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); |
3859 | 3928 | ||
3860 | cancel_delayed_work(&fan_watchdog_task); | 3929 | cancel_delayed_work(&fan_watchdog_task); |
3861 | flush_scheduled_work(); | 3930 | flush_scheduled_work(); |
@@ -3888,6 +3957,9 @@ static void fan_watchdog_fire(struct work_struct *ignored) | |||
3888 | { | 3957 | { |
3889 | int rc; | 3958 | int rc; |
3890 | 3959 | ||
3960 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | ||
3961 | return; | ||
3962 | |||
3891 | printk(IBM_NOTICE "fan watchdog: enabling fan\n"); | 3963 | printk(IBM_NOTICE "fan watchdog: enabling fan\n"); |
3892 | rc = fan_set_enable(); | 3964 | rc = fan_set_enable(); |
3893 | if (rc < 0) { | 3965 | if (rc < 0) { |
@@ -3908,7 +3980,8 @@ static void fan_watchdog_reset(void) | |||
3908 | if (fan_watchdog_active) | 3980 | if (fan_watchdog_active) |
3909 | cancel_delayed_work(&fan_watchdog_task); | 3981 | cancel_delayed_work(&fan_watchdog_task); |
3910 | 3982 | ||
3911 | if (fan_watchdog_maxinterval > 0) { | 3983 | if (fan_watchdog_maxinterval > 0 && |
3984 | tpacpi_lifecycle != TPACPI_LIFE_EXITING) { | ||
3912 | fan_watchdog_active = 1; | 3985 | fan_watchdog_active = 1; |
3913 | if (!schedule_delayed_work(&fan_watchdog_task, | 3986 | if (!schedule_delayed_work(&fan_watchdog_task, |
3914 | msecs_to_jiffies(fan_watchdog_maxinterval | 3987 | msecs_to_jiffies(fan_watchdog_maxinterval |
@@ -4302,6 +4375,19 @@ static struct ibm_struct fan_driver_data = { | |||
4302 | **************************************************************************** | 4375 | **************************************************************************** |
4303 | ****************************************************************************/ | 4376 | ****************************************************************************/ |
4304 | 4377 | ||
4378 | /* sysfs name ---------------------------------------------------------- */ | ||
4379 | static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, | ||
4380 | struct device_attribute *attr, | ||
4381 | char *buf) | ||
4382 | { | ||
4383 | return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME); | ||
4384 | } | ||
4385 | |||
4386 | static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = | ||
4387 | __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); | ||
4388 | |||
4389 | /* --------------------------------------------------------------------- */ | ||
4390 | |||
4305 | /* /proc support */ | 4391 | /* /proc support */ |
4306 | static struct proc_dir_entry *proc_dir; | 4392 | static struct proc_dir_entry *proc_dir; |
4307 | 4393 | ||
@@ -4674,6 +4760,8 @@ static int __init thinkpad_acpi_module_init(void) | |||
4674 | { | 4760 | { |
4675 | int ret, i; | 4761 | int ret, i; |
4676 | 4762 | ||
4763 | tpacpi_lifecycle = TPACPI_LIFE_INIT; | ||
4764 | |||
4677 | /* Parameter checking */ | 4765 | /* Parameter checking */ |
4678 | if (hotkey_report_mode > 2) | 4766 | if (hotkey_report_mode > 2) |
4679 | return -EINVAL; | 4767 | return -EINVAL; |
@@ -4702,19 +4790,31 @@ static int __init thinkpad_acpi_module_init(void) | |||
4702 | 4790 | ||
4703 | ret = platform_driver_register(&tpacpi_pdriver); | 4791 | ret = platform_driver_register(&tpacpi_pdriver); |
4704 | if (ret) { | 4792 | if (ret) { |
4705 | printk(IBM_ERR "unable to register platform driver\n"); | 4793 | printk(IBM_ERR "unable to register main platform driver\n"); |
4706 | thinkpad_acpi_module_exit(); | 4794 | thinkpad_acpi_module_exit(); |
4707 | return ret; | 4795 | return ret; |
4708 | } | 4796 | } |
4709 | tp_features.platform_drv_registered = 1; | 4797 | tp_features.platform_drv_registered = 1; |
4710 | 4798 | ||
4799 | ret = platform_driver_register(&tpacpi_hwmon_pdriver); | ||
4800 | if (ret) { | ||
4801 | printk(IBM_ERR "unable to register hwmon platform driver\n"); | ||
4802 | thinkpad_acpi_module_exit(); | ||
4803 | return ret; | ||
4804 | } | ||
4805 | tp_features.sensors_pdrv_registered = 1; | ||
4806 | |||
4711 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); | 4807 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); |
4808 | if (!ret) { | ||
4809 | tp_features.platform_drv_attrs_registered = 1; | ||
4810 | ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver); | ||
4811 | } | ||
4712 | if (ret) { | 4812 | if (ret) { |
4713 | printk(IBM_ERR "unable to create sysfs driver attributes\n"); | 4813 | printk(IBM_ERR "unable to create sysfs driver attributes\n"); |
4714 | thinkpad_acpi_module_exit(); | 4814 | thinkpad_acpi_module_exit(); |
4715 | return ret; | 4815 | return ret; |
4716 | } | 4816 | } |
4717 | tp_features.platform_drv_attrs_registered = 1; | 4817 | tp_features.sensors_pdrv_attrs_registered = 1; |
4718 | 4818 | ||
4719 | 4819 | ||
4720 | /* Device initialization */ | 4820 | /* Device initialization */ |
@@ -4727,7 +4827,26 @@ static int __init thinkpad_acpi_module_init(void) | |||
4727 | thinkpad_acpi_module_exit(); | 4827 | thinkpad_acpi_module_exit(); |
4728 | return ret; | 4828 | return ret; |
4729 | } | 4829 | } |
4730 | tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev); | 4830 | tpacpi_sensors_pdev = platform_device_register_simple( |
4831 | IBM_HWMON_DRVR_NAME, | ||
4832 | -1, NULL, 0); | ||
4833 | if (IS_ERR(tpacpi_sensors_pdev)) { | ||
4834 | ret = PTR_ERR(tpacpi_sensors_pdev); | ||
4835 | tpacpi_sensors_pdev = NULL; | ||
4836 | printk(IBM_ERR "unable to register hwmon platform device\n"); | ||
4837 | thinkpad_acpi_module_exit(); | ||
4838 | return ret; | ||
4839 | } | ||
4840 | ret = device_create_file(&tpacpi_sensors_pdev->dev, | ||
4841 | &dev_attr_thinkpad_acpi_pdev_name); | ||
4842 | if (ret) { | ||
4843 | printk(IBM_ERR | ||
4844 | "unable to create sysfs hwmon device attributes\n"); | ||
4845 | thinkpad_acpi_module_exit(); | ||
4846 | return ret; | ||
4847 | } | ||
4848 | tp_features.sensors_pdev_attrs_registered = 1; | ||
4849 | tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev); | ||
4731 | if (IS_ERR(tpacpi_hwmon)) { | 4850 | if (IS_ERR(tpacpi_hwmon)) { |
4732 | ret = PTR_ERR(tpacpi_hwmon); | 4851 | ret = PTR_ERR(tpacpi_hwmon); |
4733 | tpacpi_hwmon = NULL; | 4852 | tpacpi_hwmon = NULL; |
@@ -4735,6 +4854,7 @@ static int __init thinkpad_acpi_module_init(void) | |||
4735 | thinkpad_acpi_module_exit(); | 4854 | thinkpad_acpi_module_exit(); |
4736 | return ret; | 4855 | return ret; |
4737 | } | 4856 | } |
4857 | mutex_init(&tpacpi_inputdev_send_mutex); | ||
4738 | tpacpi_inputdev = input_allocate_device(); | 4858 | tpacpi_inputdev = input_allocate_device(); |
4739 | if (!tpacpi_inputdev) { | 4859 | if (!tpacpi_inputdev) { |
4740 | printk(IBM_ERR "unable to allocate input device\n"); | 4860 | printk(IBM_ERR "unable to allocate input device\n"); |
@@ -4769,6 +4889,7 @@ static int __init thinkpad_acpi_module_init(void) | |||
4769 | tp_features.input_device_registered = 1; | 4889 | tp_features.input_device_registered = 1; |
4770 | } | 4890 | } |
4771 | 4891 | ||
4892 | tpacpi_lifecycle = TPACPI_LIFE_RUNNING; | ||
4772 | return 0; | 4893 | return 0; |
4773 | } | 4894 | } |
4774 | 4895 | ||
@@ -4776,6 +4897,8 @@ static void thinkpad_acpi_module_exit(void) | |||
4776 | { | 4897 | { |
4777 | struct ibm_struct *ibm, *itmp; | 4898 | struct ibm_struct *ibm, *itmp; |
4778 | 4899 | ||
4900 | tpacpi_lifecycle = TPACPI_LIFE_EXITING; | ||
4901 | |||
4779 | list_for_each_entry_safe_reverse(ibm, itmp, | 4902 | list_for_each_entry_safe_reverse(ibm, itmp, |
4780 | &tpacpi_all_drivers, | 4903 | &tpacpi_all_drivers, |
4781 | all_drivers) { | 4904 | all_drivers) { |
@@ -4794,12 +4917,22 @@ static void thinkpad_acpi_module_exit(void) | |||
4794 | if (tpacpi_hwmon) | 4917 | if (tpacpi_hwmon) |
4795 | hwmon_device_unregister(tpacpi_hwmon); | 4918 | hwmon_device_unregister(tpacpi_hwmon); |
4796 | 4919 | ||
4920 | if (tp_features.sensors_pdev_attrs_registered) | ||
4921 | device_remove_file(&tpacpi_sensors_pdev->dev, | ||
4922 | &dev_attr_thinkpad_acpi_pdev_name); | ||
4923 | if (tpacpi_sensors_pdev) | ||
4924 | platform_device_unregister(tpacpi_sensors_pdev); | ||
4797 | if (tpacpi_pdev) | 4925 | if (tpacpi_pdev) |
4798 | platform_device_unregister(tpacpi_pdev); | 4926 | platform_device_unregister(tpacpi_pdev); |
4799 | 4927 | ||
4928 | if (tp_features.sensors_pdrv_attrs_registered) | ||
4929 | tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); | ||
4800 | if (tp_features.platform_drv_attrs_registered) | 4930 | if (tp_features.platform_drv_attrs_registered) |
4801 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); | 4931 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); |
4802 | 4932 | ||
4933 | if (tp_features.sensors_pdrv_registered) | ||
4934 | platform_driver_unregister(&tpacpi_hwmon_pdriver); | ||
4935 | |||
4803 | if (tp_features.platform_drv_registered) | 4936 | if (tp_features.platform_drv_registered) |
4804 | platform_driver_unregister(&tpacpi_pdriver); | 4937 | platform_driver_unregister(&tpacpi_pdriver); |
4805 | 4938 | ||
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index acd5835ec889..3abcc8120634 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h | |||
@@ -58,13 +58,14 @@ | |||
58 | 58 | ||
59 | #define IBM_NAME "thinkpad" | 59 | #define IBM_NAME "thinkpad" |
60 | #define IBM_DESC "ThinkPad ACPI Extras" | 60 | #define IBM_DESC "ThinkPad ACPI Extras" |
61 | #define IBM_FILE "thinkpad_acpi" | 61 | #define IBM_FILE IBM_NAME "_acpi" |
62 | #define IBM_URL "http://ibm-acpi.sf.net/" | 62 | #define IBM_URL "http://ibm-acpi.sf.net/" |
63 | #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" | 63 | #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" |
64 | 64 | ||
65 | #define IBM_PROC_DIR "ibm" | 65 | #define IBM_PROC_DIR "ibm" |
66 | #define IBM_ACPI_EVENT_PREFIX "ibm" | 66 | #define IBM_ACPI_EVENT_PREFIX "ibm" |
67 | #define IBM_DRVR_NAME IBM_FILE | 67 | #define IBM_DRVR_NAME IBM_FILE |
68 | #define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" | ||
68 | 69 | ||
69 | #define IBM_LOG IBM_FILE ": " | 70 | #define IBM_LOG IBM_FILE ": " |
70 | #define IBM_ERR KERN_ERR IBM_LOG | 71 | #define IBM_ERR KERN_ERR IBM_LOG |
@@ -171,6 +172,7 @@ static int parse_strtoul(const char *buf, unsigned long max, | |||
171 | 172 | ||
172 | /* Device model */ | 173 | /* Device model */ |
173 | static struct platform_device *tpacpi_pdev; | 174 | static struct platform_device *tpacpi_pdev; |
175 | static struct platform_device *tpacpi_sensors_pdev; | ||
174 | static struct device *tpacpi_hwmon; | 176 | static struct device *tpacpi_hwmon; |
175 | static struct platform_driver tpacpi_pdriver; | 177 | static struct platform_driver tpacpi_pdriver; |
176 | static struct input_dev *tpacpi_inputdev; | 178 | static struct input_dev *tpacpi_inputdev; |
@@ -233,22 +235,25 @@ struct ibm_init_struct { | |||
233 | 235 | ||
234 | static struct { | 236 | static struct { |
235 | #ifdef CONFIG_THINKPAD_ACPI_BAY | 237 | #ifdef CONFIG_THINKPAD_ACPI_BAY |
236 | u16 bay_status:1; | 238 | u32 bay_status:1; |
237 | u16 bay_eject:1; | 239 | u32 bay_eject:1; |
238 | u16 bay_status2:1; | 240 | u32 bay_status2:1; |
239 | u16 bay_eject2:1; | 241 | u32 bay_eject2:1; |
240 | #endif | 242 | #endif |
241 | u16 bluetooth:1; | 243 | u32 bluetooth:1; |
242 | u16 hotkey:1; | 244 | u32 hotkey:1; |
243 | u16 hotkey_mask:1; | 245 | u32 hotkey_mask:1; |
244 | u16 hotkey_wlsw:1; | 246 | u32 hotkey_wlsw:1; |
245 | u16 light:1; | 247 | u32 light:1; |
246 | u16 light_status:1; | 248 | u32 light_status:1; |
247 | u16 wan:1; | 249 | u32 wan:1; |
248 | u16 fan_ctrl_status_undef:1; | 250 | u32 fan_ctrl_status_undef:1; |
249 | u16 input_device_registered:1; | 251 | u32 input_device_registered:1; |
250 | u16 platform_drv_registered:1; | 252 | u32 platform_drv_registered:1; |
251 | u16 platform_drv_attrs_registered:1; | 253 | u32 platform_drv_attrs_registered:1; |
254 | u32 sensors_pdrv_registered:1; | ||
255 | u32 sensors_pdrv_attrs_registered:1; | ||
256 | u32 sensors_pdev_attrs_registered:1; | ||
252 | } tp_features; | 257 | } tp_features; |
253 | 258 | ||
254 | struct thinkpad_id_data { | 259 | struct thinkpad_id_data { |