aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/blacklist.c14
-rw-r--r--drivers/acpi/bus.c28
-rw-r--r--drivers/acpi/ec.c10
-rw-r--r--drivers/acpi/internal.h1
-rw-r--r--drivers/acpi/processor_core.c71
-rw-r--r--drivers/acpi/processor_pdc.c165
-rw-r--r--drivers/ata/Kconfig1
-rw-r--r--drivers/platform/x86/Kconfig12
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acer-wmi.c3
-rw-r--r--drivers/platform/x86/acerhdf.c68
-rw-r--r--drivers/platform/x86/asus_acpi.c321
-rw-r--r--drivers/platform/x86/classmate-laptop.c609
-rw-r--r--drivers/platform/x86/dell-wmi.c42
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c8
-rw-r--r--drivers/platform/x86/hp-wmi.c11
-rw-r--r--drivers/platform/x86/msi-wmi.c10
-rw-r--r--drivers/platform/x86/sony-laptop.c94
-rw-r--r--drivers/platform/x86/tc1100-wmi.c115
-rw-r--r--drivers/platform/x86/toshiba_acpi.c259
-rw-r--r--drivers/platform/x86/wmi.c4
22 files changed, 1381 insertions, 467 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index c7b10b4298e9..66cc3f36a954 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -32,6 +32,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o
32# 32#
33acpi-y += bus.o glue.o 33acpi-y += bus.o glue.o
34acpi-y += scan.o 34acpi-y += scan.o
35acpi-y += processor_pdc.o
35acpi-y += ec.o 36acpi-y += ec.o
36acpi-$(CONFIG_ACPI_DOCK) += dock.o 37acpi-$(CONFIG_ACPI_DOCK) += dock.o
37acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o 38acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 23e5a0519af5..2815df66f6f7 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -185,6 +185,12 @@ static int __init dmi_disable_osi_vista(const struct dmi_system_id *d)
185 acpi_osi_setup("!Windows 2006"); 185 acpi_osi_setup("!Windows 2006");
186 return 0; 186 return 0;
187} 187}
188static int __init dmi_disable_osi_win7(const struct dmi_system_id *d)
189{
190 printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
191 acpi_osi_setup("!Windows 2009");
192 return 0;
193}
188 194
189static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { 195static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
190 { 196 {
@@ -211,6 +217,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
211 DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"), 217 DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"),
212 }, 218 },
213 }, 219 },
220 {
221 .callback = dmi_disable_osi_win7,
222 .ident = "ASUS K50IJ",
223 .matches = {
224 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
225 DMI_MATCH(DMI_PRODUCT_NAME, "K50IJ"),
226 },
227 },
214 228
215 /* 229 /*
216 * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. 230 * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 65f7e335f122..cf761b904e4a 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -397,6 +397,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
397 union acpi_object *out_obj; 397 union acpi_object *out_obj;
398 u8 uuid[16]; 398 u8 uuid[16];
399 u32 errors; 399 u32 errors;
400 struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
400 401
401 if (!context) 402 if (!context)
402 return AE_ERROR; 403 return AE_ERROR;
@@ -419,16 +420,16 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
419 in_params[3].buffer.length = context->cap.length; 420 in_params[3].buffer.length = context->cap.length;
420 in_params[3].buffer.pointer = context->cap.pointer; 421 in_params[3].buffer.pointer = context->cap.pointer;
421 422
422 status = acpi_evaluate_object(handle, "_OSC", &input, &context->ret); 423 status = acpi_evaluate_object(handle, "_OSC", &input, &output);
423 if (ACPI_FAILURE(status)) 424 if (ACPI_FAILURE(status))
424 return status; 425 return status;
425 426
426 /* return buffer should have the same length as cap buffer */ 427 if (!output.length)
427 if (context->ret.length != context->cap.length)
428 return AE_NULL_OBJECT; 428 return AE_NULL_OBJECT;
429 429
430 out_obj = context->ret.pointer; 430 out_obj = output.pointer;
431 if (out_obj->type != ACPI_TYPE_BUFFER) { 431 if (out_obj->type != ACPI_TYPE_BUFFER
432 || out_obj->buffer.length != context->cap.length) {
432 acpi_print_osc_error(handle, context, 433 acpi_print_osc_error(handle, context,
433 "_OSC evaluation returned wrong type"); 434 "_OSC evaluation returned wrong type");
434 status = AE_TYPE; 435 status = AE_TYPE;
@@ -457,11 +458,20 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
457 goto out_kfree; 458 goto out_kfree;
458 } 459 }
459out_success: 460out_success:
460 return AE_OK; 461 context->ret.length = out_obj->buffer.length;
462 context->ret.pointer = kmalloc(context->ret.length, GFP_KERNEL);
463 if (!context->ret.pointer) {
464 status = AE_NO_MEMORY;
465 goto out_kfree;
466 }
467 memcpy(context->ret.pointer, out_obj->buffer.pointer,
468 context->ret.length);
469 status = AE_OK;
461 470
462out_kfree: 471out_kfree:
463 kfree(context->ret.pointer); 472 kfree(output.pointer);
464 context->ret.pointer = NULL; 473 if (status != AE_OK)
474 context->ret.pointer = NULL;
465 return status; 475 return status;
466} 476}
467EXPORT_SYMBOL(acpi_run_osc); 477EXPORT_SYMBOL(acpi_run_osc);
@@ -888,6 +898,8 @@ static int __init acpi_bus_init(void)
888 goto error1; 898 goto error1;
889 } 899 }
890 900
901 acpi_early_processor_set_pdc();
902
891 /* 903 /*
892 * Maybe EC region is required at bus_scan/acpi_get_devices. So it 904 * Maybe EC region is required at bus_scan/acpi_get_devices. So it
893 * is necessary to enable it as early as possible. 905 * is necessary to enable it as early as possible.
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 75b147f5c8fd..fd1801bdee66 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -916,6 +916,7 @@ static int ec_validate_ecdt(const struct dmi_system_id *id)
916/* MSI EC needs special treatment, enable it */ 916/* MSI EC needs special treatment, enable it */
917static int ec_flag_msi(const struct dmi_system_id *id) 917static int ec_flag_msi(const struct dmi_system_id *id)
918{ 918{
919 printk(KERN_DEBUG PREFIX "Detected MSI hardware, enabling workarounds.\n");
919 EC_FLAGS_MSI = 1; 920 EC_FLAGS_MSI = 1;
920 EC_FLAGS_VALIDATE_ECDT = 1; 921 EC_FLAGS_VALIDATE_ECDT = 1;
921 return 0; 922 return 0;
@@ -928,8 +929,13 @@ static struct dmi_system_id __initdata ec_dmi_table[] = {
928 DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL}, 929 DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL},
929 { 930 {
930 ec_flag_msi, "MSI hardware", { 931 ec_flag_msi, "MSI hardware", {
931 DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star"), 932 DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star")}, NULL},
932 DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star") }, NULL}, 933 {
934 ec_flag_msi, "MSI hardware", {
935 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star")}, NULL},
936 {
937 ec_flag_msi, "MSI hardware", {
938 DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL},
933 { 939 {
934 ec_validate_ecdt, "ASUS hardware", { 940 ec_validate_ecdt, "ASUS hardware", {
935 DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL}, 941 DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 074cf8682d52..cb28e0502acc 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -43,6 +43,7 @@ int acpi_power_transition(struct acpi_device *device, int state);
43extern int acpi_power_nocheck; 43extern int acpi_power_nocheck;
44 44
45int acpi_wakeup_device_init(void); 45int acpi_wakeup_device_init(void);
46void acpi_early_processor_set_pdc(void);
46 47
47/* -------------------------------------------------------------------------- 48/* --------------------------------------------------------------------------
48 Embedded Controller 49 Embedded Controller
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 41731236f9a1..9863c98c81ba 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -124,29 +124,6 @@ static const struct file_operations acpi_processor_info_fops = {
124 124
125DEFINE_PER_CPU(struct acpi_processor *, processors); 125DEFINE_PER_CPU(struct acpi_processor *, processors);
126struct acpi_processor_errata errata __read_mostly; 126struct acpi_processor_errata errata __read_mostly;
127static int set_no_mwait(const struct dmi_system_id *id)
128{
129 printk(KERN_NOTICE PREFIX "%s detected - "
130 "disabling mwait for CPU C-states\n", id->ident);
131 idle_nomwait = 1;
132 return 0;
133}
134
135static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
136 {
137 set_no_mwait, "IFL91 board", {
138 DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
139 DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
140 DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
141 DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
142 {
143 set_no_mwait, "Extensa 5220", {
144 DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
145 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
146 DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
147 DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
148 {},
149};
150 127
151/* -------------------------------------------------------------------------- 128/* --------------------------------------------------------------------------
152 Errata Handling 129 Errata Handling
@@ -277,45 +254,6 @@ static int acpi_processor_errata(struct acpi_processor *pr)
277} 254}
278 255
279/* -------------------------------------------------------------------------- 256/* --------------------------------------------------------------------------
280 Common ACPI processor functions
281 -------------------------------------------------------------------------- */
282
283/*
284 * _PDC is required for a BIOS-OS handshake for most of the newer
285 * ACPI processor features.
286 */
287static int acpi_processor_set_pdc(struct acpi_processor *pr)
288{
289 struct acpi_object_list *pdc_in = pr->pdc;
290 acpi_status status = AE_OK;
291
292
293 if (!pdc_in)
294 return status;
295 if (idle_nomwait) {
296 /*
297 * If mwait is disabled for CPU C-states, the C2C3_FFH access
298 * mode will be disabled in the parameter of _PDC object.
299 * Of course C1_FFH access mode will also be disabled.
300 */
301 union acpi_object *obj;
302 u32 *buffer = NULL;
303
304 obj = pdc_in->pointer;
305 buffer = (u32 *)(obj->buffer.pointer);
306 buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
307
308 }
309 status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL);
310
311 if (ACPI_FAILURE(status))
312 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
313 "Could not evaluate _PDC, using legacy perf. control...\n"));
314
315 return status;
316}
317
318/* --------------------------------------------------------------------------
319 FS Interface (/proc) 257 FS Interface (/proc)
320 -------------------------------------------------------------------------- */ 258 -------------------------------------------------------------------------- */
321 259
@@ -825,9 +763,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
825 } 763 }
826 764
827 /* _PDC call should be done before doing anything else (if reqd.). */ 765 /* _PDC call should be done before doing anything else (if reqd.). */
828 arch_acpi_processor_init_pdc(pr); 766 acpi_processor_set_pdc(pr->handle);
829 acpi_processor_set_pdc(pr);
830 arch_acpi_processor_cleanup_pdc(pr);
831 767
832#ifdef CONFIG_CPU_FREQ 768#ifdef CONFIG_CPU_FREQ
833 acpi_processor_ppc_has_changed(pr, 0); 769 acpi_processor_ppc_has_changed(pr, 0);
@@ -1145,11 +1081,6 @@ static int __init acpi_processor_init(void)
1145 if (!acpi_processor_dir) 1081 if (!acpi_processor_dir)
1146 return -ENOMEM; 1082 return -ENOMEM;
1147#endif 1083#endif
1148 /*
1149 * Check whether the system is DMI table. If yes, OSPM
1150 * should not use mwait for CPU-states.
1151 */
1152 dmi_check_system(processor_idle_dmi_table);
1153 result = cpuidle_register_driver(&acpi_idle_driver); 1084 result = cpuidle_register_driver(&acpi_idle_driver);
1154 if (result < 0) 1085 if (result < 0)
1155 goto out_proc; 1086 goto out_proc;
diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c
new file mode 100644
index 000000000000..30e4dc0cdf30
--- /dev/null
+++ b/drivers/acpi/processor_pdc.c
@@ -0,0 +1,165 @@
1/*
2 * Copyright (C) 2005 Intel Corporation
3 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
4 *
5 * Alex Chiang <achiang@hp.com>
6 * - Unified x86/ia64 implementations
7 * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
8 * - Added _PDC for platforms with Intel CPUs
9 */
10#include <linux/dmi.h>
11
12#include <acpi/acpi_drivers.h>
13#include <acpi/processor.h>
14
15#include "internal.h"
16
17#define PREFIX "ACPI: "
18#define _COMPONENT ACPI_PROCESSOR_COMPONENT
19ACPI_MODULE_NAME("processor_pdc");
20
21static int set_no_mwait(const struct dmi_system_id *id)
22{
23 printk(KERN_NOTICE PREFIX "%s detected - "
24 "disabling mwait for CPU C-states\n", id->ident);
25 idle_nomwait = 1;
26 return 0;
27}
28
29static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = {
30 {
31 set_no_mwait, "IFL91 board", {
32 DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
33 DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"),
34 DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"),
35 DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL},
36 {
37 set_no_mwait, "Extensa 5220", {
38 DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
39 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
40 DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
41 DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL},
42 {},
43};
44
45static void acpi_set_pdc_bits(u32 *buf)
46{
47 buf[0] = ACPI_PDC_REVISION_ID;
48 buf[1] = 1;
49
50 /* Enable coordination with firmware's _TSD info */
51 buf[2] = ACPI_PDC_SMP_T_SWCOORD;
52
53 /* Twiddle arch-specific bits needed for _PDC */
54 arch_acpi_set_pdc_bits(buf);
55}
56
57static struct acpi_object_list *acpi_processor_alloc_pdc(void)
58{
59 struct acpi_object_list *obj_list;
60 union acpi_object *obj;
61 u32 *buf;
62
63 /* allocate and initialize pdc. It will be used later. */
64 obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL);
65 if (!obj_list) {
66 printk(KERN_ERR "Memory allocation error\n");
67 return NULL;
68 }
69
70 obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
71 if (!obj) {
72 printk(KERN_ERR "Memory allocation error\n");
73 kfree(obj_list);
74 return NULL;
75 }
76
77 buf = kmalloc(12, GFP_KERNEL);
78 if (!buf) {
79 printk(KERN_ERR "Memory allocation error\n");
80 kfree(obj);
81 kfree(obj_list);
82 return NULL;
83 }
84
85 acpi_set_pdc_bits(buf);
86
87 obj->type = ACPI_TYPE_BUFFER;
88 obj->buffer.length = 12;
89 obj->buffer.pointer = (u8 *) buf;
90 obj_list->count = 1;
91 obj_list->pointer = obj;
92
93 return obj_list;
94}
95
96/*
97 * _PDC is required for a BIOS-OS handshake for most of the newer
98 * ACPI processor features.
99 */
100static int
101acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
102{
103 acpi_status status = AE_OK;
104
105 if (idle_nomwait) {
106 /*
107 * If mwait is disabled for CPU C-states, the C2C3_FFH access
108 * mode will be disabled in the parameter of _PDC object.
109 * Of course C1_FFH access mode will also be disabled.
110 */
111 union acpi_object *obj;
112 u32 *buffer = NULL;
113
114 obj = pdc_in->pointer;
115 buffer = (u32 *)(obj->buffer.pointer);
116 buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH);
117
118 }
119 status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL);
120
121 if (ACPI_FAILURE(status))
122 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
123 "Could not evaluate _PDC, using legacy perf. control.\n"));
124
125 return status;
126}
127
128void acpi_processor_set_pdc(acpi_handle handle)
129{
130 struct acpi_object_list *obj_list;
131
132 if (arch_has_acpi_pdc() == false)
133 return;
134
135 obj_list = acpi_processor_alloc_pdc();
136 if (!obj_list)
137 return;
138
139 acpi_processor_eval_pdc(handle, obj_list);
140
141 kfree(obj_list->pointer->buffer.pointer);
142 kfree(obj_list->pointer);
143 kfree(obj_list);
144}
145EXPORT_SYMBOL_GPL(acpi_processor_set_pdc);
146
147static acpi_status
148early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv)
149{
150 acpi_processor_set_pdc(handle);
151 return AE_OK;
152}
153
154void acpi_early_processor_set_pdc(void)
155{
156 /*
157 * Check whether the system is DMI table. If yes, OSPM
158 * should not use mwait for CPU-states.
159 */
160 dmi_check_system(processor_idle_dmi_table);
161
162 acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
163 ACPI_UINT32_MAX,
164 early_init_pdc, NULL, NULL, NULL);
165}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 85844d053846..56c6374a3989 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -40,7 +40,6 @@ config ATA_VERBOSE_ERROR
40config ATA_ACPI 40config ATA_ACPI
41 bool "ATA ACPI Support" 41 bool "ATA ACPI Support"
42 depends on ACPI && PCI 42 depends on ACPI && PCI
43 select ACPI_DOCK
44 default y 43 default y
45 help 44 help
46 This option adds support for ATA-related ACPI objects. 45 This option adds support for ATA-related ACPI objects.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index fc5bf9d2a3f3..ec4faffe6b05 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -464,4 +464,16 @@ config TOSHIBA_BT_RFKILL
464 464
465 If you have a modern Toshiba laptop with a Bluetooth and an 465 If you have a modern Toshiba laptop with a Bluetooth and an
466 RFKill switch (such as the Portege R500), say Y. 466 RFKill switch (such as the Portege R500), say Y.
467
468config ACPI_CMPC
469 tristate "CMPC Laptop Extras"
470 depends on X86 && ACPI
471 select INPUT
472 select BACKLIGHT_CLASS_DEVICE
473 default n
474 help
475 Support for Intel Classmate PC ACPI devices, including some
476 keys as input device, backlight device, tablet and accelerometer
477 devices.
478
467endif # X86_PLATFORM_DEVICES 479endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index b7474b6a8bf1..9cd9fa0a27e6 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -5,6 +5,7 @@
5obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 5obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
6obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o 6obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
7obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o 7obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
8obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
8obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o 9obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
9obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 10obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
10obj-$(CONFIG_DELL_WMI) += dell-wmi.o 11obj-$(CONFIG_DELL_WMI) += dell-wmi.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 454970d2d701..07d14dfdf0b4 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -96,9 +96,6 @@ struct acer_quirks {
96MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 96MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
97MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 97MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
98 98
99/* Temporary workaround until the WMI sysfs interface goes in */
100MODULE_ALIAS("dmi:*:*Acer*:*:");
101
102/* 99/*
103 * Interface capability flags 100 * Interface capability flags
104 */ 101 */
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 79b15b9d9cf0..7b2384d674d0 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -52,7 +52,7 @@
52 */ 52 */
53#undef START_IN_KERNEL_MODE 53#undef START_IN_KERNEL_MODE
54 54
55#define DRV_VER "0.5.20" 55#define DRV_VER "0.5.22"
56 56
57/* 57/*
58 * According to the Atom N270 datasheet, 58 * According to the Atom N270 datasheet,
@@ -156,19 +156,25 @@ static const struct bios_settings_t bios_tbl[] = {
156 {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} }, 156 {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} },
157 /* Acer 1410 */ 157 /* Acer 1410 */
158 {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 158 {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
159 /* special BIOS / other */ 159 {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
160 /* Acer 1810xx */
161 {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
162 {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
163 {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
164 {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
165 /* Gateway */
160 {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} }, 166 {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} },
161 {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} }, 167 {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} },
162 {"Gateway ", "LT31 ", "v1.3103 ", 0x55, 0x58, 168 {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x10, 0x0f, 0x00} },
163 {0x10, 0x0f, 0x00} }, 169 {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x10, 0x0f, 0x00} },
164 {"Gateway ", "LT31 ", "v1.3201 ", 0x55, 0x58, 170 {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x10, 0x0f, 0x00} },
165 {0x10, 0x0f, 0x00} }, 171 /* Packard Bell */
166 {"Gateway ", "LT31 ", "v1.3302 ", 0x55, 0x58,
167 {0x10, 0x0f, 0x00} },
168 {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} }, 172 {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} },
169 {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, 173 {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
170 {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} }, 174 {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} },
171 {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, 175 {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
176 {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
177 {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
172 /* pewpew-terminator */ 178 /* pewpew-terminator */
173 {"", "", "", 0, 0, {0, 0, 0} } 179 {"", "", "", 0, 0, {0, 0, 0} }
174}; 180};
@@ -486,13 +492,26 @@ static struct platform_driver acerhdf_driver = {
486 .remove = acerhdf_remove, 492 .remove = acerhdf_remove,
487}; 493};
488 494
495/* checks if str begins with start */
496static int str_starts_with(const char *str, const char *start)
497{
498 unsigned long str_len = 0, start_len = 0;
499
500 str_len = strlen(str);
501 start_len = strlen(start);
502
503 if (str_len >= start_len &&
504 !strncmp(str, start, start_len))
505 return 1;
506
507 return 0;
508}
489 509
490/* check hardware */ 510/* check hardware */
491static int acerhdf_check_hardware(void) 511static int acerhdf_check_hardware(void)
492{ 512{
493 char const *vendor, *version, *product; 513 char const *vendor, *version, *product;
494 int i; 514 const struct bios_settings_t *bt = NULL;
495 unsigned long prod_len = 0;
496 515
497 /* get BIOS data */ 516 /* get BIOS data */
498 vendor = dmi_get_system_info(DMI_SYS_VENDOR); 517 vendor = dmi_get_system_info(DMI_SYS_VENDOR);
@@ -514,20 +533,20 @@ static int acerhdf_check_hardware(void)
514 kernelmode = 0; 533 kernelmode = 0;
515 } 534 }
516 535
517 prod_len = strlen(product);
518
519 if (verbose) 536 if (verbose)
520 pr_info("BIOS info: %s %s, product: %s\n", 537 pr_info("BIOS info: %s %s, product: %s\n",
521 vendor, version, product); 538 vendor, version, product);
522 539
523 /* search BIOS version and vendor in BIOS settings table */ 540 /* search BIOS version and vendor in BIOS settings table */
524 for (i = 0; bios_tbl[i].version[0]; i++) { 541 for (bt = bios_tbl; bt->vendor[0]; bt++) {
525 if (strlen(bios_tbl[i].product) >= prod_len && 542 /*
526 !strncmp(bios_tbl[i].product, product, 543 * check if actual hardware BIOS vendor, product and version
527 strlen(bios_tbl[i].product)) && 544 * IDs start with the strings of BIOS table entry
528 !strcmp(bios_tbl[i].vendor, vendor) && 545 */
529 !strcmp(bios_tbl[i].version, version)) { 546 if (str_starts_with(vendor, bt->vendor) &&
530 bios_cfg = &bios_tbl[i]; 547 str_starts_with(product, bt->product) &&
548 str_starts_with(version, bt->version)) {
549 bios_cfg = bt;
531 break; 550 break;
532 } 551 }
533 } 552 }
@@ -640,9 +659,14 @@ static void __exit acerhdf_exit(void)
640MODULE_LICENSE("GPL"); 659MODULE_LICENSE("GPL");
641MODULE_AUTHOR("Peter Feuerer"); 660MODULE_AUTHOR("Peter Feuerer");
642MODULE_DESCRIPTION("Aspire One temperature and fan driver"); 661MODULE_DESCRIPTION("Aspire One temperature and fan driver");
643MODULE_ALIAS("dmi:*:*Acer*:*:"); 662MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:");
644MODULE_ALIAS("dmi:*:*Gateway*:*:"); 663MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:");
645MODULE_ALIAS("dmi:*:*Packard Bell*:*:"); 664MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:");
665MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:");
666MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:");
667MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:");
668MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:");
669MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:");
646 670
647module_init(acerhdf_init); 671module_init(acerhdf_init);
648module_exit(acerhdf_exit); 672module_exit(acerhdf_exit);
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index 0c9c53111a22..c1d2aeeea948 100644
--- a/drivers/platform/x86/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
@@ -35,6 +35,7 @@
35#include <linux/init.h> 35#include <linux/init.h>
36#include <linux/types.h> 36#include <linux/types.h>
37#include <linux/proc_fs.h> 37#include <linux/proc_fs.h>
38#include <linux/seq_file.h>
38#include <linux/backlight.h> 39#include <linux/backlight.h>
39#include <acpi/acpi_drivers.h> 40#include <acpi/acpi_drivers.h>
40#include <acpi/acpi_bus.h> 41#include <acpi/acpi_bus.h>
@@ -513,26 +514,12 @@ static int read_acpi_int(acpi_handle handle, const char *method, int *val)
513 return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER); 514 return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
514} 515}
515 516
516/* 517static int asus_info_proc_show(struct seq_file *m, void *v)
517 * We write our info in page, we begin at offset off and cannot write more
518 * than count bytes. We set eof to 1 if we handle those 2 values. We return the
519 * number of bytes written in page
520 */
521static int
522proc_read_info(char *page, char **start, off_t off, int count, int *eof,
523 void *data)
524{ 518{
525 int len = 0;
526 int temp; 519 int temp;
527 char buf[16]; /* enough for all info */
528 /*
529 * We use the easy way, we don't care of off and count,
530 * so we don't set eof to 1
531 */
532 520
533 len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n"); 521 seq_printf(m, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
534 len += sprintf(page + len, "Model reference : %s\n", 522 seq_printf(m, "Model reference : %s\n", hotk->methods->name);
535 hotk->methods->name);
536 /* 523 /*
537 * The SFUN method probably allows the original driver to get the list 524 * The SFUN method probably allows the original driver to get the list
538 * of features supported by a given model. For now, 0x0100 or 0x0800 525 * of features supported by a given model. For now, 0x0100 or 0x0800
@@ -540,8 +527,7 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof,
540 * The significance of others is yet to be found. 527 * The significance of others is yet to be found.
541 */ 528 */
542 if (read_acpi_int(hotk->handle, "SFUN", &temp)) 529 if (read_acpi_int(hotk->handle, "SFUN", &temp))
543 len += 530 seq_printf(m, "SFUN value : 0x%04x\n", temp);
544 sprintf(page + len, "SFUN value : 0x%04x\n", temp);
545 /* 531 /*
546 * Another value for userspace: the ASYM method returns 0x02 for 532 * Another value for userspace: the ASYM method returns 0x02 for
547 * battery low and 0x04 for battery critical, its readings tend to be 533 * battery low and 0x04 for battery critical, its readings tend to be
@@ -550,30 +536,34 @@ proc_read_info(char *page, char **start, off_t off, int count, int *eof,
550 * silently ignored. 536 * silently ignored.
551 */ 537 */
552 if (read_acpi_int(hotk->handle, "ASYM", &temp)) 538 if (read_acpi_int(hotk->handle, "ASYM", &temp))
553 len += 539 seq_printf(m, "ASYM value : 0x%04x\n", temp);
554 sprintf(page + len, "ASYM value : 0x%04x\n", temp);
555 if (asus_info) { 540 if (asus_info) {
556 snprintf(buf, 16, "%d", asus_info->length); 541 seq_printf(m, "DSDT length : %d\n", asus_info->length);
557 len += sprintf(page + len, "DSDT length : %s\n", buf); 542 seq_printf(m, "DSDT checksum : %d\n", asus_info->checksum);
558 snprintf(buf, 16, "%d", asus_info->checksum); 543 seq_printf(m, "DSDT revision : %d\n", asus_info->revision);
559 len += sprintf(page + len, "DSDT checksum : %s\n", buf); 544 seq_printf(m, "OEM id : %.*s\n", ACPI_OEM_ID_SIZE, asus_info->oem_id);
560 snprintf(buf, 16, "%d", asus_info->revision); 545 seq_printf(m, "OEM table id : %.*s\n", ACPI_OEM_TABLE_ID_SIZE, asus_info->oem_table_id);
561 len += sprintf(page + len, "DSDT revision : %s\n", buf); 546 seq_printf(m, "OEM revision : 0x%x\n", asus_info->oem_revision);
562 snprintf(buf, 7, "%s", asus_info->oem_id); 547 seq_printf(m, "ASL comp vendor id : %.*s\n", ACPI_NAME_SIZE, asus_info->asl_compiler_id);
563 len += sprintf(page + len, "OEM id : %s\n", buf); 548 seq_printf(m, "ASL comp revision : 0x%x\n", asus_info->asl_compiler_revision);
564 snprintf(buf, 9, "%s", asus_info->oem_table_id);
565 len += sprintf(page + len, "OEM table id : %s\n", buf);
566 snprintf(buf, 16, "%x", asus_info->oem_revision);
567 len += sprintf(page + len, "OEM revision : 0x%s\n", buf);
568 snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
569 len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
570 snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
571 len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf);
572 } 549 }
573 550
574 return len; 551 return 0;
552}
553
554static int asus_info_proc_open(struct inode *inode, struct file *file)
555{
556 return single_open(file, asus_info_proc_show, NULL);
575} 557}
576 558
559static const struct file_operations asus_info_proc_fops = {
560 .owner = THIS_MODULE,
561 .open = asus_info_proc_open,
562 .read = seq_read,
563 .llseek = seq_lseek,
564 .release = single_release,
565};
566
577/* 567/*
578 * /proc handlers 568 * /proc handlers
579 * We write our info in page, we begin at offset off and cannot write more 569 * We write our info in page, we begin at offset off and cannot write more
@@ -639,34 +629,48 @@ write_led(const char __user *buffer, unsigned long count,
639/* 629/*
640 * Proc handlers for MLED 630 * Proc handlers for MLED
641 */ 631 */
642static int 632static int mled_proc_show(struct seq_file *m, void *v)
643proc_read_mled(char *page, char **start, off_t off, int count, int *eof,
644 void *data)
645{ 633{
646 return sprintf(page, "%d\n", 634 seq_printf(m, "%d\n", read_led(hotk->methods->mled_status, MLED_ON));
647 read_led(hotk->methods->mled_status, MLED_ON)); 635 return 0;
648} 636}
649 637
650static int 638static int mled_proc_open(struct inode *inode, struct file *file)
651proc_write_mled(struct file *file, const char __user *buffer, 639{
652 unsigned long count, void *data) 640 return single_open(file, mled_proc_show, NULL);
641}
642
643static ssize_t mled_proc_write(struct file *file, const char __user *buffer,
644 size_t count, loff_t *pos)
653{ 645{
654 return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1); 646 return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
655} 647}
656 648
649static const struct file_operations mled_proc_fops = {
650 .owner = THIS_MODULE,
651 .open = mled_proc_open,
652 .read = seq_read,
653 .llseek = seq_lseek,
654 .release = single_release,
655 .write = mled_proc_write,
656};
657
657/* 658/*
658 * Proc handlers for LED display 659 * Proc handlers for LED display
659 */ 660 */
660static int 661static int ledd_proc_show(struct seq_file *m, void *v)
661proc_read_ledd(char *page, char **start, off_t off, int count, int *eof,
662 void *data)
663{ 662{
664 return sprintf(page, "0x%08x\n", hotk->ledd_status); 663 seq_printf(m, "0x%08x\n", hotk->ledd_status);
664 return 0;
665} 665}
666 666
667static int 667static int ledd_proc_open(struct inode *inode, struct file *file)
668proc_write_ledd(struct file *file, const char __user *buffer, 668{
669 unsigned long count, void *data) 669 return single_open(file, ledd_proc_show, NULL);
670}
671
672static ssize_t ledd_proc_write(struct file *file, const char __user *buffer,
673 size_t count, loff_t *pos)
670{ 674{
671 int rv, value; 675 int rv, value;
672 676
@@ -682,61 +686,104 @@ proc_write_ledd(struct file *file, const char __user *buffer,
682 return rv; 686 return rv;
683} 687}
684 688
689static const struct file_operations ledd_proc_fops = {
690 .owner = THIS_MODULE,
691 .open = ledd_proc_open,
692 .read = seq_read,
693 .llseek = seq_lseek,
694 .release = single_release,
695 .write = ledd_proc_write,
696};
697
685/* 698/*
686 * Proc handlers for WLED 699 * Proc handlers for WLED
687 */ 700 */
688static int 701static int wled_proc_show(struct seq_file *m, void *v)
689proc_read_wled(char *page, char **start, off_t off, int count, int *eof,
690 void *data)
691{ 702{
692 return sprintf(page, "%d\n", 703 seq_printf(m, "%d\n", read_led(hotk->methods->wled_status, WLED_ON));
693 read_led(hotk->methods->wled_status, WLED_ON)); 704 return 0;
694} 705}
695 706
696static int 707static int wled_proc_open(struct inode *inode, struct file *file)
697proc_write_wled(struct file *file, const char __user *buffer, 708{
698 unsigned long count, void *data) 709 return single_open(file, wled_proc_show, NULL);
710}
711
712static ssize_t wled_proc_write(struct file *file, const char __user *buffer,
713 size_t count, loff_t *pos)
699{ 714{
700 return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0); 715 return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
701} 716}
702 717
718static const struct file_operations wled_proc_fops = {
719 .owner = THIS_MODULE,
720 .open = wled_proc_open,
721 .read = seq_read,
722 .llseek = seq_lseek,
723 .release = single_release,
724 .write = wled_proc_write,
725};
726
703/* 727/*
704 * Proc handlers for Bluetooth 728 * Proc handlers for Bluetooth
705 */ 729 */
706static int 730static int bluetooth_proc_show(struct seq_file *m, void *v)
707proc_read_bluetooth(char *page, char **start, off_t off, int count, int *eof,
708 void *data)
709{ 731{
710 return sprintf(page, "%d\n", read_led(hotk->methods->bt_status, BT_ON)); 732 seq_printf(m, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
733 return 0;
711} 734}
712 735
713static int 736static int bluetooth_proc_open(struct inode *inode, struct file *file)
714proc_write_bluetooth(struct file *file, const char __user *buffer, 737{
715 unsigned long count, void *data) 738 return single_open(file, bluetooth_proc_show, NULL);
739}
740
741static ssize_t bluetooth_proc_write(struct file *file,
742 const char __user *buffer, size_t count, loff_t *pos)
716{ 743{
717 /* Note: mt_bt_switch controls both internal Bluetooth adapter's 744 /* Note: mt_bt_switch controls both internal Bluetooth adapter's
718 presence and its LED */ 745 presence and its LED */
719 return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0); 746 return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
720} 747}
721 748
749static const struct file_operations bluetooth_proc_fops = {
750 .owner = THIS_MODULE,
751 .open = bluetooth_proc_open,
752 .read = seq_read,
753 .llseek = seq_lseek,
754 .release = single_release,
755 .write = bluetooth_proc_write,
756};
757
722/* 758/*
723 * Proc handlers for TLED 759 * Proc handlers for TLED
724 */ 760 */
725static int 761static int tled_proc_show(struct seq_file *m, void *v)
726proc_read_tled(char *page, char **start, off_t off, int count, int *eof,
727 void *data)
728{ 762{
729 return sprintf(page, "%d\n", 763 seq_printf(m, "%d\n", read_led(hotk->methods->tled_status, TLED_ON));
730 read_led(hotk->methods->tled_status, TLED_ON)); 764 return 0;
731} 765}
732 766
733static int 767static int tled_proc_open(struct inode *inode, struct file *file)
734proc_write_tled(struct file *file, const char __user *buffer, 768{
735 unsigned long count, void *data) 769 return single_open(file, tled_proc_show, NULL);
770}
771
772static ssize_t tled_proc_write(struct file *file, const char __user *buffer,
773 size_t count, loff_t *pos)
736{ 774{
737 return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0); 775 return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
738} 776}
739 777
778static const struct file_operations tled_proc_fops = {
779 .owner = THIS_MODULE,
780 .open = tled_proc_open,
781 .read = seq_read,
782 .llseek = seq_lseek,
783 .release = single_release,
784 .write = tled_proc_write,
785};
786
740static int get_lcd_state(void) 787static int get_lcd_state(void)
741{ 788{
742 int lcd = 0; 789 int lcd = 0;
@@ -829,16 +876,19 @@ static int set_lcd_state(int value)
829 876
830} 877}
831 878
832static int 879static int lcd_proc_show(struct seq_file *m, void *v)
833proc_read_lcd(char *page, char **start, off_t off, int count, int *eof,
834 void *data)
835{ 880{
836 return sprintf(page, "%d\n", get_lcd_state()); 881 seq_printf(m, "%d\n", get_lcd_state());
882 return 0;
837} 883}
838 884
839static int 885static int lcd_proc_open(struct inode *inode, struct file *file)
840proc_write_lcd(struct file *file, const char __user *buffer, 886{
841 unsigned long count, void *data) 887 return single_open(file, lcd_proc_show, NULL);
888}
889
890static ssize_t lcd_proc_write(struct file *file, const char __user *buffer,
891 size_t count, loff_t *pos)
842{ 892{
843 int rv, value; 893 int rv, value;
844 894
@@ -848,6 +898,15 @@ proc_write_lcd(struct file *file, const char __user *buffer,
848 return rv; 898 return rv;
849} 899}
850 900
901static const struct file_operations lcd_proc_fops = {
902 .owner = THIS_MODULE,
903 .open = lcd_proc_open,
904 .read = seq_read,
905 .llseek = seq_lseek,
906 .release = single_release,
907 .write = lcd_proc_write,
908};
909
851static int read_brightness(struct backlight_device *bd) 910static int read_brightness(struct backlight_device *bd)
852{ 911{
853 int value; 912 int value;
@@ -907,16 +966,19 @@ static int set_brightness_status(struct backlight_device *bd)
907 return set_brightness(bd->props.brightness); 966 return set_brightness(bd->props.brightness);
908} 967}
909 968
910static int 969static int brn_proc_show(struct seq_file *m, void *v)
911proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
912 void *data)
913{ 970{
914 return sprintf(page, "%d\n", read_brightness(NULL)); 971 seq_printf(m, "%d\n", read_brightness(NULL));
972 return 0;
915} 973}
916 974
917static int 975static int brn_proc_open(struct inode *inode, struct file *file)
918proc_write_brn(struct file *file, const char __user *buffer, 976{
919 unsigned long count, void *data) 977 return single_open(file, brn_proc_show, NULL);
978}
979
980static ssize_t brn_proc_write(struct file *file, const char __user *buffer,
981 size_t count, loff_t *pos)
920{ 982{
921 int rv, value; 983 int rv, value;
922 984
@@ -929,6 +991,15 @@ proc_write_brn(struct file *file, const char __user *buffer,
929 return rv; 991 return rv;
930} 992}
931 993
994static const struct file_operations brn_proc_fops = {
995 .owner = THIS_MODULE,
996 .open = brn_proc_open,
997 .read = seq_read,
998 .llseek = seq_lseek,
999 .release = single_release,
1000 .write = brn_proc_write,
1001};
1002
932static void set_display(int value) 1003static void set_display(int value)
933{ 1004{
934 /* no sanity check needed for now */ 1005 /* no sanity check needed for now */
@@ -942,9 +1013,7 @@ static void set_display(int value)
942 * Now, *this* one could be more user-friendly, but so far, no-one has 1013 * Now, *this* one could be more user-friendly, but so far, no-one has
943 * complained. The significance of bits is the same as in proc_write_disp() 1014 * complained. The significance of bits is the same as in proc_write_disp()
944 */ 1015 */
945static int 1016static int disp_proc_show(struct seq_file *m, void *v)
946proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
947 void *data)
948{ 1017{
949 int value = 0; 1018 int value = 0;
950 1019
@@ -952,7 +1021,13 @@ proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
952 printk(KERN_WARNING 1021 printk(KERN_WARNING
953 "Asus ACPI: Error reading display status\n"); 1022 "Asus ACPI: Error reading display status\n");
954 value &= 0x07; /* needed for some models, shouldn't hurt others */ 1023 value &= 0x07; /* needed for some models, shouldn't hurt others */
955 return sprintf(page, "%d\n", value); 1024 seq_printf(m, "%d\n", value);
1025 return 0;
1026}
1027
1028static int disp_proc_open(struct inode *inode, struct file *file)
1029{
1030 return single_open(file, disp_proc_show, NULL);
956} 1031}
957 1032
958/* 1033/*
@@ -961,9 +1036,8 @@ proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
961 * (bitwise) of these will suffice. I never actually tested 3 displays hooked 1036 * (bitwise) of these will suffice. I never actually tested 3 displays hooked
962 * up simultaneously, so be warned. See the acpi4asus README for more info. 1037 * up simultaneously, so be warned. See the acpi4asus README for more info.
963 */ 1038 */
964static int 1039static ssize_t disp_proc_write(struct file *file, const char __user *buffer,
965proc_write_disp(struct file *file, const char __user *buffer, 1040 size_t count, loff_t *pos)
966 unsigned long count, void *data)
967{ 1041{
968 int rv, value; 1042 int rv, value;
969 1043
@@ -973,25 +1047,27 @@ proc_write_disp(struct file *file, const char __user *buffer,
973 return rv; 1047 return rv;
974} 1048}
975 1049
976typedef int (proc_readfunc) (char *page, char **start, off_t off, int count, 1050static const struct file_operations disp_proc_fops = {
977 int *eof, void *data); 1051 .owner = THIS_MODULE,
978typedef int (proc_writefunc) (struct file *file, const char __user *buffer, 1052 .open = disp_proc_open,
979 unsigned long count, void *data); 1053 .read = seq_read,
1054 .llseek = seq_lseek,
1055 .release = single_release,
1056 .write = disp_proc_write,
1057};
980 1058
981static int 1059static int
982asus_proc_add(char *name, proc_writefunc *writefunc, 1060asus_proc_add(char *name, const struct file_operations *proc_fops, mode_t mode,
983 proc_readfunc *readfunc, mode_t mode,
984 struct acpi_device *device) 1061 struct acpi_device *device)
985{ 1062{
986 struct proc_dir_entry *proc = 1063 struct proc_dir_entry *proc;
987 create_proc_entry(name, mode, acpi_device_dir(device)); 1064
1065 proc = proc_create_data(name, mode, acpi_device_dir(device),
1066 proc_fops, acpi_driver_data(device));
988 if (!proc) { 1067 if (!proc) {
989 printk(KERN_WARNING " Unable to create %s fs entry\n", name); 1068 printk(KERN_WARNING " Unable to create %s fs entry\n", name);
990 return -1; 1069 return -1;
991 } 1070 }
992 proc->write_proc = writefunc;
993 proc->read_proc = readfunc;
994 proc->data = acpi_driver_data(device);
995 proc->uid = asus_uid; 1071 proc->uid = asus_uid;
996 proc->gid = asus_gid; 1072 proc->gid = asus_gid;
997 return 0; 1073 return 0;
@@ -1020,10 +1096,9 @@ static int asus_hotk_add_fs(struct acpi_device *device)
1020 if (!acpi_device_dir(device)) 1096 if (!acpi_device_dir(device))
1021 return -ENODEV; 1097 return -ENODEV;
1022 1098
1023 proc = create_proc_entry(PROC_INFO, mode, acpi_device_dir(device)); 1099 proc = proc_create(PROC_INFO, mode, acpi_device_dir(device),
1100 &asus_info_proc_fops);
1024 if (proc) { 1101 if (proc) {
1025 proc->read_proc = proc_read_info;
1026 proc->data = acpi_driver_data(device);
1027 proc->uid = asus_uid; 1102 proc->uid = asus_uid;
1028 proc->gid = asus_gid; 1103 proc->gid = asus_gid;
1029 } else { 1104 } else {
@@ -1032,28 +1107,23 @@ static int asus_hotk_add_fs(struct acpi_device *device)
1032 } 1107 }
1033 1108
1034 if (hotk->methods->mt_wled) { 1109 if (hotk->methods->mt_wled) {
1035 asus_proc_add(PROC_WLED, &proc_write_wled, &proc_read_wled, 1110 asus_proc_add(PROC_WLED, &wled_proc_fops, mode, device);
1036 mode, device);
1037 } 1111 }
1038 1112
1039 if (hotk->methods->mt_ledd) { 1113 if (hotk->methods->mt_ledd) {
1040 asus_proc_add(PROC_LEDD, &proc_write_ledd, &proc_read_ledd, 1114 asus_proc_add(PROC_LEDD, &ledd_proc_fops, mode, device);
1041 mode, device);
1042 } 1115 }
1043 1116
1044 if (hotk->methods->mt_mled) { 1117 if (hotk->methods->mt_mled) {
1045 asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled, 1118 asus_proc_add(PROC_MLED, &mled_proc_fops, mode, device);
1046 mode, device);
1047 } 1119 }
1048 1120
1049 if (hotk->methods->mt_tled) { 1121 if (hotk->methods->mt_tled) {
1050 asus_proc_add(PROC_TLED, &proc_write_tled, &proc_read_tled, 1122 asus_proc_add(PROC_TLED, &tled_proc_fops, mode, device);
1051 mode, device);
1052 } 1123 }
1053 1124
1054 if (hotk->methods->mt_bt_switch) { 1125 if (hotk->methods->mt_bt_switch) {
1055 asus_proc_add(PROC_BT, &proc_write_bluetooth, 1126 asus_proc_add(PROC_BT, &bluetooth_proc_fops, mode, device);
1056 &proc_read_bluetooth, mode, device);
1057 } 1127 }
1058 1128
1059 /* 1129 /*
@@ -1061,19 +1131,16 @@ static int asus_hotk_add_fs(struct acpi_device *device)
1061 * accessible from the keyboard 1131 * accessible from the keyboard
1062 */ 1132 */
1063 if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) { 1133 if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
1064 asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode, 1134 asus_proc_add(PROC_LCD, &lcd_proc_fops, mode, device);
1065 device);
1066 } 1135 }
1067 1136
1068 if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || 1137 if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
1069 (hotk->methods->brightness_get && hotk->methods->brightness_set)) { 1138 (hotk->methods->brightness_get && hotk->methods->brightness_set)) {
1070 asus_proc_add(PROC_BRN, &proc_write_brn, &proc_read_brn, mode, 1139 asus_proc_add(PROC_BRN, &brn_proc_fops, mode, device);
1071 device);
1072 } 1140 }
1073 1141
1074 if (hotk->methods->display_set) { 1142 if (hotk->methods->display_set) {
1075 asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp, 1143 asus_proc_add(PROC_DISP, &disp_proc_fops, mode, device);
1076 mode, device);
1077 } 1144 }
1078 1145
1079 return 0; 1146 return 0;
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
new file mode 100644
index 000000000000..ed90082cdf1d
--- /dev/null
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -0,0 +1,609 @@
1/*
2 * Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19
20#include <linux/init.h>
21#include <linux/module.h>
22#include <linux/workqueue.h>
23#include <acpi/acpi_drivers.h>
24#include <linux/backlight.h>
25#include <linux/input.h>
26
27MODULE_LICENSE("GPL");
28
29
30struct cmpc_accel {
31 int sensitivity;
32};
33
34#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
35
36
37/*
38 * Generic input device code.
39 */
40
41typedef void (*input_device_init)(struct input_dev *dev);
42
43static int cmpc_add_acpi_notify_device(struct acpi_device *acpi, char *name,
44 input_device_init idev_init)
45{
46 struct input_dev *inputdev;
47 int error;
48
49 inputdev = input_allocate_device();
50 if (!inputdev)
51 return -ENOMEM;
52 inputdev->name = name;
53 inputdev->dev.parent = &acpi->dev;
54 idev_init(inputdev);
55 error = input_register_device(inputdev);
56 if (error) {
57 input_free_device(inputdev);
58 return error;
59 }
60 dev_set_drvdata(&acpi->dev, inputdev);
61 return 0;
62}
63
64static int cmpc_remove_acpi_notify_device(struct acpi_device *acpi)
65{
66 struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
67 input_unregister_device(inputdev);
68 return 0;
69}
70
71/*
72 * Accelerometer code.
73 */
74static acpi_status cmpc_start_accel(acpi_handle handle)
75{
76 union acpi_object param[2];
77 struct acpi_object_list input;
78 acpi_status status;
79
80 param[0].type = ACPI_TYPE_INTEGER;
81 param[0].integer.value = 0x3;
82 param[1].type = ACPI_TYPE_INTEGER;
83 input.count = 2;
84 input.pointer = param;
85 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
86 return status;
87}
88
89static acpi_status cmpc_stop_accel(acpi_handle handle)
90{
91 union acpi_object param[2];
92 struct acpi_object_list input;
93 acpi_status status;
94
95 param[0].type = ACPI_TYPE_INTEGER;
96 param[0].integer.value = 0x4;
97 param[1].type = ACPI_TYPE_INTEGER;
98 input.count = 2;
99 input.pointer = param;
100 status = acpi_evaluate_object(handle, "ACMD", &input, NULL);
101 return status;
102}
103
104static acpi_status cmpc_accel_set_sensitivity(acpi_handle handle, int val)
105{
106 union acpi_object param[2];
107 struct acpi_object_list input;
108
109 param[0].type = ACPI_TYPE_INTEGER;
110 param[0].integer.value = 0x02;
111 param[1].type = ACPI_TYPE_INTEGER;
112 param[1].integer.value = val;
113 input.count = 2;
114 input.pointer = param;
115 return acpi_evaluate_object(handle, "ACMD", &input, NULL);
116}
117
118static acpi_status cmpc_get_accel(acpi_handle handle,
119 unsigned char *x,
120 unsigned char *y,
121 unsigned char *z)
122{
123 union acpi_object param[2];
124 struct acpi_object_list input;
125 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, 0 };
126 unsigned char *locs;
127 acpi_status status;
128
129 param[0].type = ACPI_TYPE_INTEGER;
130 param[0].integer.value = 0x01;
131 param[1].type = ACPI_TYPE_INTEGER;
132 input.count = 2;
133 input.pointer = param;
134 status = acpi_evaluate_object(handle, "ACMD", &input, &output);
135 if (ACPI_SUCCESS(status)) {
136 union acpi_object *obj;
137 obj = output.pointer;
138 locs = obj->buffer.pointer;
139 *x = locs[0];
140 *y = locs[1];
141 *z = locs[2];
142 kfree(output.pointer);
143 }
144 return status;
145}
146
147static void cmpc_accel_handler(struct acpi_device *dev, u32 event)
148{
149 if (event == 0x81) {
150 unsigned char x, y, z;
151 acpi_status status;
152
153 status = cmpc_get_accel(dev->handle, &x, &y, &z);
154 if (ACPI_SUCCESS(status)) {
155 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
156
157 input_report_abs(inputdev, ABS_X, x);
158 input_report_abs(inputdev, ABS_Y, y);
159 input_report_abs(inputdev, ABS_Z, z);
160 input_sync(inputdev);
161 }
162 }
163}
164
165static ssize_t cmpc_accel_sensitivity_show(struct device *dev,
166 struct device_attribute *attr,
167 char *buf)
168{
169 struct acpi_device *acpi;
170 struct input_dev *inputdev;
171 struct cmpc_accel *accel;
172
173 acpi = to_acpi_device(dev);
174 inputdev = dev_get_drvdata(&acpi->dev);
175 accel = dev_get_drvdata(&inputdev->dev);
176
177 return sprintf(buf, "%d\n", accel->sensitivity);
178}
179
180static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
181 struct device_attribute *attr,
182 const char *buf, size_t count)
183{
184 struct acpi_device *acpi;
185 struct input_dev *inputdev;
186 struct cmpc_accel *accel;
187 unsigned long sensitivity;
188 int r;
189
190 acpi = to_acpi_device(dev);
191 inputdev = dev_get_drvdata(&acpi->dev);
192 accel = dev_get_drvdata(&inputdev->dev);
193
194 r = strict_strtoul(buf, 0, &sensitivity);
195 if (r)
196 return r;
197
198 accel->sensitivity = sensitivity;
199 cmpc_accel_set_sensitivity(acpi->handle, sensitivity);
200
201 return strnlen(buf, count);
202}
203
204struct device_attribute cmpc_accel_sensitivity_attr = {
205 .attr = { .name = "sensitivity", .mode = 0660 },
206 .show = cmpc_accel_sensitivity_show,
207 .store = cmpc_accel_sensitivity_store
208};
209
210static int cmpc_accel_open(struct input_dev *input)
211{
212 struct acpi_device *acpi;
213
214 acpi = to_acpi_device(input->dev.parent);
215 if (ACPI_SUCCESS(cmpc_start_accel(acpi->handle)))
216 return 0;
217 return -EIO;
218}
219
220static void cmpc_accel_close(struct input_dev *input)
221{
222 struct acpi_device *acpi;
223
224 acpi = to_acpi_device(input->dev.parent);
225 cmpc_stop_accel(acpi->handle);
226}
227
228static void cmpc_accel_idev_init(struct input_dev *inputdev)
229{
230 set_bit(EV_ABS, inputdev->evbit);
231 input_set_abs_params(inputdev, ABS_X, 0, 255, 8, 0);
232 input_set_abs_params(inputdev, ABS_Y, 0, 255, 8, 0);
233 input_set_abs_params(inputdev, ABS_Z, 0, 255, 8, 0);
234 inputdev->open = cmpc_accel_open;
235 inputdev->close = cmpc_accel_close;
236}
237
238static int cmpc_accel_add(struct acpi_device *acpi)
239{
240 int error;
241 struct input_dev *inputdev;
242 struct cmpc_accel *accel;
243
244 accel = kmalloc(sizeof(*accel), GFP_KERNEL);
245 if (!accel)
246 return -ENOMEM;
247
248 accel->sensitivity = CMPC_ACCEL_SENSITIVITY_DEFAULT;
249 cmpc_accel_set_sensitivity(acpi->handle, accel->sensitivity);
250
251 error = device_create_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
252 if (error)
253 goto failed_file;
254
255 error = cmpc_add_acpi_notify_device(acpi, "cmpc_accel",
256 cmpc_accel_idev_init);
257 if (error)
258 goto failed_input;
259
260 inputdev = dev_get_drvdata(&acpi->dev);
261 dev_set_drvdata(&inputdev->dev, accel);
262
263 return 0;
264
265failed_input:
266 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
267failed_file:
268 kfree(accel);
269 return error;
270}
271
272static int cmpc_accel_remove(struct acpi_device *acpi, int type)
273{
274 struct input_dev *inputdev;
275 struct cmpc_accel *accel;
276
277 inputdev = dev_get_drvdata(&acpi->dev);
278 accel = dev_get_drvdata(&inputdev->dev);
279
280 device_remove_file(&acpi->dev, &cmpc_accel_sensitivity_attr);
281 return cmpc_remove_acpi_notify_device(acpi);
282}
283
284static const struct acpi_device_id cmpc_accel_device_ids[] = {
285 {"ACCE0000", 0},
286 {"", 0}
287};
288MODULE_DEVICE_TABLE(acpi, cmpc_accel_device_ids);
289
290static struct acpi_driver cmpc_accel_acpi_driver = {
291 .owner = THIS_MODULE,
292 .name = "cmpc_accel",
293 .class = "cmpc_accel",
294 .ids = cmpc_accel_device_ids,
295 .ops = {
296 .add = cmpc_accel_add,
297 .remove = cmpc_accel_remove,
298 .notify = cmpc_accel_handler,
299 }
300};
301
302
303/*
304 * Tablet mode code.
305 */
306static acpi_status cmpc_get_tablet(acpi_handle handle,
307 unsigned long long *value)
308{
309 union acpi_object param;
310 struct acpi_object_list input;
311 unsigned long long output;
312 acpi_status status;
313
314 param.type = ACPI_TYPE_INTEGER;
315 param.integer.value = 0x01;
316 input.count = 1;
317 input.pointer = &param;
318 status = acpi_evaluate_integer(handle, "TCMD", &input, &output);
319 if (ACPI_SUCCESS(status))
320 *value = output;
321 return status;
322}
323
324static void cmpc_tablet_handler(struct acpi_device *dev, u32 event)
325{
326 unsigned long long val = 0;
327 struct input_dev *inputdev = dev_get_drvdata(&dev->dev);
328
329 if (event == 0x81) {
330 if (ACPI_SUCCESS(cmpc_get_tablet(dev->handle, &val)))
331 input_report_switch(inputdev, SW_TABLET_MODE, !val);
332 }
333}
334
335static void cmpc_tablet_idev_init(struct input_dev *inputdev)
336{
337 unsigned long long val = 0;
338 struct acpi_device *acpi;
339
340 set_bit(EV_SW, inputdev->evbit);
341 set_bit(SW_TABLET_MODE, inputdev->swbit);
342
343 acpi = to_acpi_device(inputdev->dev.parent);
344 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
345 input_report_switch(inputdev, SW_TABLET_MODE, !val);
346}
347
348static int cmpc_tablet_add(struct acpi_device *acpi)
349{
350 return cmpc_add_acpi_notify_device(acpi, "cmpc_tablet",
351 cmpc_tablet_idev_init);
352}
353
354static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
355{
356 return cmpc_remove_acpi_notify_device(acpi);
357}
358
359static int cmpc_tablet_resume(struct acpi_device *acpi)
360{
361 struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
362 unsigned long long val = 0;
363 if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
364 input_report_switch(inputdev, SW_TABLET_MODE, !val);
365 return 0;
366}
367
368static const struct acpi_device_id cmpc_tablet_device_ids[] = {
369 {"TBLT0000", 0},
370 {"", 0}
371};
372MODULE_DEVICE_TABLE(acpi, cmpc_tablet_device_ids);
373
374static struct acpi_driver cmpc_tablet_acpi_driver = {
375 .owner = THIS_MODULE,
376 .name = "cmpc_tablet",
377 .class = "cmpc_tablet",
378 .ids = cmpc_tablet_device_ids,
379 .ops = {
380 .add = cmpc_tablet_add,
381 .remove = cmpc_tablet_remove,
382 .resume = cmpc_tablet_resume,
383 .notify = cmpc_tablet_handler,
384 }
385};
386
387
388/*
389 * Backlight code.
390 */
391
392static acpi_status cmpc_get_brightness(acpi_handle handle,
393 unsigned long long *value)
394{
395 union acpi_object param;
396 struct acpi_object_list input;
397 unsigned long long output;
398 acpi_status status;
399
400 param.type = ACPI_TYPE_INTEGER;
401 param.integer.value = 0xC0;
402 input.count = 1;
403 input.pointer = &param;
404 status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
405 if (ACPI_SUCCESS(status))
406 *value = output;
407 return status;
408}
409
410static acpi_status cmpc_set_brightness(acpi_handle handle,
411 unsigned long long value)
412{
413 union acpi_object param[2];
414 struct acpi_object_list input;
415 acpi_status status;
416 unsigned long long output;
417
418 param[0].type = ACPI_TYPE_INTEGER;
419 param[0].integer.value = 0xC0;
420 param[1].type = ACPI_TYPE_INTEGER;
421 param[1].integer.value = value;
422 input.count = 2;
423 input.pointer = param;
424 status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
425 return status;
426}
427
428static int cmpc_bl_get_brightness(struct backlight_device *bd)
429{
430 acpi_status status;
431 acpi_handle handle;
432 unsigned long long brightness;
433
434 handle = bl_get_data(bd);
435 status = cmpc_get_brightness(handle, &brightness);
436 if (ACPI_SUCCESS(status))
437 return brightness;
438 else
439 return -1;
440}
441
442static int cmpc_bl_update_status(struct backlight_device *bd)
443{
444 acpi_status status;
445 acpi_handle handle;
446
447 handle = bl_get_data(bd);
448 status = cmpc_set_brightness(handle, bd->props.brightness);
449 if (ACPI_SUCCESS(status))
450 return 0;
451 else
452 return -1;
453}
454
455static struct backlight_ops cmpc_bl_ops = {
456 .get_brightness = cmpc_bl_get_brightness,
457 .update_status = cmpc_bl_update_status
458};
459
460static int cmpc_bl_add(struct acpi_device *acpi)
461{
462 struct backlight_device *bd;
463
464 bd = backlight_device_register("cmpc_bl", &acpi->dev,
465 acpi->handle, &cmpc_bl_ops);
466 bd->props.max_brightness = 7;
467 dev_set_drvdata(&acpi->dev, bd);
468 return 0;
469}
470
471static int cmpc_bl_remove(struct acpi_device *acpi, int type)
472{
473 struct backlight_device *bd;
474
475 bd = dev_get_drvdata(&acpi->dev);
476 backlight_device_unregister(bd);
477 return 0;
478}
479
480static const struct acpi_device_id cmpc_device_ids[] = {
481 {"IPML200", 0},
482 {"", 0}
483};
484MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
485
486static struct acpi_driver cmpc_bl_acpi_driver = {
487 .owner = THIS_MODULE,
488 .name = "cmpc",
489 .class = "cmpc",
490 .ids = cmpc_device_ids,
491 .ops = {
492 .add = cmpc_bl_add,
493 .remove = cmpc_bl_remove
494 }
495};
496
497
498/*
499 * Extra keys code.
500 */
501static int cmpc_keys_codes[] = {
502 KEY_UNKNOWN,
503 KEY_WLAN,
504 KEY_SWITCHVIDEOMODE,
505 KEY_BRIGHTNESSDOWN,
506 KEY_BRIGHTNESSUP,
507 KEY_VENDOR,
508 KEY_MAX
509};
510
511static void cmpc_keys_handler(struct acpi_device *dev, u32 event)
512{
513 struct input_dev *inputdev;
514 int code = KEY_MAX;
515
516 if ((event & 0x0F) < ARRAY_SIZE(cmpc_keys_codes))
517 code = cmpc_keys_codes[event & 0x0F];
518 inputdev = dev_get_drvdata(&dev->dev);;
519 input_report_key(inputdev, code, !(event & 0x10));
520}
521
522static void cmpc_keys_idev_init(struct input_dev *inputdev)
523{
524 int i;
525
526 set_bit(EV_KEY, inputdev->evbit);
527 for (i = 0; cmpc_keys_codes[i] != KEY_MAX; i++)
528 set_bit(cmpc_keys_codes[i], inputdev->keybit);
529}
530
531static int cmpc_keys_add(struct acpi_device *acpi)
532{
533 return cmpc_add_acpi_notify_device(acpi, "cmpc_keys",
534 cmpc_keys_idev_init);
535}
536
537static int cmpc_keys_remove(struct acpi_device *acpi, int type)
538{
539 return cmpc_remove_acpi_notify_device(acpi);
540}
541
542static const struct acpi_device_id cmpc_keys_device_ids[] = {
543 {"FnBT0000", 0},
544 {"", 0}
545};
546MODULE_DEVICE_TABLE(acpi, cmpc_keys_device_ids);
547
548static struct acpi_driver cmpc_keys_acpi_driver = {
549 .owner = THIS_MODULE,
550 .name = "cmpc_keys",
551 .class = "cmpc_keys",
552 .ids = cmpc_keys_device_ids,
553 .ops = {
554 .add = cmpc_keys_add,
555 .remove = cmpc_keys_remove,
556 .notify = cmpc_keys_handler,
557 }
558};
559
560
561/*
562 * General init/exit code.
563 */
564
565static int cmpc_init(void)
566{
567 int r;
568
569 r = acpi_bus_register_driver(&cmpc_keys_acpi_driver);
570 if (r)
571 goto failed_keys;
572
573 r = acpi_bus_register_driver(&cmpc_bl_acpi_driver);
574 if (r)
575 goto failed_bl;
576
577 r = acpi_bus_register_driver(&cmpc_tablet_acpi_driver);
578 if (r)
579 goto failed_tablet;
580
581 r = acpi_bus_register_driver(&cmpc_accel_acpi_driver);
582 if (r)
583 goto failed_accel;
584
585 return r;
586
587failed_accel:
588 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
589
590failed_tablet:
591 acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
592
593failed_bl:
594 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
595
596failed_keys:
597 return r;
598}
599
600static void cmpc_exit(void)
601{
602 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
603 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
604 acpi_bus_unregister_driver(&cmpc_bl_acpi_driver);
605 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
606}
607
608module_init(cmpc_init);
609module_exit(cmpc_exit);
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 67f3fe71c509..916ccb2b316c 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -238,6 +238,7 @@ static void dell_wmi_notify(u32 value, void *context)
238 input_sync(dell_wmi_input_dev); 238 input_sync(dell_wmi_input_dev);
239 } 239 }
240 } 240 }
241 kfree(obj);
241} 242}
242 243
243 244
@@ -324,37 +325,34 @@ static int __init dell_wmi_init(void)
324 int err; 325 int err;
325 326
326 if (wmi_has_guid(DELL_EVENT_GUID)) { 327 if (wmi_has_guid(DELL_EVENT_GUID)) {
328 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
329 return -ENODEV;
330 }
327 331
328 dmi_walk(find_hk_type, NULL); 332 dmi_walk(find_hk_type, NULL);
329 333 acpi_video = acpi_video_backlight_support();
330 err = dell_wmi_input_setup();
331
332 if (err)
333 return err;
334
335 err = wmi_install_notify_handler(DELL_EVENT_GUID,
336 dell_wmi_notify, NULL);
337 if (err) {
338 input_unregister_device(dell_wmi_input_dev);
339 printk(KERN_ERR "dell-wmi: Unable to register"
340 " notify handler - %d\n", err);
341 return err;
342 }
343 334
344 acpi_video = acpi_video_backlight_support(); 335 err = dell_wmi_input_setup();
336 if (err)
337 return err;
345 338
346 } else 339 err = wmi_install_notify_handler(DELL_EVENT_GUID,
347 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); 340 dell_wmi_notify, NULL);
341 if (err) {
342 input_unregister_device(dell_wmi_input_dev);
343 printk(KERN_ERR
344 "dell-wmi: Unable to register notify handler - %d\n",
345 err);
346 return err;
347 }
348 348
349 return 0; 349 return 0;
350} 350}
351 351
352static void __exit dell_wmi_exit(void) 352static void __exit dell_wmi_exit(void)
353{ 353{
354 if (wmi_has_guid(DELL_EVENT_GUID)) { 354 wmi_remove_notify_handler(DELL_EVENT_GUID);
355 wmi_remove_notify_handler(DELL_EVENT_GUID); 355 input_unregister_device(dell_wmi_input_dev);
356 input_unregister_device(dell_wmi_input_dev);
357 }
358} 356}
359 357
360module_init(dell_wmi_init); 358module_init(dell_wmi_init);
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index b66029bd75d0..5f3320d468f6 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -376,8 +376,8 @@ static int get_lcd_level(void)
376 376
377 status = 377 status =
378 acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); 378 acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state);
379 if (status < 0) 379 if (ACPI_FAILURE(status))
380 return status; 380 return 0;
381 381
382 fujitsu->brightness_level = state & 0x0fffffff; 382 fujitsu->brightness_level = state & 0x0fffffff;
383 383
@@ -398,8 +398,8 @@ static int get_max_brightness(void)
398 398
399 status = 399 status =
400 acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state); 400 acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state);
401 if (status < 0) 401 if (ACPI_FAILURE(status))
402 return status; 402 return -1;
403 403
404 fujitsu->max_brightness = state; 404 fujitsu->max_brightness = state;
405 405
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 63c3e658a884..8781d8fa7a57 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -134,10 +134,15 @@ static int hp_wmi_perform_query(int query, int write, int value)
134 134
135 obj = output.pointer; 135 obj = output.pointer;
136 136
137 if (!obj || obj->type != ACPI_TYPE_BUFFER) 137 if (!obj)
138 return -EINVAL; 138 return -EINVAL;
139 else if (obj->type != ACPI_TYPE_BUFFER) {
140 kfree(obj);
141 return -EINVAL;
142 }
139 143
140 bios_return = *((struct bios_return *)obj->buffer.pointer); 144 bios_return = *((struct bios_return *)obj->buffer.pointer);
145 kfree(obj);
141 if (bios_return.return_code > 0) 146 if (bios_return.return_code > 0)
142 return bios_return.return_code * -1; 147 return bios_return.return_code * -1;
143 else 148 else
@@ -340,10 +345,12 @@ static void hp_wmi_notify(u32 value, void *context)
340 345
341 if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) { 346 if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
342 printk(KERN_INFO "HP WMI: Unknown response received\n"); 347 printk(KERN_INFO "HP WMI: Unknown response received\n");
348 kfree(obj);
343 return; 349 return;
344 } 350 }
345 351
346 eventcode = *((u8 *) obj->buffer.pointer); 352 eventcode = *((u8 *) obj->buffer.pointer);
353 kfree(obj);
347 if (eventcode == 0x4) 354 if (eventcode == 0x4)
348 eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 355 eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
349 0); 356 0);
@@ -381,6 +388,8 @@ static void hp_wmi_notify(u32 value, void *context)
381 } else 388 } else
382 printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", 389 printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
383 eventcode); 390 eventcode);
391
392 kfree(obj);
384} 393}
385 394
386static int __init hp_wmi_input_setup(void) 395static int __init hp_wmi_input_setup(void)
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index 0c8fe145c4af..7f77f908bb01 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -34,16 +34,6 @@ MODULE_LICENSE("GPL");
34MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45"); 34MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45");
35MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"); 35MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2");
36 36
37/* Temporary workaround until the WMI sysfs interface goes in
38 { "svn", DMI_SYS_VENDOR },
39 { "pn", DMI_PRODUCT_NAME },
40 { "pvr", DMI_PRODUCT_VERSION },
41 { "rvn", DMI_BOARD_VENDOR },
42 { "rn", DMI_BOARD_NAME },
43*/
44
45MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-6638:*");
46
47#define DRV_NAME "msi-wmi" 37#define DRV_NAME "msi-wmi"
48#define DRV_PFX DRV_NAME ": " 38#define DRV_PFX DRV_NAME ": "
49 39
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 2896ca4cd9ab..5af53340da6f 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -131,6 +131,7 @@ enum sony_nc_rfkill {
131 N_SONY_RFKILL, 131 N_SONY_RFKILL,
132}; 132};
133 133
134static int sony_rfkill_handle;
134static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; 135static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
135static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; 136static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
136static void sony_nc_rfkill_update(void); 137static void sony_nc_rfkill_update(void);
@@ -232,6 +233,7 @@ static int sony_laptop_input_index[] = {
232 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */ 233 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */
233 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */ 234 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */
234 -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */ 235 -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
236 58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */
235}; 237};
236 238
237static int sony_laptop_input_keycode_map[] = { 239static int sony_laptop_input_keycode_map[] = {
@@ -293,6 +295,7 @@ static int sony_laptop_input_keycode_map[] = {
293 KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */ 295 KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */
294 KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */ 296 KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */
295 KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */ 297 KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */
298 KEY_MEDIA, /* 58 SONYPI_EVENT_MEDIA_PRESSED */
296}; 299};
297 300
298/* release buttons after a short delay if pressed */ 301/* release buttons after a short delay if pressed */
@@ -890,6 +893,8 @@ static struct sony_nc_event sony_100_events[] = {
890 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, 893 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
891 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED }, 894 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
892 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED }, 895 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED },
896 { 0xa1, SONYPI_EVENT_MEDIA_PRESSED },
897 { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED },
893 { 0, 0 }, 898 { 0, 0 },
894}; 899};
895 900
@@ -961,7 +966,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
961 else 966 else
962 sony_laptop_report_input_event(ev); 967 sony_laptop_report_input_event(ev);
963 } 968 }
964 } else if (sony_find_snc_handle(0x124) == ev) { 969 } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) {
965 sony_nc_rfkill_update(); 970 sony_nc_rfkill_update();
966 return; 971 return;
967 } 972 }
@@ -1067,7 +1072,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked)
1067 if (!blocked) 1072 if (!blocked)
1068 argument |= 0xff0000; 1073 argument |= 0xff0000;
1069 1074
1070 return sony_call_snc_handle(0x124, argument, &result); 1075 return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1071} 1076}
1072 1077
1073static const struct rfkill_ops sony_rfkill_ops = { 1078static const struct rfkill_ops sony_rfkill_ops = {
@@ -1110,7 +1115,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
1110 if (!rfk) 1115 if (!rfk)
1111 return -ENOMEM; 1116 return -ENOMEM;
1112 1117
1113 sony_call_snc_handle(0x124, 0x200, &result); 1118 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1114 hwblock = !(result & 0x1); 1119 hwblock = !(result & 0x1);
1115 rfkill_set_hw_state(rfk, hwblock); 1120 rfkill_set_hw_state(rfk, hwblock);
1116 1121
@@ -1129,7 +1134,7 @@ static void sony_nc_rfkill_update()
1129 int result; 1134 int result;
1130 bool hwblock; 1135 bool hwblock;
1131 1136
1132 sony_call_snc_handle(0x124, 0x200, &result); 1137 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1133 hwblock = !(result & 0x1); 1138 hwblock = !(result & 0x1);
1134 1139
1135 for (i = 0; i < N_SONY_RFKILL; i++) { 1140 for (i = 0; i < N_SONY_RFKILL; i++) {
@@ -1145,36 +1150,79 @@ static void sony_nc_rfkill_update()
1145 continue; 1150 continue;
1146 } 1151 }
1147 1152
1148 sony_call_snc_handle(0x124, argument, &result); 1153 sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1149 rfkill_set_states(sony_rfkill_devices[i], 1154 rfkill_set_states(sony_rfkill_devices[i],
1150 !(result & 0xf), false); 1155 !(result & 0xf), false);
1151 } 1156 }
1152} 1157}
1153 1158
1154static int sony_nc_rfkill_setup(struct acpi_device *device) 1159static void sony_nc_rfkill_setup(struct acpi_device *device)
1155{ 1160{
1156 int result, ret; 1161 int offset;
1162 u8 dev_code, i;
1163 acpi_status status;
1164 struct acpi_object_list params;
1165 union acpi_object in_obj;
1166 union acpi_object *device_enum;
1167 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1157 1168
1158 if (sony_find_snc_handle(0x124) == -1) 1169 offset = sony_find_snc_handle(0x124);
1159 return -1; 1170 if (offset == -1) {
1171 offset = sony_find_snc_handle(0x135);
1172 if (offset == -1)
1173 return;
1174 else
1175 sony_rfkill_handle = 0x135;
1176 } else
1177 sony_rfkill_handle = 0x124;
1178 dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
1160 1179
1161 ret = sony_call_snc_handle(0x124, 0xb00, &result); 1180 /* need to read the whole buffer returned by the acpi call to SN06
1162 if (ret) { 1181 * here otherwise we may miss some features
1163 printk(KERN_INFO DRV_PFX 1182 */
1164 "Unable to enumerate rfkill devices: %x\n", ret); 1183 params.count = 1;
1165 return ret; 1184 params.pointer = &in_obj;
1185 in_obj.type = ACPI_TYPE_INTEGER;
1186 in_obj.integer.value = offset;
1187 status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
1188 &buffer);
1189 if (ACPI_FAILURE(status)) {
1190 dprintk("Radio device enumeration failed\n");
1191 return;
1192 }
1193
1194 device_enum = (union acpi_object *) buffer.pointer;
1195 if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) {
1196 printk(KERN_ERR "Invalid SN06 return object 0x%.2x\n",
1197 device_enum->type);
1198 goto out_no_enum;
1166 } 1199 }
1167 1200
1168 if (result & 0x1) 1201 /* the buffer is filled with magic numbers describing the devices
1169 sony_nc_setup_rfkill(device, SONY_WIFI); 1202 * available, 0xff terminates the enumeration
1170 if (result & 0x2) 1203 */
1171 sony_nc_setup_rfkill(device, SONY_BLUETOOTH); 1204 while ((dev_code = *(device_enum->buffer.pointer + i)) != 0xff &&
1172 if (result & 0x1c) 1205 i < device_enum->buffer.length) {
1173 sony_nc_setup_rfkill(device, SONY_WWAN); 1206 i++;
1174 if (result & 0x20) 1207 dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
1175 sony_nc_setup_rfkill(device, SONY_WIMAX);
1176 1208
1177 return 0; 1209 if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
1210 sony_nc_setup_rfkill(device, SONY_WIFI);
1211
1212 if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
1213 sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
1214
1215 if ((0xf0 & dev_code) == 0x20 &&
1216 !sony_rfkill_devices[SONY_WWAN])
1217 sony_nc_setup_rfkill(device, SONY_WWAN);
1218
1219 if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
1220 sony_nc_setup_rfkill(device, SONY_WIMAX);
1221 }
1222
1223out_no_enum:
1224 kfree(buffer.pointer);
1225 return;
1178} 1226}
1179 1227
1180static int sony_nc_add(struct acpi_device *device) 1228static int sony_nc_add(struct acpi_device *device)
diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c
index 44166003d4ef..dd33b51c3486 100644
--- a/drivers/platform/x86/tc1100-wmi.c
+++ b/drivers/platform/x86/tc1100-wmi.c
@@ -47,22 +47,6 @@ MODULE_DESCRIPTION("HP Compaq TC1100 Tablet WMI Extras");
47MODULE_LICENSE("GPL"); 47MODULE_LICENSE("GPL");
48MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505"); 48MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505");
49 49
50static int tc1100_probe(struct platform_device *device);
51static int tc1100_remove(struct platform_device *device);
52static int tc1100_suspend(struct platform_device *device, pm_message_t state);
53static int tc1100_resume(struct platform_device *device);
54
55static struct platform_driver tc1100_driver = {
56 .driver = {
57 .name = "tc1100-wmi",
58 .owner = THIS_MODULE,
59 },
60 .probe = tc1100_probe,
61 .remove = tc1100_remove,
62 .suspend = tc1100_suspend,
63 .resume = tc1100_resume,
64};
65
66static struct platform_device *tc1100_device; 50static struct platform_device *tc1100_device;
67 51
68struct tc1100_data { 52struct tc1100_data {
@@ -183,51 +167,35 @@ static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
183show_set_bool(wireless, TC1100_INSTANCE_WIRELESS); 167show_set_bool(wireless, TC1100_INSTANCE_WIRELESS);
184show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL); 168show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL);
185 169
186static void remove_fs(void) 170static struct attribute *tc1100_attributes[] = {
187{ 171 &dev_attr_wireless.attr,
188 device_remove_file(&tc1100_device->dev, &dev_attr_wireless); 172 &dev_attr_jogdial.attr,
189 device_remove_file(&tc1100_device->dev, &dev_attr_jogdial); 173 NULL
190} 174};
191
192static int add_fs(void)
193{
194 int ret;
195
196 ret = device_create_file(&tc1100_device->dev, &dev_attr_wireless);
197 if (ret)
198 goto add_sysfs_error;
199
200 ret = device_create_file(&tc1100_device->dev, &dev_attr_jogdial);
201 if (ret)
202 goto add_sysfs_error;
203
204 return ret;
205 175
206add_sysfs_error: 176static struct attribute_group tc1100_attribute_group = {
207 remove_fs(); 177 .attrs = tc1100_attributes,
208 return ret; 178};
209}
210 179
211/* -------------------------------------------------------------------------- 180/* --------------------------------------------------------------------------
212 Driver Model 181 Driver Model
213 -------------------------------------------------------------------------- */ 182 -------------------------------------------------------------------------- */
214 183
215static int tc1100_probe(struct platform_device *device) 184static int __init tc1100_probe(struct platform_device *device)
216{ 185{
217 int result = 0; 186 return sysfs_create_group(&device->dev.kobj, &tc1100_attribute_group);
218
219 result = add_fs();
220 return result;
221} 187}
222 188
223 189
224static int tc1100_remove(struct platform_device *device) 190static int __devexit tc1100_remove(struct platform_device *device)
225{ 191{
226 remove_fs(); 192 sysfs_remove_group(&device->dev.kobj, &tc1100_attribute_group);
193
227 return 0; 194 return 0;
228} 195}
229 196
230static int tc1100_suspend(struct platform_device *dev, pm_message_t state) 197#ifdef CONFIG_PM
198static int tc1100_suspend(struct device *dev)
231{ 199{
232 int ret; 200 int ret;
233 201
@@ -239,10 +207,10 @@ static int tc1100_suspend(struct platform_device *dev, pm_message_t state)
239 if (ret) 207 if (ret)
240 return ret; 208 return ret;
241 209
242 return ret; 210 return 0;
243} 211}
244 212
245static int tc1100_resume(struct platform_device *dev) 213static int tc1100_resume(struct device *dev)
246{ 214{
247 int ret; 215 int ret;
248 216
@@ -254,34 +222,61 @@ static int tc1100_resume(struct platform_device *dev)
254 if (ret) 222 if (ret)
255 return ret; 223 return ret;
256 224
257 return ret; 225 return 0;
258} 226}
259 227
228static const struct dev_pm_ops tc1100_pm_ops = {
229 .suspend = tc1100_suspend,
230 .resume = tc1100_resume,
231 .freeze = tc1100_suspend,
232 .restore = tc1100_resume,
233};
234#endif
235
236static struct platform_driver tc1100_driver = {
237 .driver = {
238 .name = "tc1100-wmi",
239 .owner = THIS_MODULE,
240#ifdef CONFIG_PM
241 .pm = &tc1100_pm_ops,
242#endif
243 },
244 .remove = __devexit_p(tc1100_remove),
245};
246
260static int __init tc1100_init(void) 247static int __init tc1100_init(void)
261{ 248{
262 int result = 0; 249 int error;
263 250
264 if (!wmi_has_guid(GUID)) 251 if (!wmi_has_guid(GUID))
265 return -ENODEV; 252 return -ENODEV;
266 253
267 result = platform_driver_register(&tc1100_driver);
268 if (result)
269 return result;
270
271 tc1100_device = platform_device_alloc("tc1100-wmi", -1); 254 tc1100_device = platform_device_alloc("tc1100-wmi", -1);
272 platform_device_add(tc1100_device); 255 if (!tc1100_device)
256 return -ENOMEM;
257
258 error = platform_device_add(tc1100_device);
259 if (error)
260 goto err_device_put;
261
262 error = platform_driver_probe(&tc1100_driver, tc1100_probe);
263 if (error)
264 goto err_device_del;
273 265
274 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n"); 266 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n");
267 return 0;
275 268
276 return result; 269 err_device_del:
270 platform_device_del(tc1100_device);
271 err_device_put:
272 platform_device_put(tc1100_device);
273 return error;
277} 274}
278 275
279static void __exit tc1100_exit(void) 276static void __exit tc1100_exit(void)
280{ 277{
281 platform_device_del(tc1100_device); 278 platform_device_unregister(tc1100_device);
282 platform_driver_unregister(&tc1100_driver); 279 platform_driver_unregister(&tc1100_driver);
283
284 printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras unloaded\n");
285} 280}
286 281
287module_init(tc1100_init); 282module_init(tc1100_init);
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 51c0a8bee414..77bf5d8f893a 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -42,6 +42,7 @@
42#include <linux/init.h> 42#include <linux/init.h>
43#include <linux/types.h> 43#include <linux/types.h>
44#include <linux/proc_fs.h> 44#include <linux/proc_fs.h>
45#include <linux/seq_file.h>
45#include <linux/backlight.h> 46#include <linux/backlight.h>
46#include <linux/platform_device.h> 47#include <linux/platform_device.h>
47#include <linux/rfkill.h> 48#include <linux/rfkill.h>
@@ -357,63 +358,6 @@ static int force_fan;
357static int last_key_event; 358static int last_key_event;
358static int key_event_valid; 359static int key_event_valid;
359 360
360typedef struct _ProcItem {
361 const char *name;
362 char *(*read_func) (char *);
363 unsigned long (*write_func) (const char *, unsigned long);
364} ProcItem;
365
366/* proc file handlers
367 */
368
369static int
370dispatch_read(char *page, char **start, off_t off, int count, int *eof,
371 ProcItem * item)
372{
373 char *p = page;
374 int len;
375
376 if (off == 0)
377 p = item->read_func(p);
378
379 /* ISSUE: I don't understand this code */
380 len = (p - page);
381 if (len <= off + count)
382 *eof = 1;
383 *start = page + off;
384 len -= off;
385 if (len > count)
386 len = count;
387 if (len < 0)
388 len = 0;
389 return len;
390}
391
392static int
393dispatch_write(struct file *file, const char __user * buffer,
394 unsigned long count, ProcItem * item)
395{
396 int result;
397 char *tmp_buffer;
398
399 /* Arg buffer points to userspace memory, which can't be accessed
400 * directly. Since we're making a copy, zero-terminate the
401 * destination so that sscanf can be used on it safely.
402 */
403 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
404 if (!tmp_buffer)
405 return -ENOMEM;
406
407 if (copy_from_user(tmp_buffer, buffer, count)) {
408 result = -EFAULT;
409 } else {
410 tmp_buffer[count] = 0;
411 result = item->write_func(tmp_buffer, count);
412 }
413 kfree(tmp_buffer);
414 return result;
415}
416
417static int get_lcd(struct backlight_device *bd) 361static int get_lcd(struct backlight_device *bd)
418{ 362{
419 u32 hci_result; 363 u32 hci_result;
@@ -426,19 +370,24 @@ static int get_lcd(struct backlight_device *bd)
426 return -EFAULT; 370 return -EFAULT;
427} 371}
428 372
429static char *read_lcd(char *p) 373static int lcd_proc_show(struct seq_file *m, void *v)
430{ 374{
431 int value = get_lcd(NULL); 375 int value = get_lcd(NULL);
432 376
433 if (value >= 0) { 377 if (value >= 0) {
434 p += sprintf(p, "brightness: %d\n", value); 378 seq_printf(m, "brightness: %d\n", value);
435 p += sprintf(p, "brightness_levels: %d\n", 379 seq_printf(m, "brightness_levels: %d\n",
436 HCI_LCD_BRIGHTNESS_LEVELS); 380 HCI_LCD_BRIGHTNESS_LEVELS);
437 } else { 381 } else {
438 printk(MY_ERR "Error reading LCD brightness\n"); 382 printk(MY_ERR "Error reading LCD brightness\n");
439 } 383 }
440 384
441 return p; 385 return 0;
386}
387
388static int lcd_proc_open(struct inode *inode, struct file *file)
389{
390 return single_open(file, lcd_proc_show, NULL);
442} 391}
443 392
444static int set_lcd(int value) 393static int set_lcd(int value)
@@ -458,12 +407,20 @@ static int set_lcd_status(struct backlight_device *bd)
458 return set_lcd(bd->props.brightness); 407 return set_lcd(bd->props.brightness);
459} 408}
460 409
461static unsigned long write_lcd(const char *buffer, unsigned long count) 410static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
411 size_t count, loff_t *pos)
462{ 412{
413 char cmd[42];
414 size_t len;
463 int value; 415 int value;
464 int ret; 416 int ret;
465 417
466 if (sscanf(buffer, " brightness : %i", &value) == 1 && 418 len = min(count, sizeof(cmd) - 1);
419 if (copy_from_user(cmd, buf, len))
420 return -EFAULT;
421 cmd[len] = '\0';
422
423 if (sscanf(cmd, " brightness : %i", &value) == 1 &&
467 value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { 424 value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
468 ret = set_lcd(value); 425 ret = set_lcd(value);
469 if (ret == 0) 426 if (ret == 0)
@@ -474,7 +431,16 @@ static unsigned long write_lcd(const char *buffer, unsigned long count)
474 return ret; 431 return ret;
475} 432}
476 433
477static char *read_video(char *p) 434static const struct file_operations lcd_proc_fops = {
435 .owner = THIS_MODULE,
436 .open = lcd_proc_open,
437 .read = seq_read,
438 .llseek = seq_lseek,
439 .release = single_release,
440 .write = lcd_proc_write,
441};
442
443static int video_proc_show(struct seq_file *m, void *v)
478{ 444{
479 u32 hci_result; 445 u32 hci_result;
480 u32 value; 446 u32 value;
@@ -484,18 +450,25 @@ static char *read_video(char *p)
484 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 450 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
485 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 451 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
486 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 452 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
487 p += sprintf(p, "lcd_out: %d\n", is_lcd); 453 seq_printf(m, "lcd_out: %d\n", is_lcd);
488 p += sprintf(p, "crt_out: %d\n", is_crt); 454 seq_printf(m, "crt_out: %d\n", is_crt);
489 p += sprintf(p, "tv_out: %d\n", is_tv); 455 seq_printf(m, "tv_out: %d\n", is_tv);
490 } else { 456 } else {
491 printk(MY_ERR "Error reading video out status\n"); 457 printk(MY_ERR "Error reading video out status\n");
492 } 458 }
493 459
494 return p; 460 return 0;
495} 461}
496 462
497static unsigned long write_video(const char *buffer, unsigned long count) 463static int video_proc_open(struct inode *inode, struct file *file)
498{ 464{
465 return single_open(file, video_proc_show, NULL);
466}
467
468static ssize_t video_proc_write(struct file *file, const char __user *buf,
469 size_t count, loff_t *pos)
470{
471 char *cmd, *buffer;
499 int value; 472 int value;
500 int remain = count; 473 int remain = count;
501 int lcd_out = -1; 474 int lcd_out = -1;
@@ -504,6 +477,17 @@ static unsigned long write_video(const char *buffer, unsigned long count)
504 u32 hci_result; 477 u32 hci_result;
505 u32 video_out; 478 u32 video_out;
506 479
480 cmd = kmalloc(count + 1, GFP_KERNEL);
481 if (!cmd)
482 return -ENOMEM;
483 if (copy_from_user(cmd, buf, count)) {
484 kfree(cmd);
485 return -EFAULT;
486 }
487 cmd[count] = '\0';
488
489 buffer = cmd;
490
507 /* scan expression. Multiple expressions may be delimited with ; 491 /* scan expression. Multiple expressions may be delimited with ;
508 * 492 *
509 * NOTE: to keep scanning simple, invalid fields are ignored 493 * NOTE: to keep scanning simple, invalid fields are ignored
@@ -523,6 +507,8 @@ static unsigned long write_video(const char *buffer, unsigned long count)
523 while (remain && *(buffer - 1) != ';'); 507 while (remain && *(buffer - 1) != ';');
524 } 508 }
525 509
510 kfree(cmd);
511
526 hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result); 512 hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
527 if (hci_result == HCI_SUCCESS) { 513 if (hci_result == HCI_SUCCESS) {
528 unsigned int new_video_out = video_out; 514 unsigned int new_video_out = video_out;
@@ -543,28 +529,50 @@ static unsigned long write_video(const char *buffer, unsigned long count)
543 return count; 529 return count;
544} 530}
545 531
546static char *read_fan(char *p) 532static const struct file_operations video_proc_fops = {
533 .owner = THIS_MODULE,
534 .open = video_proc_open,
535 .read = seq_read,
536 .llseek = seq_lseek,
537 .release = single_release,
538 .write = video_proc_write,
539};
540
541static int fan_proc_show(struct seq_file *m, void *v)
547{ 542{
548 u32 hci_result; 543 u32 hci_result;
549 u32 value; 544 u32 value;
550 545
551 hci_read1(HCI_FAN, &value, &hci_result); 546 hci_read1(HCI_FAN, &value, &hci_result);
552 if (hci_result == HCI_SUCCESS) { 547 if (hci_result == HCI_SUCCESS) {
553 p += sprintf(p, "running: %d\n", (value > 0)); 548 seq_printf(m, "running: %d\n", (value > 0));
554 p += sprintf(p, "force_on: %d\n", force_fan); 549 seq_printf(m, "force_on: %d\n", force_fan);
555 } else { 550 } else {
556 printk(MY_ERR "Error reading fan status\n"); 551 printk(MY_ERR "Error reading fan status\n");
557 } 552 }
558 553
559 return p; 554 return 0;
555}
556
557static int fan_proc_open(struct inode *inode, struct file *file)
558{
559 return single_open(file, fan_proc_show, NULL);
560} 560}
561 561
562static unsigned long write_fan(const char *buffer, unsigned long count) 562static ssize_t fan_proc_write(struct file *file, const char __user *buf,
563 size_t count, loff_t *pos)
563{ 564{
565 char cmd[42];
566 size_t len;
564 int value; 567 int value;
565 u32 hci_result; 568 u32 hci_result;
566 569
567 if (sscanf(buffer, " force_on : %i", &value) == 1 && 570 len = min(count, sizeof(cmd) - 1);
571 if (copy_from_user(cmd, buf, len))
572 return -EFAULT;
573 cmd[len] = '\0';
574
575 if (sscanf(cmd, " force_on : %i", &value) == 1 &&
568 value >= 0 && value <= 1) { 576 value >= 0 && value <= 1) {
569 hci_write1(HCI_FAN, value, &hci_result); 577 hci_write1(HCI_FAN, value, &hci_result);
570 if (hci_result != HCI_SUCCESS) 578 if (hci_result != HCI_SUCCESS)
@@ -578,7 +586,16 @@ static unsigned long write_fan(const char *buffer, unsigned long count)
578 return count; 586 return count;
579} 587}
580 588
581static char *read_keys(char *p) 589static const struct file_operations fan_proc_fops = {
590 .owner = THIS_MODULE,
591 .open = fan_proc_open,
592 .read = seq_read,
593 .llseek = seq_lseek,
594 .release = single_release,
595 .write = fan_proc_write,
596};
597
598static int keys_proc_show(struct seq_file *m, void *v)
582{ 599{
583 u32 hci_result; 600 u32 hci_result;
584 u32 value; 601 u32 value;
@@ -602,18 +619,30 @@ static char *read_keys(char *p)
602 } 619 }
603 } 620 }
604 621
605 p += sprintf(p, "hotkey_ready: %d\n", key_event_valid); 622 seq_printf(m, "hotkey_ready: %d\n", key_event_valid);
606 p += sprintf(p, "hotkey: 0x%04x\n", last_key_event); 623 seq_printf(m, "hotkey: 0x%04x\n", last_key_event);
624end:
625 return 0;
626}
607 627
608 end: 628static int keys_proc_open(struct inode *inode, struct file *file)
609 return p; 629{
630 return single_open(file, keys_proc_show, NULL);
610} 631}
611 632
612static unsigned long write_keys(const char *buffer, unsigned long count) 633static ssize_t keys_proc_write(struct file *file, const char __user *buf,
634 size_t count, loff_t *pos)
613{ 635{
636 char cmd[42];
637 size_t len;
614 int value; 638 int value;
615 639
616 if (sscanf(buffer, " hotkey_ready : %i", &value) == 1 && value == 0) { 640 len = min(count, sizeof(cmd) - 1);
641 if (copy_from_user(cmd, buf, len))
642 return -EFAULT;
643 cmd[len] = '\0';
644
645 if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
617 key_event_valid = 0; 646 key_event_valid = 0;
618 } else { 647 } else {
619 return -EINVAL; 648 return -EINVAL;
@@ -622,52 +651,58 @@ static unsigned long write_keys(const char *buffer, unsigned long count)
622 return count; 651 return count;
623} 652}
624 653
625static char *read_version(char *p) 654static const struct file_operations keys_proc_fops = {
655 .owner = THIS_MODULE,
656 .open = keys_proc_open,
657 .read = seq_read,
658 .llseek = seq_lseek,
659 .release = single_release,
660 .write = keys_proc_write,
661};
662
663static int version_proc_show(struct seq_file *m, void *v)
626{ 664{
627 p += sprintf(p, "driver: %s\n", TOSHIBA_ACPI_VERSION); 665 seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION);
628 p += sprintf(p, "proc_interface: %d\n", 666 seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION);
629 PROC_INTERFACE_VERSION); 667 return 0;
630 return p;
631} 668}
632 669
670static int version_proc_open(struct inode *inode, struct file *file)
671{
672 return single_open(file, version_proc_show, PDE(inode)->data);
673}
674
675static const struct file_operations version_proc_fops = {
676 .owner = THIS_MODULE,
677 .open = version_proc_open,
678 .read = seq_read,
679 .llseek = seq_lseek,
680 .release = single_release,
681};
682
633/* proc and module init 683/* proc and module init
634 */ 684 */
635 685
636#define PROC_TOSHIBA "toshiba" 686#define PROC_TOSHIBA "toshiba"
637 687
638static ProcItem proc_items[] = {
639 {"lcd", read_lcd, write_lcd},
640 {"video", read_video, write_video},
641 {"fan", read_fan, write_fan},
642 {"keys", read_keys, write_keys},
643 {"version", read_version, NULL},
644 {NULL}
645};
646
647static acpi_status __init add_device(void) 688static acpi_status __init add_device(void)
648{ 689{
649 struct proc_dir_entry *proc; 690 proc_create("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, &lcd_proc_fops);
650 ProcItem *item; 691 proc_create("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, &video_proc_fops);
651 692 proc_create("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, &fan_proc_fops);
652 for (item = proc_items; item->name; ++item) { 693 proc_create("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, &keys_proc_fops);
653 proc = create_proc_read_entry(item->name, 694 proc_create("version", S_IRUGO, toshiba_proc_dir, &version_proc_fops);
654 S_IFREG | S_IRUGO | S_IWUSR,
655 toshiba_proc_dir,
656 (read_proc_t *) dispatch_read,
657 item);
658 if (proc && item->write_func)
659 proc->write_proc = (write_proc_t *) dispatch_write;
660 }
661 695
662 return AE_OK; 696 return AE_OK;
663} 697}
664 698
665static acpi_status remove_device(void) 699static acpi_status remove_device(void)
666{ 700{
667 ProcItem *item; 701 remove_proc_entry("lcd", toshiba_proc_dir);
668 702 remove_proc_entry("video", toshiba_proc_dir);
669 for (item = proc_items; item->name; ++item) 703 remove_proc_entry("fan", toshiba_proc_dir);
670 remove_proc_entry(item->name, toshiba_proc_dir); 704 remove_proc_entry("keys", toshiba_proc_dir);
705 remove_proc_entry("version", toshiba_proc_dir);
671 return AE_OK; 706 return AE_OK;
672} 707}
673 708
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index e425a868cd3a..9f93d6c0f510 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -540,8 +540,8 @@ EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
540/** 540/**
541 * wmi_get_event_data - Get WMI data associated with an event 541 * wmi_get_event_data - Get WMI data associated with an event
542 * 542 *
543 * @event - Event to find 543 * @event: Event to find
544 * &out - Buffer to hold event data 544 * @out: Buffer to hold event data. out->pointer should be freed with kfree()
545 * 545 *
546 * Returns extra data associated with an event in WMI. 546 * Returns extra data associated with an event in WMI.
547 */ 547 */