aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-07-27 07:54:08 -0400
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-07-27 07:54:08 -0400
commiteda3d8f5604860aae1bb9996bb5efc4213778369 (patch)
tree9d3887d2665bcc5f5abf200758794545c7b2c69b /drivers/misc
parent87a9f704658a40940e740b1d73d861667e9164d3 (diff)
parent8be1a6d6c77ab4532e4476fdb8177030ef48b52c (diff)
Merge commit 'upstream/master'
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig32
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/atmel_pwm.c3
-rw-r--r--drivers/misc/hp-wmi.c494
-rw-r--r--drivers/misc/hpilo.c768
-rw-r--r--drivers/misc/hpilo.h189
-rw-r--r--drivers/misc/phantom.c7
-rw-r--r--drivers/misc/sgi-xp/xpc_main.c3
-rw-r--r--drivers/misc/thinkpad_acpi.c475
9 files changed, 1824 insertions, 149 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1921b8dbb242..321eb9134635 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -77,11 +77,13 @@ config IBM_ASM
77 for your IBM server. 77 for your IBM server.
78 78
79config PHANTOM 79config PHANTOM
80 tristate "Sensable PHANToM" 80 tristate "Sensable PHANToM (PCI)"
81 depends on PCI 81 depends on PCI
82 help 82 help
83 Say Y here if you want to build a driver for Sensable PHANToM device. 83 Say Y here if you want to build a driver for Sensable PHANToM device.
84 84
85 This driver is only for PCI PHANToMs.
86
85 If you choose to build module, its name will be phantom. If unsure, 87 If you choose to build module, its name will be phantom. If unsure,
86 say N here. 88 say N here.
87 89
@@ -212,6 +214,18 @@ config TC1100_WMI
212 This is a driver for the WMI extensions (wireless and bluetooth power 214 This is a driver for the WMI extensions (wireless and bluetooth power
213 control) of the HP Compaq TC1100 tablet. 215 control) of the HP Compaq TC1100 tablet.
214 216
217config HP_WMI
218 tristate "HP WMI extras"
219 depends on ACPI_WMI
220 depends on INPUT
221 depends on RFKILL
222 help
223 Say Y here if you want to support WMI-based hotkeys on HP laptops and
224 to read data from WMI such as docking or ambient light sensor state.
225
226 To compile this driver as a module, choose M here: the module will
227 be called hp-wmi.
228
215config MSI_LAPTOP 229config MSI_LAPTOP
216 tristate "MSI Laptop Extras" 230 tristate "MSI Laptop Extras"
217 depends on X86 231 depends on X86
@@ -279,6 +293,8 @@ config THINKPAD_ACPI
279 select INPUT 293 select INPUT
280 select NEW_LEDS 294 select NEW_LEDS
281 select LEDS_CLASS 295 select LEDS_CLASS
296 select NET
297 select RFKILL
282 ---help--- 298 ---help---
283 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds 299 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
284 support for Fn-Fx key combinations, Bluetooth control, video 300 support for Fn-Fx key combinations, Bluetooth control, video
@@ -420,4 +436,18 @@ config SGI_XP
420 this feature will allow for direct communication between SSIs 436 this feature will allow for direct communication between SSIs
421 based on a network adapter and DMA messaging. 437 based on a network adapter and DMA messaging.
422 438
439config HP_ILO
440 tristate "Channel interface driver for HP iLO/iLO2 processor"
441 depends on PCI
442 default n
443 help
444 The channel interface driver allows applications to communicate
445 with iLO/iLO2 management processors present on HP ProLiant
446 servers. Upon loading, the driver creates /dev/hpilo/dXccbN files,
447 which can be used to gather data from the management processor,
448 via read and write system calls.
449
450 To compile this driver as a module, choose M here: the
451 module will be called hpilo.
452
423endif # MISC_DEVICES 453endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index a6dac6a2e7e5..f5e273420c09 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o
13obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o 13obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
14obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o 14obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
15obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o 15obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
16obj-$(CONFIG_HP_WMI) += hp-wmi.o
16obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o 17obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
17obj-$(CONFIG_LKDTM) += lkdtm.o 18obj-$(CONFIG_LKDTM) += lkdtm.o
18obj-$(CONFIG_TIFM_CORE) += tifm_core.o 19obj-$(CONFIG_TIFM_CORE) += tifm_core.o
@@ -27,3 +28,4 @@ obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
27obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o 28obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
28obj-$(CONFIG_KGDB_TESTS) += kgdbts.o 29obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
29obj-$(CONFIG_SGI_XP) += sgi-xp/ 30obj-$(CONFIG_SGI_XP) += sgi-xp/
31obj-$(CONFIG_HP_ILO) += hpilo.o
diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c
index 5b5a14dab3d3..6aa5294dfec4 100644
--- a/drivers/misc/atmel_pwm.c
+++ b/drivers/misc/atmel_pwm.c
@@ -211,8 +211,7 @@ int pwm_clk_alloc(unsigned prescale, unsigned div)
211 if ((mr & 0xffff) == 0) { 211 if ((mr & 0xffff) == 0) {
212 mr |= val; 212 mr |= val;
213 ret = PWM_CPR_CLKA; 213 ret = PWM_CPR_CLKA;
214 } 214 } else if ((mr & (0xffff << 16)) == 0) {
215 if ((mr & (0xffff << 16)) == 0) {
216 mr |= val << 16; 215 mr |= val << 16;
217 ret = PWM_CPR_CLKB; 216 ret = PWM_CPR_CLKB;
218 } 217 }
diff --git a/drivers/misc/hp-wmi.c b/drivers/misc/hp-wmi.c
new file mode 100644
index 000000000000..1dbcbcb323a2
--- /dev/null
+++ b/drivers/misc/hp-wmi.c
@@ -0,0 +1,494 @@
1/*
2 * HP WMI hotkeys
3 *
4 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
5 *
6 * Portions based on wistron_btns.c:
7 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
8 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
9 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
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,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/types.h>
30#include <linux/input.h>
31#include <acpi/acpi_drivers.h>
32#include <linux/platform_device.h>
33#include <linux/acpi.h>
34#include <linux/rfkill.h>
35#include <linux/string.h>
36
37MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
38MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
39MODULE_LICENSE("GPL");
40
41MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
42MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
43
44#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
45#define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
46
47#define HPWMI_DISPLAY_QUERY 0x1
48#define HPWMI_HDDTEMP_QUERY 0x2
49#define HPWMI_ALS_QUERY 0x3
50#define HPWMI_DOCK_QUERY 0x4
51#define HPWMI_WIRELESS_QUERY 0x5
52
53static int __init hp_wmi_bios_setup(struct platform_device *device);
54static int __exit hp_wmi_bios_remove(struct platform_device *device);
55
56struct bios_args {
57 u32 signature;
58 u32 command;
59 u32 commandtype;
60 u32 datasize;
61 u32 data;
62};
63
64struct bios_return {
65 u32 sigpass;
66 u32 return_code;
67 u32 value;
68};
69
70struct key_entry {
71 char type; /* See KE_* below */
72 u8 code;
73 u16 keycode;
74};
75
76enum { KE_KEY, KE_SW, KE_END };
77
78static struct key_entry hp_wmi_keymap[] = {
79 {KE_SW, 0x01, SW_DOCK},
80 {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
81 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
82 {KE_KEY, 0x04, KEY_HELP},
83 {KE_END, 0}
84};
85
86static struct input_dev *hp_wmi_input_dev;
87static struct platform_device *hp_wmi_platform_dev;
88
89static struct rfkill *wifi_rfkill;
90static struct rfkill *bluetooth_rfkill;
91static struct rfkill *wwan_rfkill;
92
93static struct platform_driver hp_wmi_driver = {
94 .driver = {
95 .name = "hp-wmi",
96 .owner = THIS_MODULE,
97 },
98 .probe = hp_wmi_bios_setup,
99 .remove = hp_wmi_bios_remove,
100};
101
102static int hp_wmi_perform_query(int query, int write, int value)
103{
104 struct bios_return bios_return;
105 acpi_status status;
106 union acpi_object *obj;
107 struct bios_args args = {
108 .signature = 0x55434553,
109 .command = write ? 0x2 : 0x1,
110 .commandtype = query,
111 .datasize = write ? 0x4 : 0,
112 .data = value,
113 };
114 struct acpi_buffer input = { sizeof(struct bios_args), &args };
115 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
116
117 status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
118
119 obj = output.pointer;
120
121 if (!obj || obj->type != ACPI_TYPE_BUFFER)
122 return -EINVAL;
123
124 bios_return = *((struct bios_return *)obj->buffer.pointer);
125 if (bios_return.return_code > 0)
126 return bios_return.return_code * -1;
127 else
128 return bios_return.value;
129}
130
131static int hp_wmi_display_state(void)
132{
133 return hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, 0);
134}
135
136static int hp_wmi_hddtemp_state(void)
137{
138 return hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, 0);
139}
140
141static int hp_wmi_als_state(void)
142{
143 return hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, 0);
144}
145
146static int hp_wmi_dock_state(void)
147{
148 return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0);
149}
150
151static int hp_wmi_wifi_set(void *data, enum rfkill_state state)
152{
153 if (state)
154 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101);
155 else
156 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100);
157}
158
159static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state)
160{
161 if (state)
162 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202);
163 else
164 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200);
165}
166
167static int hp_wmi_wwan_set(void *data, enum rfkill_state state)
168{
169 if (state)
170 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404);
171 else
172 return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400);
173}
174
175static int hp_wmi_wifi_state(void)
176{
177 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
178
179 if (wireless & 0x100)
180 return 1;
181 else
182 return 0;
183}
184
185static int hp_wmi_bluetooth_state(void)
186{
187 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
188
189 if (wireless & 0x10000)
190 return 1;
191 else
192 return 0;
193}
194
195static int hp_wmi_wwan_state(void)
196{
197 int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
198
199 if (wireless & 0x1000000)
200 return 1;
201 else
202 return 0;
203}
204
205static ssize_t show_display(struct device *dev, struct device_attribute *attr,
206 char *buf)
207{
208 int value = hp_wmi_display_state();
209 if (value < 0)
210 return -EINVAL;
211 return sprintf(buf, "%d\n", value);
212}
213
214static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr,
215 char *buf)
216{
217 int value = hp_wmi_hddtemp_state();
218 if (value < 0)
219 return -EINVAL;
220 return sprintf(buf, "%d\n", value);
221}
222
223static ssize_t show_als(struct device *dev, struct device_attribute *attr,
224 char *buf)
225{
226 int value = hp_wmi_als_state();
227 if (value < 0)
228 return -EINVAL;
229 return sprintf(buf, "%d\n", value);
230}
231
232static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
233 char *buf)
234{
235 int value = hp_wmi_dock_state();
236 if (value < 0)
237 return -EINVAL;
238 return sprintf(buf, "%d\n", value);
239}
240
241static ssize_t set_als(struct device *dev, struct device_attribute *attr,
242 const char *buf, size_t count)
243{
244 u32 tmp = simple_strtoul(buf, NULL, 10);
245 hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, tmp);
246 return count;
247}
248
249static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
250static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
251static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
252static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
253
254static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
255{
256 struct key_entry *key;
257
258 for (key = hp_wmi_keymap; key->type != KE_END; key++)
259 if (code == key->code)
260 return key;
261
262 return NULL;
263}
264
265static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode)
266{
267 struct key_entry *key;
268
269 for (key = hp_wmi_keymap; key->type != KE_END; key++)
270 if (key->type == KE_KEY && keycode == key->keycode)
271 return key;
272
273 return NULL;
274}
275
276static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode)
277{
278 struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
279
280 if (key && key->type == KE_KEY) {
281 *keycode = key->keycode;
282 return 0;
283 }
284
285 return -EINVAL;
286}
287
288static int hp_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
289{
290 struct key_entry *key;
291 int old_keycode;
292
293 if (keycode < 0 || keycode > KEY_MAX)
294 return -EINVAL;
295
296 key = hp_wmi_get_entry_by_scancode(scancode);
297 if (key && key->type == KE_KEY) {
298 old_keycode = key->keycode;
299 key->keycode = keycode;
300 set_bit(keycode, dev->keybit);
301 if (!hp_wmi_get_entry_by_keycode(old_keycode))
302 clear_bit(old_keycode, dev->keybit);
303 return 0;
304 }
305
306 return -EINVAL;
307}
308
309void hp_wmi_notify(u32 value, void *context)
310{
311 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
312 static struct key_entry *key;
313 union acpi_object *obj;
314
315 wmi_get_event_data(value, &response);
316
317 obj = (union acpi_object *)response.pointer;
318
319 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) {
320 int eventcode = *((u8 *) obj->buffer.pointer);
321 key = hp_wmi_get_entry_by_scancode(eventcode);
322 if (key) {
323 switch (key->type) {
324 case KE_KEY:
325 input_report_key(hp_wmi_input_dev,
326 key->keycode, 1);
327 input_sync(hp_wmi_input_dev);
328 input_report_key(hp_wmi_input_dev,
329 key->keycode, 0);
330 input_sync(hp_wmi_input_dev);
331 break;
332 case KE_SW:
333 input_report_switch(hp_wmi_input_dev,
334 key->keycode,
335 hp_wmi_dock_state());
336 input_sync(hp_wmi_input_dev);
337 break;
338 }
339 } else if (eventcode == 0x5) {
340 if (wifi_rfkill)
341 wifi_rfkill->state = hp_wmi_wifi_state();
342 if (bluetooth_rfkill)
343 bluetooth_rfkill->state =
344 hp_wmi_bluetooth_state();
345 if (wwan_rfkill)
346 wwan_rfkill->state = hp_wmi_wwan_state();
347 } else
348 printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
349 eventcode);
350 } else
351 printk(KERN_INFO "HP WMI: Unknown response received\n");
352}
353
354static int __init hp_wmi_input_setup(void)
355{
356 struct key_entry *key;
357 int err;
358
359 hp_wmi_input_dev = input_allocate_device();
360
361 hp_wmi_input_dev->name = "HP WMI hotkeys";
362 hp_wmi_input_dev->phys = "wmi/input0";
363 hp_wmi_input_dev->id.bustype = BUS_HOST;
364 hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
365 hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
366
367 for (key = hp_wmi_keymap; key->type != KE_END; key++) {
368 switch (key->type) {
369 case KE_KEY:
370 set_bit(EV_KEY, hp_wmi_input_dev->evbit);
371 set_bit(key->keycode, hp_wmi_input_dev->keybit);
372 break;
373 case KE_SW:
374 set_bit(EV_SW, hp_wmi_input_dev->evbit);
375 set_bit(key->keycode, hp_wmi_input_dev->swbit);
376 break;
377 }
378 }
379
380 err = input_register_device(hp_wmi_input_dev);
381
382 if (err) {
383 input_free_device(hp_wmi_input_dev);
384 return err;
385 }
386
387 return 0;
388}
389
390static void cleanup_sysfs(struct platform_device *device)
391{
392 device_remove_file(&device->dev, &dev_attr_display);
393 device_remove_file(&device->dev, &dev_attr_hddtemp);
394 device_remove_file(&device->dev, &dev_attr_als);
395 device_remove_file(&device->dev, &dev_attr_dock);
396}
397
398static int __init hp_wmi_bios_setup(struct platform_device *device)
399{
400 int err;
401
402 err = device_create_file(&device->dev, &dev_attr_display);
403 if (err)
404 goto add_sysfs_error;
405 err = device_create_file(&device->dev, &dev_attr_hddtemp);
406 if (err)
407 goto add_sysfs_error;
408 err = device_create_file(&device->dev, &dev_attr_als);
409 if (err)
410 goto add_sysfs_error;
411 err = device_create_file(&device->dev, &dev_attr_dock);
412 if (err)
413 goto add_sysfs_error;
414
415 wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
416 wifi_rfkill->name = "hp-wifi";
417 wifi_rfkill->state = hp_wmi_wifi_state();
418 wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
419 wifi_rfkill->user_claim_unsupported = 1;
420
421 bluetooth_rfkill = rfkill_allocate(&device->dev,
422 RFKILL_TYPE_BLUETOOTH);
423 bluetooth_rfkill->name = "hp-bluetooth";
424 bluetooth_rfkill->state = hp_wmi_bluetooth_state();
425 bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
426 bluetooth_rfkill->user_claim_unsupported = 1;
427
428 wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
429 wwan_rfkill->name = "hp-wwan";
430 wwan_rfkill->state = hp_wmi_wwan_state();
431 wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
432 wwan_rfkill->user_claim_unsupported = 1;
433
434 rfkill_register(wifi_rfkill);
435 rfkill_register(bluetooth_rfkill);
436 rfkill_register(wwan_rfkill);
437
438 return 0;
439add_sysfs_error:
440 cleanup_sysfs(device);
441 return err;
442}
443
444static int __exit hp_wmi_bios_remove(struct platform_device *device)
445{
446 cleanup_sysfs(device);
447
448 rfkill_unregister(wifi_rfkill);
449 rfkill_unregister(bluetooth_rfkill);
450 rfkill_unregister(wwan_rfkill);
451
452 return 0;
453}
454
455static int __init hp_wmi_init(void)
456{
457 int err;
458
459 if (wmi_has_guid(HPWMI_EVENT_GUID)) {
460 err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
461 hp_wmi_notify, NULL);
462 if (!err)
463 hp_wmi_input_setup();
464 }
465
466 if (wmi_has_guid(HPWMI_BIOS_GUID)) {
467 err = platform_driver_register(&hp_wmi_driver);
468 if (err)
469 return 0;
470 hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1);
471 if (!hp_wmi_platform_dev) {
472 platform_driver_unregister(&hp_wmi_driver);
473 return 0;
474 }
475 platform_device_add(hp_wmi_platform_dev);
476 }
477
478 return 0;
479}
480
481static void __exit hp_wmi_exit(void)
482{
483 if (wmi_has_guid(HPWMI_EVENT_GUID)) {
484 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
485 input_unregister_device(hp_wmi_input_dev);
486 }
487 if (hp_wmi_platform_dev) {
488 platform_device_del(hp_wmi_platform_dev);
489 platform_driver_unregister(&hp_wmi_driver);
490 }
491}
492
493module_init(hp_wmi_init);
494module_exit(hp_wmi_exit);
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
new file mode 100644
index 000000000000..05e298289238
--- /dev/null
+++ b/drivers/misc/hpilo.c
@@ -0,0 +1,768 @@
1/*
2 * Driver for HP iLO/iLO2 management processor.
3 *
4 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
5 * David Altobelli <david.altobelli@hp.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/kernel.h>
12#include <linux/types.h>
13#include <linux/module.h>
14#include <linux/fs.h>
15#include <linux/pci.h>
16#include <linux/ioport.h>
17#include <linux/device.h>
18#include <linux/file.h>
19#include <linux/cdev.h>
20#include <linux/spinlock.h>
21#include <linux/delay.h>
22#include <linux/uaccess.h>
23#include <linux/io.h>
24#include "hpilo.h"
25
26static struct class *ilo_class;
27static unsigned int ilo_major;
28static char ilo_hwdev[MAX_ILO_DEV];
29
30static inline int get_entry_id(int entry)
31{
32 return (entry & ENTRY_MASK_DESCRIPTOR) >> ENTRY_BITPOS_DESCRIPTOR;
33}
34
35static inline int get_entry_len(int entry)
36{
37 return ((entry & ENTRY_MASK_QWORDS) >> ENTRY_BITPOS_QWORDS) << 3;
38}
39
40static inline int mk_entry(int id, int len)
41{
42 int qlen = len & 7 ? (len >> 3) + 1 : len >> 3;
43 return id << ENTRY_BITPOS_DESCRIPTOR | qlen << ENTRY_BITPOS_QWORDS;
44}
45
46static inline int desc_mem_sz(int nr_entry)
47{
48 return nr_entry << L2_QENTRY_SZ;
49}
50
51/*
52 * FIFO queues, shared with hardware.
53 *
54 * If a queue has empty slots, an entry is added to the queue tail,
55 * and that entry is marked as occupied.
56 * Entries can be dequeued from the head of the list, when the device
57 * has marked the entry as consumed.
58 *
59 * Returns true on successful queue/dequeue, false on failure.
60 */
61static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry)
62{
63 struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
64 int ret = 0;
65
66 spin_lock(&hw->fifo_lock);
67 if (!(fifo_q->fifobar[(fifo_q->tail + 1) & fifo_q->imask]
68 & ENTRY_MASK_O)) {
69 fifo_q->fifobar[fifo_q->tail & fifo_q->imask] |=
70 (entry & ENTRY_MASK_NOSTATE) | fifo_q->merge;
71 fifo_q->tail += 1;
72 ret = 1;
73 }
74 spin_unlock(&hw->fifo_lock);
75
76 return ret;
77}
78
79static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry)
80{
81 struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
82 int ret = 0;
83 u64 c;
84
85 spin_lock(&hw->fifo_lock);
86 c = fifo_q->fifobar[fifo_q->head & fifo_q->imask];
87 if (c & ENTRY_MASK_C) {
88 if (entry)
89 *entry = c & ENTRY_MASK_NOSTATE;
90
91 fifo_q->fifobar[fifo_q->head & fifo_q->imask] =
92 (c | ENTRY_MASK) + 1;
93 fifo_q->head += 1;
94 ret = 1;
95 }
96 spin_unlock(&hw->fifo_lock);
97
98 return ret;
99}
100
101static int ilo_pkt_enqueue(struct ilo_hwinfo *hw, struct ccb *ccb,
102 int dir, int id, int len)
103{
104 char *fifobar;
105 int entry;
106
107 if (dir == SENDQ)
108 fifobar = ccb->ccb_u1.send_fifobar;
109 else
110 fifobar = ccb->ccb_u3.recv_fifobar;
111
112 entry = mk_entry(id, len);
113 return fifo_enqueue(hw, fifobar, entry);
114}
115
116static int ilo_pkt_dequeue(struct ilo_hwinfo *hw, struct ccb *ccb,
117 int dir, int *id, int *len, void **pkt)
118{
119 char *fifobar, *desc;
120 int entry = 0, pkt_id = 0;
121 int ret;
122
123 if (dir == SENDQ) {
124 fifobar = ccb->ccb_u1.send_fifobar;
125 desc = ccb->ccb_u2.send_desc;
126 } else {
127 fifobar = ccb->ccb_u3.recv_fifobar;
128 desc = ccb->ccb_u4.recv_desc;
129 }
130
131 ret = fifo_dequeue(hw, fifobar, &entry);
132 if (ret) {
133 pkt_id = get_entry_id(entry);
134 if (id)
135 *id = pkt_id;
136 if (len)
137 *len = get_entry_len(entry);
138 if (pkt)
139 *pkt = (void *)(desc + desc_mem_sz(pkt_id));
140 }
141
142 return ret;
143}
144
145static inline void doorbell_set(struct ccb *ccb)
146{
147 iowrite8(1, ccb->ccb_u5.db_base);
148}
149
150static inline void doorbell_clr(struct ccb *ccb)
151{
152 iowrite8(2, ccb->ccb_u5.db_base);
153}
154static inline int ctrl_set(int l2sz, int idxmask, int desclim)
155{
156 int active = 0, go = 1;
157 return l2sz << CTRL_BITPOS_L2SZ |
158 idxmask << CTRL_BITPOS_FIFOINDEXMASK |
159 desclim << CTRL_BITPOS_DESCLIMIT |
160 active << CTRL_BITPOS_A |
161 go << CTRL_BITPOS_G;
162}
163static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz)
164{
165 /* for simplicity, use the same parameters for send and recv ctrls */
166 ccb->send_ctrl = ctrl_set(l2desc_sz, nr_desc-1, nr_desc-1);
167 ccb->recv_ctrl = ctrl_set(l2desc_sz, nr_desc-1, nr_desc-1);
168}
169
170static inline int fifo_sz(int nr_entry)
171{
172 /* size of a fifo is determined by the number of entries it contains */
173 return (nr_entry * sizeof(u64)) + FIFOHANDLESIZE;
174}
175
176static void fifo_setup(void *base_addr, int nr_entry)
177{
178 struct fifo *fifo_q = base_addr;
179 int i;
180
181 /* set up an empty fifo */
182 fifo_q->head = 0;
183 fifo_q->tail = 0;
184 fifo_q->reset = 0;
185 fifo_q->nrents = nr_entry;
186 fifo_q->imask = nr_entry - 1;
187 fifo_q->merge = ENTRY_MASK_O;
188
189 for (i = 0; i < nr_entry; i++)
190 fifo_q->fifobar[i] = 0;
191}
192
193static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
194{
195 struct ccb *driver_ccb;
196 struct ccb __iomem *device_ccb;
197 int retries;
198
199 driver_ccb = &data->driver_ccb;
200 device_ccb = data->mapped_ccb;
201
202 /* complicated dance to tell the hw we are stopping */
203 doorbell_clr(driver_ccb);
204 iowrite32(ioread32(&device_ccb->send_ctrl) & ~(1 << CTRL_BITPOS_G),
205 &device_ccb->send_ctrl);
206 iowrite32(ioread32(&device_ccb->recv_ctrl) & ~(1 << CTRL_BITPOS_G),
207 &device_ccb->recv_ctrl);
208
209 /* give iLO some time to process stop request */
210 for (retries = 1000; retries > 0; retries--) {
211 doorbell_set(driver_ccb);
212 udelay(1);
213 if (!(ioread32(&device_ccb->send_ctrl) & (1 << CTRL_BITPOS_A))
214 &&
215 !(ioread32(&device_ccb->recv_ctrl) & (1 << CTRL_BITPOS_A)))
216 break;
217 }
218 if (retries == 0)
219 dev_err(&pdev->dev, "Closing, but controller still active\n");
220
221 /* clear the hw ccb */
222 memset_io(device_ccb, 0, sizeof(struct ccb));
223
224 /* free resources used to back send/recv queues */
225 pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa);
226}
227
228static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot)
229{
230 char *dma_va, *dma_pa;
231 int pkt_id, pkt_sz, i, error;
232 struct ccb *driver_ccb, *ilo_ccb;
233 struct pci_dev *pdev;
234
235 driver_ccb = &data->driver_ccb;
236 ilo_ccb = &data->ilo_ccb;
237 pdev = hw->ilo_dev;
238
239 data->dma_size = 2 * fifo_sz(NR_QENTRY) +
240 2 * desc_mem_sz(NR_QENTRY) +
241 ILO_START_ALIGN + ILO_CACHE_SZ;
242
243 error = -ENOMEM;
244 data->dma_va = pci_alloc_consistent(pdev, data->dma_size,
245 &data->dma_pa);
246 if (!data->dma_va)
247 goto out;
248
249 dma_va = (char *)data->dma_va;
250 dma_pa = (char *)data->dma_pa;
251
252 memset(dma_va, 0, data->dma_size);
253
254 dma_va = (char *)roundup((unsigned long)dma_va, ILO_START_ALIGN);
255 dma_pa = (char *)roundup((unsigned long)dma_pa, ILO_START_ALIGN);
256
257 /*
258 * Create two ccb's, one with virt addrs, one with phys addrs.
259 * Copy the phys addr ccb to device shared mem.
260 */
261 ctrl_setup(driver_ccb, NR_QENTRY, L2_QENTRY_SZ);
262 ctrl_setup(ilo_ccb, NR_QENTRY, L2_QENTRY_SZ);
263
264 fifo_setup(dma_va, NR_QENTRY);
265 driver_ccb->ccb_u1.send_fifobar = dma_va + FIFOHANDLESIZE;
266 ilo_ccb->ccb_u1.send_fifobar = dma_pa + FIFOHANDLESIZE;
267 dma_va += fifo_sz(NR_QENTRY);
268 dma_pa += fifo_sz(NR_QENTRY);
269
270 dma_va = (char *)roundup((unsigned long)dma_va, ILO_CACHE_SZ);
271 dma_pa = (char *)roundup((unsigned long)dma_pa, ILO_CACHE_SZ);
272
273 fifo_setup(dma_va, NR_QENTRY);
274 driver_ccb->ccb_u3.recv_fifobar = dma_va + FIFOHANDLESIZE;
275 ilo_ccb->ccb_u3.recv_fifobar = dma_pa + FIFOHANDLESIZE;
276 dma_va += fifo_sz(NR_QENTRY);
277 dma_pa += fifo_sz(NR_QENTRY);
278
279 driver_ccb->ccb_u2.send_desc = dma_va;
280 ilo_ccb->ccb_u2.send_desc = dma_pa;
281 dma_pa += desc_mem_sz(NR_QENTRY);
282 dma_va += desc_mem_sz(NR_QENTRY);
283
284 driver_ccb->ccb_u4.recv_desc = dma_va;
285 ilo_ccb->ccb_u4.recv_desc = dma_pa;
286
287 driver_ccb->channel = slot;
288 ilo_ccb->channel = slot;
289
290 driver_ccb->ccb_u5.db_base = hw->db_vaddr + (slot << L2_DB_SIZE);
291 ilo_ccb->ccb_u5.db_base = NULL; /* hw ccb's doorbell is not used */
292
293 /* copy the ccb with physical addrs to device memory */
294 data->mapped_ccb = (struct ccb __iomem *)
295 (hw->ram_vaddr + (slot * ILOHW_CCB_SZ));
296 memcpy_toio(data->mapped_ccb, ilo_ccb, sizeof(struct ccb));
297
298 /* put packets on the send and receive queues */
299 pkt_sz = 0;
300 for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++) {
301 ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, pkt_sz);
302 doorbell_set(driver_ccb);
303 }
304
305 pkt_sz = desc_mem_sz(1);
306 for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++)
307 ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz);
308
309 doorbell_clr(driver_ccb);
310
311 /* make sure iLO is really handling requests */
312 for (i = 1000; i > 0; i--) {
313 if (ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, NULL, NULL))
314 break;
315 udelay(1);
316 }
317
318 if (i) {
319 ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0);
320 doorbell_set(driver_ccb);
321 } else {
322 dev_err(&pdev->dev, "Open could not dequeue a packet\n");
323 error = -EBUSY;
324 goto free;
325 }
326
327 return 0;
328free:
329 pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa);
330out:
331 return error;
332}
333
334static inline int is_channel_reset(struct ccb *ccb)
335{
336 /* check for this particular channel needing a reset */
337 return FIFOBARTOHANDLE(ccb->ccb_u1.send_fifobar)->reset;
338}
339
340static inline void set_channel_reset(struct ccb *ccb)
341{
342 /* set a flag indicating this channel needs a reset */
343 FIFOBARTOHANDLE(ccb->ccb_u1.send_fifobar)->reset = 1;
344}
345
346static inline int is_device_reset(struct ilo_hwinfo *hw)
347{
348 /* check for global reset condition */
349 return ioread32(&hw->mmio_vaddr[DB_OUT]) & (1 << DB_RESET);
350}
351
352static inline void clear_device(struct ilo_hwinfo *hw)
353{
354 /* clear the device (reset bits, pending channel entries) */
355 iowrite32(-1, &hw->mmio_vaddr[DB_OUT]);
356}
357
358static void ilo_locked_reset(struct ilo_hwinfo *hw)
359{
360 int slot;
361
362 /*
363 * Mapped memory is zeroed on ilo reset, so set a per ccb flag
364 * to indicate that this ccb needs to be closed and reopened.
365 */
366 for (slot = 0; slot < MAX_CCB; slot++) {
367 if (!hw->ccb_alloc[slot])
368 continue;
369 set_channel_reset(&hw->ccb_alloc[slot]->driver_ccb);
370 }
371
372 clear_device(hw);
373}
374
375static void ilo_reset(struct ilo_hwinfo *hw)
376{
377 spin_lock(&hw->alloc_lock);
378
379 /* reset might have been handled after lock was taken */
380 if (is_device_reset(hw))
381 ilo_locked_reset(hw);
382
383 spin_unlock(&hw->alloc_lock);
384}
385
386static ssize_t ilo_read(struct file *fp, char __user *buf,
387 size_t len, loff_t *off)
388{
389 int err, found, cnt, pkt_id, pkt_len;
390 struct ccb_data *data;
391 struct ccb *driver_ccb;
392 struct ilo_hwinfo *hw;
393 void *pkt;
394
395 data = fp->private_data;
396 driver_ccb = &data->driver_ccb;
397 hw = data->ilo_hw;
398
399 if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
400 /*
401 * If the device has been reset, applications
402 * need to close and reopen all ccbs.
403 */
404 ilo_reset(hw);
405 return -ENODEV;
406 }
407
408 /*
409 * This function is to be called when data is expected
410 * in the channel, and will return an error if no packet is found
411 * during the loop below. The sleep/retry logic is to allow
412 * applications to call read() immediately post write(),
413 * and give iLO some time to process the sent packet.
414 */
415 cnt = 20;
416 do {
417 /* look for a received packet */
418 found = ilo_pkt_dequeue(hw, driver_ccb, RECVQ, &pkt_id,
419 &pkt_len, &pkt);
420 if (found)
421 break;
422 cnt--;
423 msleep(100);
424 } while (!found && cnt);
425
426 if (!found)
427 return -EAGAIN;
428
429 /* only copy the length of the received packet */
430 if (pkt_len < len)
431 len = pkt_len;
432
433 err = copy_to_user(buf, pkt, len);
434
435 /* return the received packet to the queue */
436 ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, desc_mem_sz(1));
437
438 return err ? -EFAULT : len;
439}
440
441static ssize_t ilo_write(struct file *fp, const char __user *buf,
442 size_t len, loff_t *off)
443{
444 int err, pkt_id, pkt_len;
445 struct ccb_data *data;
446 struct ccb *driver_ccb;
447 struct ilo_hwinfo *hw;
448 void *pkt;
449
450 data = fp->private_data;
451 driver_ccb = &data->driver_ccb;
452 hw = data->ilo_hw;
453
454 if (is_device_reset(hw) || is_channel_reset(driver_ccb)) {
455 /*
456 * If the device has been reset, applications
457 * need to close and reopen all ccbs.
458 */
459 ilo_reset(hw);
460 return -ENODEV;
461 }
462
463 /* get a packet to send the user command */
464 if (!ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, &pkt_len, &pkt))
465 return -EBUSY;
466
467 /* limit the length to the length of the packet */
468 if (pkt_len < len)
469 len = pkt_len;
470
471 /* on failure, set the len to 0 to return empty packet to the device */
472 err = copy_from_user(pkt, buf, len);
473 if (err)
474 len = 0;
475
476 /* send the packet */
477 ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, len);
478 doorbell_set(driver_ccb);
479
480 return err ? -EFAULT : len;
481}
482
483static int ilo_close(struct inode *ip, struct file *fp)
484{
485 int slot;
486 struct ccb_data *data;
487 struct ilo_hwinfo *hw;
488
489 slot = iminor(ip) % MAX_CCB;
490 hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
491
492 spin_lock(&hw->alloc_lock);
493
494 if (is_device_reset(hw))
495 ilo_locked_reset(hw);
496
497 if (hw->ccb_alloc[slot]->ccb_cnt == 1) {
498
499 data = fp->private_data;
500
501 ilo_ccb_close(hw->ilo_dev, data);
502
503 kfree(data);
504 hw->ccb_alloc[slot] = NULL;
505 } else
506 hw->ccb_alloc[slot]->ccb_cnt--;
507
508 spin_unlock(&hw->alloc_lock);
509
510 return 0;
511}
512
513static int ilo_open(struct inode *ip, struct file *fp)
514{
515 int slot, error;
516 struct ccb_data *data;
517 struct ilo_hwinfo *hw;
518
519 slot = iminor(ip) % MAX_CCB;
520 hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
521
522 /* new ccb allocation */
523 data = kzalloc(sizeof(*data), GFP_KERNEL);
524 if (!data)
525 return -ENOMEM;
526
527 spin_lock(&hw->alloc_lock);
528
529 if (is_device_reset(hw))
530 ilo_locked_reset(hw);
531
532 /* each fd private_data holds sw/hw view of ccb */
533 if (hw->ccb_alloc[slot] == NULL) {
534 /* create a channel control block for this minor */
535 error = ilo_ccb_open(hw, data, slot);
536 if (!error) {
537 hw->ccb_alloc[slot] = data;
538 hw->ccb_alloc[slot]->ccb_cnt = 1;
539 hw->ccb_alloc[slot]->ccb_excl = fp->f_flags & O_EXCL;
540 hw->ccb_alloc[slot]->ilo_hw = hw;
541 } else
542 kfree(data);
543 } else {
544 kfree(data);
545 if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) {
546 /*
547 * The channel exists, and either this open
548 * or a previous open of this channel wants
549 * exclusive access.
550 */
551 error = -EBUSY;
552 } else {
553 hw->ccb_alloc[slot]->ccb_cnt++;
554 error = 0;
555 }
556 }
557 spin_unlock(&hw->alloc_lock);
558
559 if (!error)
560 fp->private_data = hw->ccb_alloc[slot];
561
562 return error;
563}
564
565static const struct file_operations ilo_fops = {
566 .owner = THIS_MODULE,
567 .read = ilo_read,
568 .write = ilo_write,
569 .open = ilo_open,
570 .release = ilo_close,
571};
572
573static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
574{
575 pci_iounmap(pdev, hw->db_vaddr);
576 pci_iounmap(pdev, hw->ram_vaddr);
577 pci_iounmap(pdev, hw->mmio_vaddr);
578}
579
580static int __devinit ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
581{
582 int error = -ENOMEM;
583
584 /* map the memory mapped i/o registers */
585 hw->mmio_vaddr = pci_iomap(pdev, 1, 0);
586 if (hw->mmio_vaddr == NULL) {
587 dev_err(&pdev->dev, "Error mapping mmio\n");
588 goto out;
589 }
590
591 /* map the adapter shared memory region */
592 hw->ram_vaddr = pci_iomap(pdev, 2, MAX_CCB * ILOHW_CCB_SZ);
593 if (hw->ram_vaddr == NULL) {
594 dev_err(&pdev->dev, "Error mapping shared mem\n");
595 goto mmio_free;
596 }
597
598 /* map the doorbell aperture */
599 hw->db_vaddr = pci_iomap(pdev, 3, MAX_CCB * ONE_DB_SIZE);
600 if (hw->db_vaddr == NULL) {
601 dev_err(&pdev->dev, "Error mapping doorbell\n");
602 goto ram_free;
603 }
604
605 return 0;
606ram_free:
607 pci_iounmap(pdev, hw->ram_vaddr);
608mmio_free:
609 pci_iounmap(pdev, hw->mmio_vaddr);
610out:
611 return error;
612}
613
614static void ilo_remove(struct pci_dev *pdev)
615{
616 int i, minor;
617 struct ilo_hwinfo *ilo_hw = pci_get_drvdata(pdev);
618
619 clear_device(ilo_hw);
620
621 minor = MINOR(ilo_hw->cdev.dev);
622 for (i = minor; i < minor + MAX_CCB; i++)
623 device_destroy(ilo_class, MKDEV(ilo_major, i));
624
625 cdev_del(&ilo_hw->cdev);
626 ilo_unmap_device(pdev, ilo_hw);
627 pci_release_regions(pdev);
628 pci_disable_device(pdev);
629 kfree(ilo_hw);
630 ilo_hwdev[(minor / MAX_CCB)] = 0;
631}
632
633static int __devinit ilo_probe(struct pci_dev *pdev,
634 const struct pci_device_id *ent)
635{
636 int devnum, minor, start, error;
637 struct ilo_hwinfo *ilo_hw;
638
639 /* find a free range for device files */
640 for (devnum = 0; devnum < MAX_ILO_DEV; devnum++) {
641 if (ilo_hwdev[devnum] == 0) {
642 ilo_hwdev[devnum] = 1;
643 break;
644 }
645 }
646
647 if (devnum == MAX_ILO_DEV) {
648 dev_err(&pdev->dev, "Error finding free device\n");
649 return -ENODEV;
650 }
651
652 /* track global allocations for this device */
653 error = -ENOMEM;
654 ilo_hw = kzalloc(sizeof(*ilo_hw), GFP_KERNEL);
655 if (!ilo_hw)
656 goto out;
657
658 ilo_hw->ilo_dev = pdev;
659 spin_lock_init(&ilo_hw->alloc_lock);
660 spin_lock_init(&ilo_hw->fifo_lock);
661
662 error = pci_enable_device(pdev);
663 if (error)
664 goto free;
665
666 pci_set_master(pdev);
667
668 error = pci_request_regions(pdev, ILO_NAME);
669 if (error)
670 goto disable;
671
672 error = ilo_map_device(pdev, ilo_hw);
673 if (error)
674 goto free_regions;
675
676 pci_set_drvdata(pdev, ilo_hw);
677 clear_device(ilo_hw);
678
679 cdev_init(&ilo_hw->cdev, &ilo_fops);
680 ilo_hw->cdev.owner = THIS_MODULE;
681 start = devnum * MAX_CCB;
682 error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), MAX_CCB);
683 if (error) {
684 dev_err(&pdev->dev, "Could not add cdev\n");
685 goto unmap;
686 }
687
688 for (minor = 0 ; minor < MAX_CCB; minor++) {
689 struct device *dev;
690 dev = device_create(ilo_class, &pdev->dev,
691 MKDEV(ilo_major, minor), NULL,
692 "hpilo!d%dccb%d", devnum, minor);
693 if (IS_ERR(dev))
694 dev_err(&pdev->dev, "Could not create files\n");
695 }
696
697 return 0;
698unmap:
699 ilo_unmap_device(pdev, ilo_hw);
700free_regions:
701 pci_release_regions(pdev);
702disable:
703 pci_disable_device(pdev);
704free:
705 kfree(ilo_hw);
706out:
707 ilo_hwdev[devnum] = 0;
708 return error;
709}
710
711static struct pci_device_id ilo_devices[] = {
712 { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB204) },
713 { }
714};
715MODULE_DEVICE_TABLE(pci, ilo_devices);
716
717static struct pci_driver ilo_driver = {
718 .name = ILO_NAME,
719 .id_table = ilo_devices,
720 .probe = ilo_probe,
721 .remove = __devexit_p(ilo_remove),
722};
723
724static int __init ilo_init(void)
725{
726 int error;
727 dev_t dev;
728
729 ilo_class = class_create(THIS_MODULE, "iLO");
730 if (IS_ERR(ilo_class)) {
731 error = PTR_ERR(ilo_class);
732 goto out;
733 }
734
735 error = alloc_chrdev_region(&dev, 0, MAX_OPEN, ILO_NAME);
736 if (error)
737 goto class_destroy;
738
739 ilo_major = MAJOR(dev);
740
741 error = pci_register_driver(&ilo_driver);
742 if (error)
743 goto chr_remove;
744
745 return 0;
746chr_remove:
747 unregister_chrdev_region(dev, MAX_OPEN);
748class_destroy:
749 class_destroy(ilo_class);
750out:
751 return error;
752}
753
754static void __exit ilo_exit(void)
755{
756 pci_unregister_driver(&ilo_driver);
757 unregister_chrdev_region(MKDEV(ilo_major, 0), MAX_OPEN);
758 class_destroy(ilo_class);
759}
760
761MODULE_VERSION("0.05");
762MODULE_ALIAS(ILO_NAME);
763MODULE_DESCRIPTION(ILO_NAME);
764MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
765MODULE_LICENSE("GPL v2");
766
767module_init(ilo_init);
768module_exit(ilo_exit);
diff --git a/drivers/misc/hpilo.h b/drivers/misc/hpilo.h
new file mode 100644
index 000000000000..a281207696c1
--- /dev/null
+++ b/drivers/misc/hpilo.h
@@ -0,0 +1,189 @@
1/*
2 * linux/drivers/char/hpilo.h
3 *
4 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
5 * David Altobelli <david.altobelli@hp.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef __HPILO_H
12#define __HPILO_H
13
14#define ILO_NAME "hpilo"
15
16/* max number of open channel control blocks per device, hw limited to 32 */
17#define MAX_CCB 8
18/* max number of supported devices */
19#define MAX_ILO_DEV 1
20/* max number of files */
21#define MAX_OPEN (MAX_CCB * MAX_ILO_DEV)
22
23/*
24 * Per device, used to track global memory allocations.
25 */
26struct ilo_hwinfo {
27 /* mmio registers on device */
28 char __iomem *mmio_vaddr;
29
30 /* doorbell registers on device */
31 char __iomem *db_vaddr;
32
33 /* shared memory on device used for channel control blocks */
34 char __iomem *ram_vaddr;
35
36 /* files corresponding to this device */
37 struct ccb_data *ccb_alloc[MAX_CCB];
38
39 struct pci_dev *ilo_dev;
40
41 spinlock_t alloc_lock;
42 spinlock_t fifo_lock;
43
44 struct cdev cdev;
45};
46
47/* offset from mmio_vaddr */
48#define DB_OUT 0xD4
49/* DB_OUT reset bit */
50#define DB_RESET 26
51
52/*
53 * Channel control block. Used to manage hardware queues.
54 * The format must match hw's version. The hw ccb is 128 bytes,
55 * but the context area shouldn't be touched by the driver.
56 */
57#define ILOSW_CCB_SZ 64
58#define ILOHW_CCB_SZ 128
59struct ccb {
60 union {
61 char *send_fifobar;
62 u64 padding1;
63 } ccb_u1;
64 union {
65 char *send_desc;
66 u64 padding2;
67 } ccb_u2;
68 u64 send_ctrl;
69
70 union {
71 char *recv_fifobar;
72 u64 padding3;
73 } ccb_u3;
74 union {
75 char *recv_desc;
76 u64 padding4;
77 } ccb_u4;
78 u64 recv_ctrl;
79
80 union {
81 char __iomem *db_base;
82 u64 padding5;
83 } ccb_u5;
84
85 u64 channel;
86
87 /* unused context area (64 bytes) */
88};
89
90/* ccb queue parameters */
91#define SENDQ 1
92#define RECVQ 2
93#define NR_QENTRY 4
94#define L2_QENTRY_SZ 12
95
96/* ccb ctrl bitfields */
97#define CTRL_BITPOS_L2SZ 0
98#define CTRL_BITPOS_FIFOINDEXMASK 4
99#define CTRL_BITPOS_DESCLIMIT 18
100#define CTRL_BITPOS_A 30
101#define CTRL_BITPOS_G 31
102
103/* ccb doorbell macros */
104#define L2_DB_SIZE 14
105#define ONE_DB_SIZE (1 << L2_DB_SIZE)
106
107/*
108 * Per fd structure used to track the ccb allocated to that dev file.
109 */
110struct ccb_data {
111 /* software version of ccb, using virtual addrs */
112 struct ccb driver_ccb;
113
114 /* hardware version of ccb, using physical addrs */
115 struct ccb ilo_ccb;
116
117 /* hardware ccb is written to this shared mapped device memory */
118 struct ccb __iomem *mapped_ccb;
119
120 /* dma'able memory used for send/recv queues */
121 void *dma_va;
122 dma_addr_t dma_pa;
123 size_t dma_size;
124
125 /* pointer to hardware device info */
126 struct ilo_hwinfo *ilo_hw;
127
128 /* usage count, to allow for shared ccb's */
129 int ccb_cnt;
130
131 /* open wanted exclusive access to this ccb */
132 int ccb_excl;
133};
134
135/*
136 * FIFO queue structure, shared with hw.
137 */
138#define ILO_START_ALIGN 4096
139#define ILO_CACHE_SZ 128
140struct fifo {
141 u64 nrents; /* user requested number of fifo entries */
142 u64 imask; /* mask to extract valid fifo index */
143 u64 merge; /* O/C bits to merge in during enqueue operation */
144 u64 reset; /* set to non-zero when the target device resets */
145 u8 pad_0[ILO_CACHE_SZ - (sizeof(u64) * 4)];
146
147 u64 head;
148 u8 pad_1[ILO_CACHE_SZ - (sizeof(u64))];
149
150 u64 tail;
151 u8 pad_2[ILO_CACHE_SZ - (sizeof(u64))];
152
153 u64 fifobar[1];
154};
155
156/* convert between struct fifo, and the fifobar, which is saved in the ccb */
157#define FIFOHANDLESIZE (sizeof(struct fifo) - sizeof(u64))
158#define FIFOBARTOHANDLE(_fifo) \
159 ((struct fifo *)(((char *)(_fifo)) - FIFOHANDLESIZE))
160
161/* the number of qwords to consume from the entry descriptor */
162#define ENTRY_BITPOS_QWORDS 0
163/* descriptor index number (within a specified queue) */
164#define ENTRY_BITPOS_DESCRIPTOR 10
165/* state bit, fifo entry consumed by consumer */
166#define ENTRY_BITPOS_C 22
167/* state bit, fifo entry is occupied */
168#define ENTRY_BITPOS_O 23
169
170#define ENTRY_BITS_QWORDS 10
171#define ENTRY_BITS_DESCRIPTOR 12
172#define ENTRY_BITS_C 1
173#define ENTRY_BITS_O 1
174#define ENTRY_BITS_TOTAL \
175 (ENTRY_BITS_C + ENTRY_BITS_O + \
176 ENTRY_BITS_QWORDS + ENTRY_BITS_DESCRIPTOR)
177
178/* extract various entry fields */
179#define ENTRY_MASK ((1 << ENTRY_BITS_TOTAL) - 1)
180#define ENTRY_MASK_C (((1 << ENTRY_BITS_C) - 1) << ENTRY_BITPOS_C)
181#define ENTRY_MASK_O (((1 << ENTRY_BITS_O) - 1) << ENTRY_BITPOS_O)
182#define ENTRY_MASK_QWORDS \
183 (((1 << ENTRY_BITS_QWORDS) - 1) << ENTRY_BITPOS_QWORDS)
184#define ENTRY_MASK_DESCRIPTOR \
185 (((1 << ENTRY_BITS_DESCRIPTOR) - 1) << ENTRY_BITPOS_DESCRIPTOR)
186
187#define ENTRY_MASK_NOSTATE (ENTRY_MASK >> (ENTRY_BITS_C + ENTRY_BITS_O))
188
189#endif /* __HPILO_H */
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index 186162470090..daf585689ce3 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -399,8 +399,9 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
399 goto err_irq; 399 goto err_irq;
400 } 400 }
401 401
402 if (IS_ERR(device_create(phantom_class, &pdev->dev, MKDEV(phantom_major, 402 if (IS_ERR(device_create_drvdata(phantom_class, &pdev->dev,
403 minor), "phantom%u", minor))) 403 MKDEV(phantom_major, minor),
404 NULL, "phantom%u", minor)))
404 dev_err(&pdev->dev, "can't create device\n"); 405 dev_err(&pdev->dev, "can't create device\n");
405 406
406 pci_set_drvdata(pdev, pht); 407 pci_set_drvdata(pdev, pht);
@@ -562,6 +563,6 @@ module_init(phantom_init);
562module_exit(phantom_exit); 563module_exit(phantom_exit);
563 564
564MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>"); 565MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>");
565MODULE_DESCRIPTION("Sensable Phantom driver"); 566MODULE_DESCRIPTION("Sensable Phantom driver (PCI devices)");
566MODULE_LICENSE("GPL"); 567MODULE_LICENSE("GPL");
567MODULE_VERSION(PHANTOM_VERSION); 568MODULE_VERSION(PHANTOM_VERSION);
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c
index 08256ed0d9a6..579b01ff82d4 100644
--- a/drivers/misc/sgi-xp/xpc_main.c
+++ b/drivers/misc/sgi-xp/xpc_main.c
@@ -229,10 +229,11 @@ xpc_hb_checker(void *ignore)
229 int last_IRQ_count = 0; 229 int last_IRQ_count = 0;
230 int new_IRQ_count; 230 int new_IRQ_count;
231 int force_IRQ = 0; 231 int force_IRQ = 0;
232 cpumask_of_cpu_ptr(cpumask, XPC_HB_CHECK_CPU);
232 233
233 /* this thread was marked active by xpc_hb_init() */ 234 /* this thread was marked active by xpc_hb_init() */
234 235
235 set_cpus_allowed(current, cpumask_of_cpu(XPC_HB_CHECK_CPU)); 236 set_cpus_allowed_ptr(current, cpumask);
236 237
237 /* set our heartbeating to other partitions into motion */ 238 /* set our heartbeating to other partitions into motion */
238 xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ); 239 xpc_hb_check_timeout = jiffies + (xpc_hb_check_interval * HZ);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index b5969298f3d3..d3eb7903c346 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,7 +21,7 @@
21 * 02110-1301, USA. 21 * 02110-1301, USA.
22 */ 22 */
23 23
24#define TPACPI_VERSION "0.20" 24#define TPACPI_VERSION "0.21"
25#define TPACPI_SYSFS_VERSION 0x020200 25#define TPACPI_SYSFS_VERSION 0x020200
26 26
27/* 27/*
@@ -68,6 +68,7 @@
68#include <linux/hwmon-sysfs.h> 68#include <linux/hwmon-sysfs.h>
69#include <linux/input.h> 69#include <linux/input.h>
70#include <linux/leds.h> 70#include <linux/leds.h>
71#include <linux/rfkill.h>
71#include <asm/uaccess.h> 72#include <asm/uaccess.h>
72 73
73#include <linux/dmi.h> 74#include <linux/dmi.h>
@@ -144,6 +145,12 @@ enum {
144 145
145#define TPACPI_MAX_ACPI_ARGS 3 146#define TPACPI_MAX_ACPI_ARGS 3
146 147
148/* rfkill switches */
149enum {
150 TPACPI_RFK_BLUETOOTH_SW_ID = 0,
151 TPACPI_RFK_WWAN_SW_ID,
152};
153
147/* Debugging */ 154/* Debugging */
148#define TPACPI_LOG TPACPI_FILE ": " 155#define TPACPI_LOG TPACPI_FILE ": "
149#define TPACPI_ERR KERN_ERR TPACPI_LOG 156#define TPACPI_ERR KERN_ERR TPACPI_LOG
@@ -905,6 +912,43 @@ static int __init tpacpi_check_std_acpi_brightness_support(void)
905 return 0; 912 return 0;
906} 913}
907 914
915static int __init tpacpi_new_rfkill(const unsigned int id,
916 struct rfkill **rfk,
917 const enum rfkill_type rfktype,
918 const char *name,
919 int (*toggle_radio)(void *, enum rfkill_state),
920 int (*get_state)(void *, enum rfkill_state *))
921{
922 int res;
923 enum rfkill_state initial_state;
924
925 *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype);
926 if (!*rfk) {
927 printk(TPACPI_ERR
928 "failed to allocate memory for rfkill class\n");
929 return -ENOMEM;
930 }
931
932 (*rfk)->name = name;
933 (*rfk)->get_state = get_state;
934 (*rfk)->toggle_radio = toggle_radio;
935
936 if (!get_state(NULL, &initial_state))
937 (*rfk)->state = initial_state;
938
939 res = rfkill_register(*rfk);
940 if (res < 0) {
941 printk(TPACPI_ERR
942 "failed to register %s rfkill switch: %d\n",
943 name, res);
944 rfkill_free(*rfk);
945 *rfk = NULL;
946 return res;
947 }
948
949 return 0;
950}
951
908/************************************************************************* 952/*************************************************************************
909 * thinkpad-acpi driver attributes 953 * thinkpad-acpi driver attributes
910 */ 954 */
@@ -1285,21 +1329,6 @@ static int hotkey_status_set(int status)
1285 return 0; 1329 return 0;
1286} 1330}
1287 1331
1288static void tpacpi_input_send_radiosw(void)
1289{
1290 int wlsw;
1291
1292 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
1293 mutex_lock(&tpacpi_inputdev_send_mutex);
1294
1295 input_report_switch(tpacpi_inputdev,
1296 SW_RFKILL_ALL, !!wlsw);
1297 input_sync(tpacpi_inputdev);
1298
1299 mutex_unlock(&tpacpi_inputdev_send_mutex);
1300 }
1301}
1302
1303static void tpacpi_input_send_tabletsw(void) 1332static void tpacpi_input_send_tabletsw(void)
1304{ 1333{
1305 int state; 1334 int state;
@@ -1921,6 +1950,30 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
1921 &dev_attr_hotkey_wakeup_hotunplug_complete.attr, 1950 &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
1922}; 1951};
1923 1952
1953static void bluetooth_update_rfk(void);
1954static void wan_update_rfk(void);
1955static void tpacpi_send_radiosw_update(void)
1956{
1957 int wlsw;
1958
1959 /* Sync these BEFORE sending any rfkill events */
1960 if (tp_features.bluetooth)
1961 bluetooth_update_rfk();
1962 if (tp_features.wan)
1963 wan_update_rfk();
1964
1965 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
1966 mutex_lock(&tpacpi_inputdev_send_mutex);
1967
1968 input_report_switch(tpacpi_inputdev,
1969 SW_RFKILL_ALL, !!wlsw);
1970 input_sync(tpacpi_inputdev);
1971
1972 mutex_unlock(&tpacpi_inputdev_send_mutex);
1973 }
1974 hotkey_radio_sw_notify_change();
1975}
1976
1924static void hotkey_exit(void) 1977static void hotkey_exit(void)
1925{ 1978{
1926#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL 1979#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
@@ -2167,9 +2220,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2167 printk(TPACPI_INFO 2220 printk(TPACPI_INFO
2168 "radio switch found; radios are %s\n", 2221 "radio switch found; radios are %s\n",
2169 enabled(status, 0)); 2222 enabled(status, 0));
2223 }
2224 if (tp_features.hotkey_wlsw)
2170 res = add_to_attr_set(hotkey_dev_attributes, 2225 res = add_to_attr_set(hotkey_dev_attributes,
2171 &dev_attr_hotkey_radio_sw.attr); 2226 &dev_attr_hotkey_radio_sw.attr);
2172 }
2173 2227
2174 /* For X41t, X60t, X61t Tablets... */ 2228 /* For X41t, X60t, X61t Tablets... */
2175 if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { 2229 if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
@@ -2287,7 +2341,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
2287 tpacpi_inputdev->close = &hotkey_inputdev_close; 2341 tpacpi_inputdev->close = &hotkey_inputdev_close;
2288 2342
2289 hotkey_poll_setup_safe(1); 2343 hotkey_poll_setup_safe(1);
2290 tpacpi_input_send_radiosw(); 2344 tpacpi_send_radiosw_update();
2291 tpacpi_input_send_tabletsw(); 2345 tpacpi_input_send_tabletsw();
2292 2346
2293 return 0; 2347 return 0;
@@ -2419,8 +2473,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
2419 case 7: 2473 case 7:
2420 /* 0x7000-0x7FFF: misc */ 2474 /* 0x7000-0x7FFF: misc */
2421 if (tp_features.hotkey_wlsw && hkey == 0x7000) { 2475 if (tp_features.hotkey_wlsw && hkey == 0x7000) {
2422 tpacpi_input_send_radiosw(); 2476 tpacpi_send_radiosw_update();
2423 hotkey_radio_sw_notify_change();
2424 send_acpi_ev = 0; 2477 send_acpi_ev = 0;
2425 break; 2478 break;
2426 } 2479 }
@@ -2463,8 +2516,7 @@ static void hotkey_resume(void)
2463 printk(TPACPI_ERR 2516 printk(TPACPI_ERR
2464 "error while trying to read hot key mask " 2517 "error while trying to read hot key mask "
2465 "from firmware\n"); 2518 "from firmware\n");
2466 tpacpi_input_send_radiosw(); 2519 tpacpi_send_radiosw_update();
2467 hotkey_radio_sw_notify_change();
2468 hotkey_tablet_mode_notify_change(); 2520 hotkey_tablet_mode_notify_change();
2469 hotkey_wakeup_reason_notify_change(); 2521 hotkey_wakeup_reason_notify_change();
2470 hotkey_wakeup_hotunplug_complete_notify_change(); 2522 hotkey_wakeup_hotunplug_complete_notify_change();
@@ -2581,8 +2633,66 @@ enum {
2581 TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ 2633 TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
2582}; 2634};
2583 2635
2584static int bluetooth_get_radiosw(void); 2636static struct rfkill *tpacpi_bluetooth_rfkill;
2585static int bluetooth_set_radiosw(int radio_on); 2637
2638static int bluetooth_get_radiosw(void)
2639{
2640 int status;
2641
2642 if (!tp_features.bluetooth)
2643 return -ENODEV;
2644
2645 /* WLSW overrides bluetooth in firmware/hardware, reflect that */
2646 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
2647 return RFKILL_STATE_HARD_BLOCKED;
2648
2649 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
2650 return -EIO;
2651
2652 return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ?
2653 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
2654}
2655
2656static void bluetooth_update_rfk(void)
2657{
2658 int status;
2659
2660 if (!tpacpi_bluetooth_rfkill)
2661 return;
2662
2663 status = bluetooth_get_radiosw();
2664 if (status < 0)
2665 return;
2666 rfkill_force_state(tpacpi_bluetooth_rfkill, status);
2667}
2668
2669static int bluetooth_set_radiosw(int radio_on, int update_rfk)
2670{
2671 int status;
2672
2673 if (!tp_features.bluetooth)
2674 return -ENODEV;
2675
2676 /* WLSW overrides bluetooth in firmware/hardware, but there is no
2677 * reason to risk weird behaviour. */
2678 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
2679 && radio_on)
2680 return -EPERM;
2681
2682 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
2683 return -EIO;
2684 if (radio_on)
2685 status |= TP_ACPI_BLUETOOTH_RADIOSSW;
2686 else
2687 status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
2688 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
2689 return -EIO;
2690
2691 if (update_rfk)
2692 bluetooth_update_rfk();
2693
2694 return 0;
2695}
2586 2696
2587/* sysfs bluetooth enable ---------------------------------------------- */ 2697/* sysfs bluetooth enable ---------------------------------------------- */
2588static ssize_t bluetooth_enable_show(struct device *dev, 2698static ssize_t bluetooth_enable_show(struct device *dev,
@@ -2595,7 +2705,8 @@ static ssize_t bluetooth_enable_show(struct device *dev,
2595 if (status < 0) 2705 if (status < 0)
2596 return status; 2706 return status;
2597 2707
2598 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); 2708 return snprintf(buf, PAGE_SIZE, "%d\n",
2709 (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0);
2599} 2710}
2600 2711
2601static ssize_t bluetooth_enable_store(struct device *dev, 2712static ssize_t bluetooth_enable_store(struct device *dev,
@@ -2608,7 +2719,7 @@ static ssize_t bluetooth_enable_store(struct device *dev,
2608 if (parse_strtoul(buf, 1, &t)) 2719 if (parse_strtoul(buf, 1, &t))
2609 return -EINVAL; 2720 return -EINVAL;
2610 2721
2611 res = bluetooth_set_radiosw(t); 2722 res = bluetooth_set_radiosw(t, 1);
2612 2723
2613 return (res) ? res : count; 2724 return (res) ? res : count;
2614} 2725}
@@ -2628,6 +2739,31 @@ static const struct attribute_group bluetooth_attr_group = {
2628 .attrs = bluetooth_attributes, 2739 .attrs = bluetooth_attributes,
2629}; 2740};
2630 2741
2742static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state)
2743{
2744 int bts = bluetooth_get_radiosw();
2745
2746 if (bts < 0)
2747 return bts;
2748
2749 *state = bts;
2750 return 0;
2751}
2752
2753static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state)
2754{
2755 return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
2756}
2757
2758static void bluetooth_exit(void)
2759{
2760 if (tpacpi_bluetooth_rfkill)
2761 rfkill_unregister(tpacpi_bluetooth_rfkill);
2762
2763 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2764 &bluetooth_attr_group);
2765}
2766
2631static int __init bluetooth_init(struct ibm_init_struct *iibm) 2767static int __init bluetooth_init(struct ibm_init_struct *iibm)
2632{ 2768{
2633 int res; 2769 int res;
@@ -2646,57 +2782,32 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
2646 str_supported(tp_features.bluetooth), 2782 str_supported(tp_features.bluetooth),
2647 status); 2783 status);
2648 2784
2649 if (tp_features.bluetooth) { 2785 if (tp_features.bluetooth &&
2650 if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { 2786 !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
2651 /* no bluetooth hardware present in system */ 2787 /* no bluetooth hardware present in system */
2652 tp_features.bluetooth = 0; 2788 tp_features.bluetooth = 0;
2653 dbg_printk(TPACPI_DBG_INIT, 2789 dbg_printk(TPACPI_DBG_INIT,
2654 "bluetooth hardware not installed\n"); 2790 "bluetooth hardware not installed\n");
2655 } else {
2656 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2657 &bluetooth_attr_group);
2658 if (res)
2659 return res;
2660 }
2661 } 2791 }
2662 2792
2663 return (tp_features.bluetooth)? 0 : 1;
2664}
2665
2666static void bluetooth_exit(void)
2667{
2668 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2669 &bluetooth_attr_group);
2670}
2671
2672static int bluetooth_get_radiosw(void)
2673{
2674 int status;
2675
2676 if (!tp_features.bluetooth) 2793 if (!tp_features.bluetooth)
2677 return -ENODEV; 2794 return 1;
2678
2679 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
2680 return -EIO;
2681
2682 return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
2683}
2684
2685static int bluetooth_set_radiosw(int radio_on)
2686{
2687 int status;
2688 2795
2689 if (!tp_features.bluetooth) 2796 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2690 return -ENODEV; 2797 &bluetooth_attr_group);
2798 if (res)
2799 return res;
2691 2800
2692 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) 2801 res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID,
2693 return -EIO; 2802 &tpacpi_bluetooth_rfkill,
2694 if (radio_on) 2803 RFKILL_TYPE_BLUETOOTH,
2695 status |= TP_ACPI_BLUETOOTH_RADIOSSW; 2804 "tpacpi_bluetooth_sw",
2696 else 2805 tpacpi_bluetooth_rfk_set,
2697 status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; 2806 tpacpi_bluetooth_rfk_get);
2698 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) 2807 if (res) {
2699 return -EIO; 2808 bluetooth_exit();
2809 return res;
2810 }
2700 2811
2701 return 0; 2812 return 0;
2702} 2813}
@@ -2711,7 +2822,8 @@ static int bluetooth_read(char *p)
2711 len += sprintf(p + len, "status:\t\tnot supported\n"); 2822 len += sprintf(p + len, "status:\t\tnot supported\n");
2712 else { 2823 else {
2713 len += sprintf(p + len, "status:\t\t%s\n", 2824 len += sprintf(p + len, "status:\t\t%s\n",
2714 (status)? "enabled" : "disabled"); 2825 (status == RFKILL_STATE_UNBLOCKED) ?
2826 "enabled" : "disabled");
2715 len += sprintf(p + len, "commands:\tenable, disable\n"); 2827 len += sprintf(p + len, "commands:\tenable, disable\n");
2716 } 2828 }
2717 2829
@@ -2727,9 +2839,9 @@ static int bluetooth_write(char *buf)
2727 2839
2728 while ((cmd = next_cmd(&buf))) { 2840 while ((cmd = next_cmd(&buf))) {
2729 if (strlencmp(cmd, "enable") == 0) { 2841 if (strlencmp(cmd, "enable") == 0) {
2730 bluetooth_set_radiosw(1); 2842 bluetooth_set_radiosw(1, 1);
2731 } else if (strlencmp(cmd, "disable") == 0) { 2843 } else if (strlencmp(cmd, "disable") == 0) {
2732 bluetooth_set_radiosw(0); 2844 bluetooth_set_radiosw(0, 1);
2733 } else 2845 } else
2734 return -EINVAL; 2846 return -EINVAL;
2735 } 2847 }
@@ -2755,8 +2867,66 @@ enum {
2755 TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ 2867 TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
2756}; 2868};
2757 2869
2758static int wan_get_radiosw(void); 2870static struct rfkill *tpacpi_wan_rfkill;
2759static int wan_set_radiosw(int radio_on); 2871
2872static int wan_get_radiosw(void)
2873{
2874 int status;
2875
2876 if (!tp_features.wan)
2877 return -ENODEV;
2878
2879 /* WLSW overrides WWAN in firmware/hardware, reflect that */
2880 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
2881 return RFKILL_STATE_HARD_BLOCKED;
2882
2883 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
2884 return -EIO;
2885
2886 return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ?
2887 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
2888}
2889
2890static void wan_update_rfk(void)
2891{
2892 int status;
2893
2894 if (!tpacpi_wan_rfkill)
2895 return;
2896
2897 status = wan_get_radiosw();
2898 if (status < 0)
2899 return;
2900 rfkill_force_state(tpacpi_wan_rfkill, status);
2901}
2902
2903static int wan_set_radiosw(int radio_on, int update_rfk)
2904{
2905 int status;
2906
2907 if (!tp_features.wan)
2908 return -ENODEV;
2909
2910 /* WLSW overrides bluetooth in firmware/hardware, but there is no
2911 * reason to risk weird behaviour. */
2912 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
2913 && radio_on)
2914 return -EPERM;
2915
2916 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
2917 return -EIO;
2918 if (radio_on)
2919 status |= TP_ACPI_WANCARD_RADIOSSW;
2920 else
2921 status &= ~TP_ACPI_WANCARD_RADIOSSW;
2922 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
2923 return -EIO;
2924
2925 if (update_rfk)
2926 wan_update_rfk();
2927
2928 return 0;
2929}
2760 2930
2761/* sysfs wan enable ---------------------------------------------------- */ 2931/* sysfs wan enable ---------------------------------------------------- */
2762static ssize_t wan_enable_show(struct device *dev, 2932static ssize_t wan_enable_show(struct device *dev,
@@ -2769,7 +2939,8 @@ static ssize_t wan_enable_show(struct device *dev,
2769 if (status < 0) 2939 if (status < 0)
2770 return status; 2940 return status;
2771 2941
2772 return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); 2942 return snprintf(buf, PAGE_SIZE, "%d\n",
2943 (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0);
2773} 2944}
2774 2945
2775static ssize_t wan_enable_store(struct device *dev, 2946static ssize_t wan_enable_store(struct device *dev,
@@ -2782,7 +2953,7 @@ static ssize_t wan_enable_store(struct device *dev,
2782 if (parse_strtoul(buf, 1, &t)) 2953 if (parse_strtoul(buf, 1, &t))
2783 return -EINVAL; 2954 return -EINVAL;
2784 2955
2785 res = wan_set_radiosw(t); 2956 res = wan_set_radiosw(t, 1);
2786 2957
2787 return (res) ? res : count; 2958 return (res) ? res : count;
2788} 2959}
@@ -2802,6 +2973,31 @@ static const struct attribute_group wan_attr_group = {
2802 .attrs = wan_attributes, 2973 .attrs = wan_attributes,
2803}; 2974};
2804 2975
2976static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state)
2977{
2978 int wans = wan_get_radiosw();
2979
2980 if (wans < 0)
2981 return wans;
2982
2983 *state = wans;
2984 return 0;
2985}
2986
2987static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state)
2988{
2989 return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
2990}
2991
2992static void wan_exit(void)
2993{
2994 if (tpacpi_wan_rfkill)
2995 rfkill_unregister(tpacpi_wan_rfkill);
2996
2997 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2998 &wan_attr_group);
2999}
3000
2805static int __init wan_init(struct ibm_init_struct *iibm) 3001static int __init wan_init(struct ibm_init_struct *iibm)
2806{ 3002{
2807 int res; 3003 int res;
@@ -2818,57 +3014,32 @@ static int __init wan_init(struct ibm_init_struct *iibm)
2818 str_supported(tp_features.wan), 3014 str_supported(tp_features.wan),
2819 status); 3015 status);
2820 3016
2821 if (tp_features.wan) { 3017 if (tp_features.wan &&
2822 if (!(status & TP_ACPI_WANCARD_HWPRESENT)) { 3018 !(status & TP_ACPI_WANCARD_HWPRESENT)) {
2823 /* no wan hardware present in system */ 3019 /* no wan hardware present in system */
2824 tp_features.wan = 0; 3020 tp_features.wan = 0;
2825 dbg_printk(TPACPI_DBG_INIT, 3021 dbg_printk(TPACPI_DBG_INIT,
2826 "wan hardware not installed\n"); 3022 "wan hardware not installed\n");
2827 } else {
2828 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2829 &wan_attr_group);
2830 if (res)
2831 return res;
2832 }
2833 } 3023 }
2834 3024
2835 return (tp_features.wan)? 0 : 1;
2836}
2837
2838static void wan_exit(void)
2839{
2840 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
2841 &wan_attr_group);
2842}
2843
2844static int wan_get_radiosw(void)
2845{
2846 int status;
2847
2848 if (!tp_features.wan) 3025 if (!tp_features.wan)
2849 return -ENODEV; 3026 return 1;
2850
2851 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
2852 return -EIO;
2853
2854 return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0);
2855}
2856
2857static int wan_set_radiosw(int radio_on)
2858{
2859 int status;
2860 3027
2861 if (!tp_features.wan) 3028 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
2862 return -ENODEV; 3029 &wan_attr_group);
3030 if (res)
3031 return res;
2863 3032
2864 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) 3033 res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID,
2865 return -EIO; 3034 &tpacpi_wan_rfkill,
2866 if (radio_on) 3035 RFKILL_TYPE_WWAN,
2867 status |= TP_ACPI_WANCARD_RADIOSSW; 3036 "tpacpi_wwan_sw",
2868 else 3037 tpacpi_wan_rfk_set,
2869 status &= ~TP_ACPI_WANCARD_RADIOSSW; 3038 tpacpi_wan_rfk_get);
2870 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) 3039 if (res) {
2871 return -EIO; 3040 wan_exit();
3041 return res;
3042 }
2872 3043
2873 return 0; 3044 return 0;
2874} 3045}
@@ -2883,7 +3054,8 @@ static int wan_read(char *p)
2883 len += sprintf(p + len, "status:\t\tnot supported\n"); 3054 len += sprintf(p + len, "status:\t\tnot supported\n");
2884 else { 3055 else {
2885 len += sprintf(p + len, "status:\t\t%s\n", 3056 len += sprintf(p + len, "status:\t\t%s\n",
2886 (status)? "enabled" : "disabled"); 3057 (status == RFKILL_STATE_UNBLOCKED) ?
3058 "enabled" : "disabled");
2887 len += sprintf(p + len, "commands:\tenable, disable\n"); 3059 len += sprintf(p + len, "commands:\tenable, disable\n");
2888 } 3060 }
2889 3061
@@ -2899,9 +3071,9 @@ static int wan_write(char *buf)
2899 3071
2900 while ((cmd = next_cmd(&buf))) { 3072 while ((cmd = next_cmd(&buf))) {
2901 if (strlencmp(cmd, "enable") == 0) { 3073 if (strlencmp(cmd, "enable") == 0) {
2902 wan_set_radiosw(1); 3074 wan_set_radiosw(1, 1);
2903 } else if (strlencmp(cmd, "disable") == 0) { 3075 } else if (strlencmp(cmd, "disable") == 0) {
2904 wan_set_radiosw(0); 3076 wan_set_radiosw(0, 1);
2905 } else 3077 } else
2906 return -EINVAL; 3078 return -EINVAL;
2907 } 3079 }
@@ -6168,13 +6340,18 @@ err_out:
6168 6340
6169/* Probing */ 6341/* Probing */
6170 6342
6171static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) 6343/* returns 0 - probe ok, or < 0 - probe error.
6344 * Probe ok doesn't mean thinkpad found.
6345 * On error, kfree() cleanup on tp->* is not performed, caller must do it */
6346static int __must_check __init get_thinkpad_model_data(
6347 struct thinkpad_id_data *tp)
6172{ 6348{
6173 const struct dmi_device *dev = NULL; 6349 const struct dmi_device *dev = NULL;
6174 char ec_fw_string[18]; 6350 char ec_fw_string[18];
6351 char const *s;
6175 6352
6176 if (!tp) 6353 if (!tp)
6177 return; 6354 return -EINVAL;
6178 6355
6179 memset(tp, 0, sizeof(*tp)); 6356 memset(tp, 0, sizeof(*tp));
6180 6357
@@ -6183,12 +6360,14 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
6183 else if (dmi_name_in_vendors("LENOVO")) 6360 else if (dmi_name_in_vendors("LENOVO"))
6184 tp->vendor = PCI_VENDOR_ID_LENOVO; 6361 tp->vendor = PCI_VENDOR_ID_LENOVO;
6185 else 6362 else
6186 return; 6363 return 0;
6187 6364
6188 tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION), 6365 s = dmi_get_system_info(DMI_BIOS_VERSION);
6189 GFP_KERNEL); 6366 tp->bios_version_str = kstrdup(s, GFP_KERNEL);
6367 if (s && !tp->bios_version_str)
6368 return -ENOMEM;
6190 if (!tp->bios_version_str) 6369 if (!tp->bios_version_str)
6191 return; 6370 return 0;
6192 tp->bios_model = tp->bios_version_str[0] 6371 tp->bios_model = tp->bios_version_str[0]
6193 | (tp->bios_version_str[1] << 8); 6372 | (tp->bios_version_str[1] << 8);
6194 6373
@@ -6207,21 +6386,27 @@ static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
6207 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; 6386 ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
6208 6387
6209 tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); 6388 tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
6389 if (!tp->ec_version_str)
6390 return -ENOMEM;
6210 tp->ec_model = ec_fw_string[0] 6391 tp->ec_model = ec_fw_string[0]
6211 | (ec_fw_string[1] << 8); 6392 | (ec_fw_string[1] << 8);
6212 break; 6393 break;
6213 } 6394 }
6214 } 6395 }
6215 6396
6216 tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION), 6397 s = dmi_get_system_info(DMI_PRODUCT_VERSION);
6217 GFP_KERNEL); 6398 if (s && !strnicmp(s, "ThinkPad", 8)) {
6218 if (tp->model_str && strnicmp(tp->model_str, "ThinkPad", 8) != 0) { 6399 tp->model_str = kstrdup(s, GFP_KERNEL);
6219 kfree(tp->model_str); 6400 if (!tp->model_str)
6220 tp->model_str = NULL; 6401 return -ENOMEM;
6221 } 6402 }
6222 6403
6223 tp->nummodel_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_NAME), 6404 s = dmi_get_system_info(DMI_PRODUCT_NAME);
6224 GFP_KERNEL); 6405 tp->nummodel_str = kstrdup(s, GFP_KERNEL);
6406 if (s && !tp->nummodel_str)
6407 return -ENOMEM;
6408
6409 return 0;
6225} 6410}
6226 6411
6227static int __init probe_for_thinkpad(void) 6412static int __init probe_for_thinkpad(void)
@@ -6484,7 +6669,13 @@ static int __init thinkpad_acpi_module_init(void)
6484 6669
6485 /* Driver-level probe */ 6670 /* Driver-level probe */
6486 6671
6487 get_thinkpad_model_data(&thinkpad_id); 6672 ret = get_thinkpad_model_data(&thinkpad_id);
6673 if (ret) {
6674 printk(TPACPI_ERR
6675 "unable to get DMI data: %d\n", ret);
6676 thinkpad_acpi_module_exit();
6677 return ret;
6678 }
6488 ret = probe_for_thinkpad(); 6679 ret = probe_for_thinkpad();
6489 if (ret) { 6680 if (ret) {
6490 thinkpad_acpi_module_exit(); 6681 thinkpad_acpi_module_exit();