aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig29
-rw-r--r--drivers/platform/x86/dell-wmi.c18
-rw-r--r--drivers/platform/x86/eeepc-laptop.c298
-rw-r--r--drivers/platform/x86/hp-wmi.c11
-rw-r--r--drivers/platform/x86/msi-wmi.c9
-rw-r--r--drivers/platform/x86/sony-laptop.c9
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c59
-rw-r--r--drivers/platform/x86/wmi.c36
8 files changed, 301 insertions, 168 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index ec4faffe6b0..f526e735c5a 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -231,8 +231,36 @@ config THINKPAD_ACPI
231 231
232 This driver was formerly known as ibm-acpi. 232 This driver was formerly known as ibm-acpi.
233 233
234 Extra functionality will be available if the rfkill (CONFIG_RFKILL)
235 and/or ALSA (CONFIG_SND) subsystems are available in the kernel.
236 Note that if you want ThinkPad-ACPI to be built-in instead of
237 modular, ALSA and rfkill will also have to be built-in.
238
234 If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. 239 If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
235 240
241config THINKPAD_ACPI_ALSA_SUPPORT
242 bool "Console audio control ALSA interface"
243 depends on THINKPAD_ACPI
244 depends on SND
245 depends on SND = y || THINKPAD_ACPI = SND
246 default y
247 ---help---
248 Enables monitoring of the built-in console audio output control
249 (headphone and speakers), which is operated by the mute and (in
250 some ThinkPad models) volume hotkeys.
251
252 If this option is enabled, ThinkPad-ACPI will export an ALSA card
253 with a single read-only mixer control, which should be used for
254 on-screen-display feedback purposes by the Desktop Environment.
255
256 Optionally, the driver will also allow software control (the
257 ALSA mixer will be made read-write). Please refer to the driver
258 documentation for details.
259
260 All IBM models have both volume and mute control. Newer Lenovo
261 models only have mute control (the volume hotkeys are just normal
262 keys and volume control is done through the main HDA mixer).
263
236config THINKPAD_ACPI_DEBUGFACILITIES 264config THINKPAD_ACPI_DEBUGFACILITIES
237 bool "Maintainer debug facilities" 265 bool "Maintainer debug facilities"
238 depends on THINKPAD_ACPI 266 depends on THINKPAD_ACPI
@@ -336,6 +364,7 @@ config EEEPC_LAPTOP
336 select HWMON 364 select HWMON
337 select LEDS_CLASS 365 select LEDS_CLASS
338 select NEW_LEDS 366 select NEW_LEDS
367 select INPUT_SPARSEKMAP
339 ---help--- 368 ---help---
340 This driver supports the Fn-Fx keys on Eee PC laptops. 369 This driver supports the Fn-Fx keys on Eee PC laptops.
341 370
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 916ccb2b316..1b1dddbd574 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -202,8 +202,13 @@ static void dell_wmi_notify(u32 value, void *context)
202 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 202 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
203 static struct key_entry *key; 203 static struct key_entry *key;
204 union acpi_object *obj; 204 union acpi_object *obj;
205 acpi_status status;
205 206
206 wmi_get_event_data(value, &response); 207 status = wmi_get_event_data(value, &response);
208 if (status != AE_OK) {
209 printk(KERN_INFO "dell-wmi: bad event status 0x%x\n", status);
210 return;
211 }
207 212
208 obj = (union acpi_object *)response.pointer; 213 obj = (union acpi_object *)response.pointer;
209 214
@@ -323,8 +328,9 @@ static int __init dell_wmi_input_setup(void)
323static int __init dell_wmi_init(void) 328static int __init dell_wmi_init(void)
324{ 329{
325 int err; 330 int err;
331 acpi_status status;
326 332
327 if (wmi_has_guid(DELL_EVENT_GUID)) { 333 if (!wmi_has_guid(DELL_EVENT_GUID)) {
328 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); 334 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
329 return -ENODEV; 335 return -ENODEV;
330 } 336 }
@@ -336,14 +342,14 @@ static int __init dell_wmi_init(void)
336 if (err) 342 if (err)
337 return err; 343 return err;
338 344
339 err = wmi_install_notify_handler(DELL_EVENT_GUID, 345 status = wmi_install_notify_handler(DELL_EVENT_GUID,
340 dell_wmi_notify, NULL); 346 dell_wmi_notify, NULL);
341 if (err) { 347 if (ACPI_FAILURE(status)) {
342 input_unregister_device(dell_wmi_input_dev); 348 input_unregister_device(dell_wmi_input_dev);
343 printk(KERN_ERR 349 printk(KERN_ERR
344 "dell-wmi: Unable to register notify handler - %d\n", 350 "dell-wmi: Unable to register notify handler - %d\n",
345 err); 351 status);
346 return err; 352 return -ENODEV;
347 } 353 }
348 354
349 return 0; 355 return 0;
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 5838c69b2fb..e2be6bb33d9 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -31,10 +31,12 @@
31#include <acpi/acpi_bus.h> 31#include <acpi/acpi_bus.h>
32#include <linux/uaccess.h> 32#include <linux/uaccess.h>
33#include <linux/input.h> 33#include <linux/input.h>
34#include <linux/input/sparse-keymap.h>
34#include <linux/rfkill.h> 35#include <linux/rfkill.h>
35#include <linux/pci.h> 36#include <linux/pci.h>
36#include <linux/pci_hotplug.h> 37#include <linux/pci_hotplug.h>
37#include <linux/leds.h> 38#include <linux/leds.h>
39#include <linux/dmi.h>
38 40
39#define EEEPC_LAPTOP_VERSION "0.1" 41#define EEEPC_LAPTOP_VERSION "0.1"
40#define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver" 42#define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver"
@@ -48,6 +50,14 @@ MODULE_AUTHOR("Corentin Chary, Eric Cooper");
48MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME); 50MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME);
49MODULE_LICENSE("GPL"); 51MODULE_LICENSE("GPL");
50 52
53static bool hotplug_disabled;
54
55module_param(hotplug_disabled, bool, 0644);
56MODULE_PARM_DESC(hotplug_disabled,
57 "Disable hotplug for wireless device. "
58 "If your laptop need that, please report to "
59 "acpi4asus-user@lists.sourceforge.net.");
60
51/* 61/*
52 * Definitions for Asus EeePC 62 * Definitions for Asus EeePC
53 */ 63 */
@@ -120,38 +130,28 @@ static const char *cm_setv[] = {
120 NULL, NULL, "PBPS", "TPDS" 130 NULL, NULL, "PBPS", "TPDS"
121}; 131};
122 132
123struct key_entry {
124 char type;
125 u8 code;
126 u16 keycode;
127};
128
129enum { KE_KEY, KE_END };
130
131static const struct key_entry eeepc_keymap[] = { 133static const struct key_entry eeepc_keymap[] = {
132 /* Sleep already handled via generic ACPI code */ 134 { KE_KEY, 0x10, { KEY_WLAN } },
133 {KE_KEY, 0x10, KEY_WLAN }, 135 { KE_KEY, 0x11, { KEY_WLAN } },
134 {KE_KEY, 0x11, KEY_WLAN }, 136 { KE_KEY, 0x12, { KEY_PROG1 } },
135 {KE_KEY, 0x12, KEY_PROG1 }, 137 { KE_KEY, 0x13, { KEY_MUTE } },
136 {KE_KEY, 0x13, KEY_MUTE }, 138 { KE_KEY, 0x14, { KEY_VOLUMEDOWN } },
137 {KE_KEY, 0x14, KEY_VOLUMEDOWN }, 139 { KE_KEY, 0x15, { KEY_VOLUMEUP } },
138 {KE_KEY, 0x15, KEY_VOLUMEUP }, 140 { KE_KEY, 0x16, { KEY_DISPLAY_OFF } },
139 {KE_KEY, 0x16, KEY_DISPLAY_OFF }, 141 { KE_KEY, 0x1a, { KEY_COFFEE } },
140 {KE_KEY, 0x1a, KEY_COFFEE }, 142 { KE_KEY, 0x1b, { KEY_ZOOM } },
141 {KE_KEY, 0x1b, KEY_ZOOM }, 143 { KE_KEY, 0x1c, { KEY_PROG2 } },
142 {KE_KEY, 0x1c, KEY_PROG2 }, 144 { KE_KEY, 0x1d, { KEY_PROG3 } },
143 {KE_KEY, 0x1d, KEY_PROG3 }, 145 { KE_KEY, NOTIFY_BRN_MIN, { KEY_BRIGHTNESSDOWN } },
144 {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN }, 146 { KE_KEY, NOTIFY_BRN_MAX, { KEY_BRIGHTNESSUP } },
145 {KE_KEY, NOTIFY_BRN_MAX, KEY_BRIGHTNESSUP }, 147 { KE_KEY, 0x30, { KEY_SWITCHVIDEOMODE } },
146 {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, 148 { KE_KEY, 0x31, { KEY_SWITCHVIDEOMODE } },
147 {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, 149 { KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } },
148 {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, 150 { KE_KEY, 0x37, { KEY_F13 } }, /* Disable Touchpad */
149 {KE_KEY, 0x37, KEY_F13 }, /* Disable Touchpad */ 151 { KE_KEY, 0x38, { KEY_F14 } },
150 {KE_KEY, 0x38, KEY_F14 }, 152 { KE_END, 0 },
151 {KE_END, 0},
152}; 153};
153 154
154
155/* 155/*
156 * This is the main structure, we can use it to store useful information 156 * This is the main structure, we can use it to store useful information
157 */ 157 */
@@ -159,6 +159,8 @@ struct eeepc_laptop {
159 acpi_handle handle; /* the handle of the acpi device */ 159 acpi_handle handle; /* the handle of the acpi device */
160 u32 cm_supported; /* the control methods supported 160 u32 cm_supported; /* the control methods supported
161 by this BIOS */ 161 by this BIOS */
162 bool cpufv_disabled;
163 bool hotplug_disabled;
162 u16 event_count[128]; /* count for each event */ 164 u16 event_count[128]; /* count for each event */
163 165
164 struct platform_device *platform_device; 166 struct platform_device *platform_device;
@@ -378,6 +380,8 @@ static ssize_t store_cpufv(struct device *dev,
378 struct eeepc_cpufv c; 380 struct eeepc_cpufv c;
379 int rv, value; 381 int rv, value;
380 382
383 if (eeepc->cpufv_disabled)
384 return -EPERM;
381 if (get_cpufv(eeepc, &c)) 385 if (get_cpufv(eeepc, &c))
382 return -ENODEV; 386 return -ENODEV;
383 rv = parse_arg(buf, count, &value); 387 rv = parse_arg(buf, count, &value);
@@ -389,6 +393,41 @@ static ssize_t store_cpufv(struct device *dev,
389 return rv; 393 return rv;
390} 394}
391 395
396static ssize_t show_cpufv_disabled(struct device *dev,
397 struct device_attribute *attr,
398 char *buf)
399{
400 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
401
402 return sprintf(buf, "%d\n", eeepc->cpufv_disabled);
403}
404
405static ssize_t store_cpufv_disabled(struct device *dev,
406 struct device_attribute *attr,
407 const char *buf, size_t count)
408{
409 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
410 int rv, value;
411
412 rv = parse_arg(buf, count, &value);
413 if (rv < 0)
414 return rv;
415
416 switch (value) {
417 case 0:
418 if (eeepc->cpufv_disabled)
419 pr_warning("cpufv enabled (not officially supported "
420 "on this model)\n");
421 eeepc->cpufv_disabled = false;
422 return rv;
423 case 1:
424 return -EPERM;
425 default:
426 return -EINVAL;
427 }
428}
429
430
392static struct device_attribute dev_attr_cpufv = { 431static struct device_attribute dev_attr_cpufv = {
393 .attr = { 432 .attr = {
394 .name = "cpufv", 433 .name = "cpufv",
@@ -404,12 +443,22 @@ static struct device_attribute dev_attr_available_cpufv = {
404 .show = show_available_cpufv 443 .show = show_available_cpufv
405}; 444};
406 445
446static struct device_attribute dev_attr_cpufv_disabled = {
447 .attr = {
448 .name = "cpufv_disabled",
449 .mode = 0644 },
450 .show = show_cpufv_disabled,
451 .store = store_cpufv_disabled
452};
453
454
407static struct attribute *platform_attributes[] = { 455static struct attribute *platform_attributes[] = {
408 &dev_attr_camera.attr, 456 &dev_attr_camera.attr,
409 &dev_attr_cardr.attr, 457 &dev_attr_cardr.attr,
410 &dev_attr_disp.attr, 458 &dev_attr_disp.attr,
411 &dev_attr_cpufv.attr, 459 &dev_attr_cpufv.attr,
412 &dev_attr_available_cpufv.attr, 460 &dev_attr_available_cpufv.attr,
461 &dev_attr_cpufv_disabled.attr,
413 NULL 462 NULL
414}; 463};
415 464
@@ -796,6 +845,9 @@ static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)
796 if (result && result != -ENODEV) 845 if (result && result != -ENODEV)
797 goto exit; 846 goto exit;
798 847
848 if (eeepc->hotplug_disabled)
849 return 0;
850
799 result = eeepc_setup_pci_hotplug(eeepc); 851 result = eeepc_setup_pci_hotplug(eeepc);
800 /* 852 /*
801 * If we get -EBUSY then something else is handling the PCI hotplug - 853 * If we get -EBUSY then something else is handling the PCI hotplug -
@@ -1090,120 +1142,42 @@ static void eeepc_backlight_exit(struct eeepc_laptop *eeepc)
1090/* 1142/*
1091 * Input device (i.e. hotkeys) 1143 * Input device (i.e. hotkeys)
1092 */ 1144 */
1093static struct key_entry *eeepc_get_entry_by_scancode( 1145static int eeepc_input_init(struct eeepc_laptop *eeepc)
1094 struct eeepc_laptop *eeepc,
1095 int code)
1096{ 1146{
1097 struct key_entry *key; 1147 struct input_dev *input;
1148 int error;
1098 1149
1099 for (key = eeepc->keymap; key->type != KE_END; key++) 1150 input = input_allocate_device();
1100 if (code == key->code) 1151 if (!input) {
1101 return key; 1152 pr_info("Unable to allocate input device\n");
1102 1153 return -ENOMEM;
1103 return NULL;
1104}
1105
1106static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
1107{
1108 static struct key_entry *key;
1109
1110 key = eeepc_get_entry_by_scancode(eeepc, event);
1111 if (key) {
1112 switch (key->type) {
1113 case KE_KEY:
1114 input_report_key(eeepc->inputdev, key->keycode,
1115 1);
1116 input_sync(eeepc->inputdev);
1117 input_report_key(eeepc->inputdev, key->keycode,
1118 0);
1119 input_sync(eeepc->inputdev);
1120 break;
1121 }
1122 } 1154 }
1123}
1124
1125static struct key_entry *eeepc_get_entry_by_keycode(
1126 struct eeepc_laptop *eeepc, int code)
1127{
1128 struct key_entry *key;
1129
1130 for (key = eeepc->keymap; key->type != KE_END; key++)
1131 if (code == key->keycode && key->type == KE_KEY)
1132 return key;
1133 1155
1134 return NULL; 1156 input->name = "Asus EeePC extra buttons";
1135} 1157 input->phys = EEEPC_LAPTOP_FILE "/input0";
1158 input->id.bustype = BUS_HOST;
1159 input->dev.parent = &eeepc->platform_device->dev;
1136 1160
1137static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) 1161 error = sparse_keymap_setup(input, eeepc_keymap, NULL);
1138{ 1162 if (error) {
1139 struct eeepc_laptop *eeepc = input_get_drvdata(dev); 1163 pr_err("Unable to setup input device keymap\n");
1140 struct key_entry *key = eeepc_get_entry_by_scancode(eeepc, scancode); 1164 goto err_free_dev;
1141
1142 if (key && key->type == KE_KEY) {
1143 *keycode = key->keycode;
1144 return 0;
1145 } 1165 }
1146 1166
1147 return -EINVAL; 1167 error = input_register_device(input);
1148} 1168 if (error) {
1149 1169 pr_err("Unable to register input device\n");
1150static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) 1170 goto err_free_keymap;
1151{
1152 struct eeepc_laptop *eeepc = input_get_drvdata(dev);
1153 struct key_entry *key;
1154 int old_keycode;
1155
1156 if (keycode < 0 || keycode > KEY_MAX)
1157 return -EINVAL;
1158
1159 key = eeepc_get_entry_by_scancode(eeepc, scancode);
1160 if (key && key->type == KE_KEY) {
1161 old_keycode = key->keycode;
1162 key->keycode = keycode;
1163 set_bit(keycode, dev->keybit);
1164 if (!eeepc_get_entry_by_keycode(eeepc, old_keycode))
1165 clear_bit(old_keycode, dev->keybit);
1166 return 0;
1167 } 1171 }
1168 1172
1169 return -EINVAL; 1173 eeepc->inputdev = input;
1170}
1171
1172static int eeepc_input_init(struct eeepc_laptop *eeepc)
1173{
1174 const struct key_entry *key;
1175 int result;
1176
1177 eeepc->inputdev = input_allocate_device();
1178 if (!eeepc->inputdev) {
1179 pr_info("Unable to allocate input device\n");
1180 return -ENOMEM;
1181 }
1182 eeepc->inputdev->name = "Asus EeePC extra buttons";
1183 eeepc->inputdev->dev.parent = &eeepc->platform_device->dev;
1184 eeepc->inputdev->phys = EEEPC_LAPTOP_FILE "/input0";
1185 eeepc->inputdev->id.bustype = BUS_HOST;
1186 eeepc->inputdev->getkeycode = eeepc_getkeycode;
1187 eeepc->inputdev->setkeycode = eeepc_setkeycode;
1188 input_set_drvdata(eeepc->inputdev, eeepc);
1189
1190 eeepc->keymap = kmemdup(eeepc_keymap, sizeof(eeepc_keymap),
1191 GFP_KERNEL);
1192 for (key = eeepc_keymap; key->type != KE_END; key++) {
1193 switch (key->type) {
1194 case KE_KEY:
1195 set_bit(EV_KEY, eeepc->inputdev->evbit);
1196 set_bit(key->keycode, eeepc->inputdev->keybit);
1197 break;
1198 }
1199 }
1200 result = input_register_device(eeepc->inputdev);
1201 if (result) {
1202 pr_info("Unable to register input device\n");
1203 input_free_device(eeepc->inputdev);
1204 return result;
1205 }
1206 return 0; 1174 return 0;
1175
1176 err_free_keymap:
1177 sparse_keymap_free(input);
1178 err_free_dev:
1179 input_free_device(input);
1180 return error;
1207} 1181}
1208 1182
1209static void eeepc_input_exit(struct eeepc_laptop *eeepc) 1183static void eeepc_input_exit(struct eeepc_laptop *eeepc)
@@ -1253,11 +1227,59 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
1253 * event will be desired value (or else ignored) 1227 * event will be desired value (or else ignored)
1254 */ 1228 */
1255 } 1229 }
1256 eeepc_input_notify(eeepc, event); 1230 sparse_keymap_report_event(eeepc->inputdev, event,
1231 1, true);
1257 } 1232 }
1258 } else { 1233 } else {
1259 /* Everything else is a bona-fide keypress event */ 1234 /* Everything else is a bona-fide keypress event */
1260 eeepc_input_notify(eeepc, event); 1235 sparse_keymap_report_event(eeepc->inputdev, event, 1, true);
1236 }
1237}
1238
1239static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
1240{
1241 const char *model;
1242
1243 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1244 if (!model)
1245 return;
1246
1247 /*
1248 * Blacklist for setting cpufv (cpu speed).
1249 *
1250 * EeePC 4G ("701") implements CFVS, but it is not supported
1251 * by the pre-installed OS, and the original option to change it
1252 * in the BIOS setup screen was removed in later versions.
1253 *
1254 * Judging by the lack of "Super Hybrid Engine" on Asus product pages,
1255 * this applies to all "701" models (4G/4G Surf/2G Surf).
1256 *
1257 * So Asus made a deliberate decision not to support it on this model.
1258 * We have several reports that using it can cause the system to hang
1259 *
1260 * The hang has also been reported on a "702" (Model name "8G"?).
1261 *
1262 * We avoid dmi_check_system() / dmi_match(), because they use
1263 * substring matching. We don't want to affect the "701SD"
1264 * and "701SDX" models, because they do support S.H.E.
1265 */
1266 if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
1267 eeepc->cpufv_disabled = true;
1268 pr_info("model %s does not officially support setting cpu "
1269 "speed\n", model);
1270 pr_info("cpufv disabled to avoid instability\n");
1271 }
1272
1273 /*
1274 * Blacklist for wlan hotplug
1275 *
1276 * Eeepc 1005HA doesn't work like others models and don't need the
1277 * hotplug code. In fact, current hotplug code seems to unplug another
1278 * device...
1279 */
1280 if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0) {
1281 eeepc->hotplug_disabled = true;
1282 pr_info("wlan hotplug disabled\n");
1261 } 1283 }
1262} 1284}
1263 1285
@@ -1342,6 +1364,10 @@ static int __devinit eeepc_acpi_add(struct acpi_device *device)
1342 strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS); 1364 strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
1343 device->driver_data = eeepc; 1365 device->driver_data = eeepc;
1344 1366
1367 eeepc->hotplug_disabled = hotplug_disabled;
1368
1369 eeepc_dmi_check(eeepc);
1370
1345 result = eeepc_acpi_init(eeepc, device); 1371 result = eeepc_acpi_init(eeepc, device);
1346 if (result) 1372 if (result)
1347 goto fail_platform; 1373 goto fail_platform;
@@ -1452,10 +1478,12 @@ static int __init eeepc_laptop_init(void)
1452 result = acpi_bus_register_driver(&eeepc_acpi_driver); 1478 result = acpi_bus_register_driver(&eeepc_acpi_driver);
1453 if (result < 0) 1479 if (result < 0)
1454 goto fail_acpi_driver; 1480 goto fail_acpi_driver;
1481
1455 if (!eeepc_device_present) { 1482 if (!eeepc_device_present) {
1456 result = -ENODEV; 1483 result = -ENODEV;
1457 goto fail_no_device; 1484 goto fail_no_device;
1458 } 1485 }
1486
1459 return 0; 1487 return 0;
1460 1488
1461fail_no_device: 1489fail_no_device:
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 8781d8fa7a5..ad4c414dbfb 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -338,8 +338,13 @@ static void hp_wmi_notify(u32 value, void *context)
338 static struct key_entry *key; 338 static struct key_entry *key;
339 union acpi_object *obj; 339 union acpi_object *obj;
340 int eventcode; 340 int eventcode;
341 acpi_status status;
341 342
342 wmi_get_event_data(value, &response); 343 status = wmi_get_event_data(value, &response);
344 if (status != AE_OK) {
345 printk(KERN_INFO "hp-wmi: bad event status 0x%x\n", status);
346 return;
347 }
343 348
344 obj = (union acpi_object *)response.pointer; 349 obj = (union acpi_object *)response.pointer;
345 350
@@ -388,8 +393,6 @@ static void hp_wmi_notify(u32 value, void *context)
388 } else 393 } else
389 printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", 394 printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
390 eventcode); 395 eventcode);
391
392 kfree(obj);
393} 396}
394 397
395static int __init hp_wmi_input_setup(void) 398static int __init hp_wmi_input_setup(void)
@@ -581,7 +584,7 @@ static int __init hp_wmi_init(void)
581 if (wmi_has_guid(HPWMI_EVENT_GUID)) { 584 if (wmi_has_guid(HPWMI_EVENT_GUID)) {
582 err = wmi_install_notify_handler(HPWMI_EVENT_GUID, 585 err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
583 hp_wmi_notify, NULL); 586 hp_wmi_notify, NULL);
584 if (!err) 587 if (ACPI_SUCCESS(err))
585 hp_wmi_input_setup(); 588 hp_wmi_input_setup();
586 } 589 }
587 590
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index 7f77f908bb0..f5f70d4c691 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -149,8 +149,13 @@ static void msi_wmi_notify(u32 value, void *context)
149 static struct key_entry *key; 149 static struct key_entry *key;
150 union acpi_object *obj; 150 union acpi_object *obj;
151 ktime_t cur; 151 ktime_t cur;
152 acpi_status status;
152 153
153 wmi_get_event_data(value, &response); 154 status = wmi_get_event_data(value, &response);
155 if (status != AE_OK) {
156 printk(KERN_INFO DRV_PFX "bad event status 0x%x\n", status);
157 return;
158 }
154 159
155 obj = (union acpi_object *)response.pointer; 160 obj = (union acpi_object *)response.pointer;
156 161
@@ -236,7 +241,7 @@ static int __init msi_wmi_init(void)
236 } 241 }
237 err = wmi_install_notify_handler(MSIWMI_EVENT_GUID, 242 err = wmi_install_notify_handler(MSIWMI_EVENT_GUID,
238 msi_wmi_notify, NULL); 243 msi_wmi_notify, NULL);
239 if (err) 244 if (ACPI_FAILURE(err))
240 return -EINVAL; 245 return -EINVAL;
241 246
242 err = msi_wmi_input_setup(); 247 err = msi_wmi_input_setup();
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 5af53340da6..3f71a605a49 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1201,9 +1201,12 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
1201 /* the buffer is filled with magic numbers describing the devices 1201 /* the buffer is filled with magic numbers describing the devices
1202 * available, 0xff terminates the enumeration 1202 * available, 0xff terminates the enumeration
1203 */ 1203 */
1204 while ((dev_code = *(device_enum->buffer.pointer + i)) != 0xff && 1204 for (i = 0; i < device_enum->buffer.length; i++) {
1205 i < device_enum->buffer.length) { 1205
1206 i++; 1206 dev_code = *(device_enum->buffer.pointer + i);
1207 if (dev_code == 0xff)
1208 break;
1209
1207 dprintk("Radio devices, looking at 0x%.2x\n", dev_code); 1210 dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
1208 1211
1209 if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI]) 1212 if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 448c8aeb166..e67e4feb35c 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -6384,11 +6384,13 @@ static struct ibm_struct brightness_driver_data = {
6384 * and we leave them unchanged. 6384 * and we leave them unchanged.
6385 */ 6385 */
6386 6386
6387#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
6388
6387#define TPACPI_ALSA_DRVNAME "ThinkPad EC" 6389#define TPACPI_ALSA_DRVNAME "ThinkPad EC"
6388#define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control" 6390#define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control"
6389#define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME 6391#define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME
6390 6392
6391static int alsa_index = SNDRV_DEFAULT_IDX1; 6393static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */
6392static char *alsa_id = "ThinkPadEC"; 6394static char *alsa_id = "ThinkPadEC";
6393static int alsa_enable = SNDRV_DEFAULT_ENABLE1; 6395static int alsa_enable = SNDRV_DEFAULT_ENABLE1;
6394 6396
@@ -6705,10 +6707,11 @@ static int __init volume_create_alsa_mixer(void)
6705 6707
6706 rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE, 6708 rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE,
6707 sizeof(struct tpacpi_alsa_data), &card); 6709 sizeof(struct tpacpi_alsa_data), &card);
6708 if (rc < 0) 6710 if (rc < 0 || !card) {
6709 return rc; 6711 printk(TPACPI_ERR
6710 if (!card) 6712 "Failed to create ALSA card structures: %d\n", rc);
6711 return -ENOMEM; 6713 return 1;
6714 }
6712 6715
6713 BUG_ON(!card->private_data); 6716 BUG_ON(!card->private_data);
6714 data = card->private_data; 6717 data = card->private_data;
@@ -6741,8 +6744,9 @@ static int __init volume_create_alsa_mixer(void)
6741 rc = snd_ctl_add(card, ctl_vol); 6744 rc = snd_ctl_add(card, ctl_vol);
6742 if (rc < 0) { 6745 if (rc < 0) {
6743 printk(TPACPI_ERR 6746 printk(TPACPI_ERR
6744 "Failed to create ALSA volume control\n"); 6747 "Failed to create ALSA volume control: %d\n",
6745 goto err_out; 6748 rc);
6749 goto err_exit;
6746 } 6750 }
6747 data->ctl_vol_id = &ctl_vol->id; 6751 data->ctl_vol_id = &ctl_vol->id;
6748 } 6752 }
@@ -6750,22 +6754,25 @@ static int __init volume_create_alsa_mixer(void)
6750 ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL); 6754 ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL);
6751 rc = snd_ctl_add(card, ctl_mute); 6755 rc = snd_ctl_add(card, ctl_mute);
6752 if (rc < 0) { 6756 if (rc < 0) {
6753 printk(TPACPI_ERR "Failed to create ALSA mute control\n"); 6757 printk(TPACPI_ERR "Failed to create ALSA mute control: %d\n",
6754 goto err_out; 6758 rc);
6759 goto err_exit;
6755 } 6760 }
6756 data->ctl_mute_id = &ctl_mute->id; 6761 data->ctl_mute_id = &ctl_mute->id;
6757 6762
6758 snd_card_set_dev(card, &tpacpi_pdev->dev); 6763 snd_card_set_dev(card, &tpacpi_pdev->dev);
6759 rc = snd_card_register(card); 6764 rc = snd_card_register(card);
6760
6761err_out:
6762 if (rc < 0) { 6765 if (rc < 0) {
6763 snd_card_free(card); 6766 printk(TPACPI_ERR "Failed to register ALSA card: %d\n", rc);
6764 card = NULL; 6767 goto err_exit;
6765 } 6768 }
6766 6769
6767 alsa_card = card; 6770 alsa_card = card;
6768 return rc; 6771 return 0;
6772
6773err_exit:
6774 snd_card_free(card);
6775 return 1;
6769} 6776}
6770 6777
6771#define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */ 6778#define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */
@@ -7016,6 +7023,28 @@ static struct ibm_struct volume_driver_data = {
7016 .shutdown = volume_shutdown, 7023 .shutdown = volume_shutdown,
7017}; 7024};
7018 7025
7026#else /* !CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
7027
7028#define alsa_card NULL
7029
7030static void inline volume_alsa_notify_change(void)
7031{
7032}
7033
7034static int __init volume_init(struct ibm_init_struct *iibm)
7035{
7036 printk(TPACPI_INFO
7037 "volume: disabled as there is no ALSA support in this kernel\n");
7038
7039 return 1;
7040}
7041
7042static struct ibm_struct volume_driver_data = {
7043 .name = "volume",
7044};
7045
7046#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
7047
7019/************************************************************************* 7048/*************************************************************************
7020 * Fan subdriver 7049 * Fan subdriver
7021 */ 7050 */
@@ -8738,6 +8767,7 @@ MODULE_PARM_DESC(hotkey_report_mode,
8738 "used for backwards compatibility with userspace, " 8767 "used for backwards compatibility with userspace, "
8739 "see documentation"); 8768 "see documentation");
8740 8769
8770#ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
8741module_param_named(volume_mode, volume_mode, uint, 0444); 8771module_param_named(volume_mode, volume_mode, uint, 0444);
8742MODULE_PARM_DESC(volume_mode, 8772MODULE_PARM_DESC(volume_mode,
8743 "Selects volume control strategy: " 8773 "Selects volume control strategy: "
@@ -8760,6 +8790,7 @@ module_param_named(id, alsa_id, charp, 0444);
8760MODULE_PARM_DESC(id, "ALSA id for the ACPI EC Mixer"); 8790MODULE_PARM_DESC(id, "ALSA id for the ACPI EC Mixer");
8761module_param_named(enable, alsa_enable, bool, 0444); 8791module_param_named(enable, alsa_enable, bool, 0444);
8762MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer"); 8792MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer");
8793#endif /* CONFIG_THINKPAD_ACPI_ALSA_SUPPORT */
8763 8794
8764#define TPACPI_PARAM(feature) \ 8795#define TPACPI_PARAM(feature) \
8765 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ 8796 module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 9f93d6c0f51..b104302fea0 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -492,8 +492,7 @@ wmi_notify_handler handler, void *data)
492 if (!guid || !handler) 492 if (!guid || !handler)
493 return AE_BAD_PARAMETER; 493 return AE_BAD_PARAMETER;
494 494
495 find_guid(guid, &block); 495 if (!find_guid(guid, &block))
496 if (!block)
497 return AE_NOT_EXIST; 496 return AE_NOT_EXIST;
498 497
499 if (block->handler) 498 if (block->handler)
@@ -521,8 +520,7 @@ acpi_status wmi_remove_notify_handler(const char *guid)
521 if (!guid) 520 if (!guid)
522 return AE_BAD_PARAMETER; 521 return AE_BAD_PARAMETER;
523 522
524 find_guid(guid, &block); 523 if (!find_guid(guid, &block))
525 if (!block)
526 return AE_NOT_EXIST; 524 return AE_NOT_EXIST;
527 525
528 if (!block->handler) 526 if (!block->handler)
@@ -716,6 +714,22 @@ static int wmi_class_init(void)
716 return ret; 714 return ret;
717} 715}
718 716
717static bool guid_already_parsed(const char *guid_string)
718{
719 struct guid_block *gblock;
720 struct wmi_block *wblock;
721 struct list_head *p;
722
723 list_for_each(p, &wmi_blocks.list) {
724 wblock = list_entry(p, struct wmi_block, list);
725 gblock = &wblock->gblock;
726
727 if (strncmp(gblock->guid, guid_string, 16) == 0)
728 return true;
729 }
730 return false;
731}
732
719/* 733/*
720 * Parse the _WDG method for the GUID data blocks 734 * Parse the _WDG method for the GUID data blocks
721 */ 735 */
@@ -725,6 +739,7 @@ static __init acpi_status parse_wdg(acpi_handle handle)
725 union acpi_object *obj; 739 union acpi_object *obj;
726 struct guid_block *gblock; 740 struct guid_block *gblock;
727 struct wmi_block *wblock; 741 struct wmi_block *wblock;
742 char guid_string[37];
728 acpi_status status; 743 acpi_status status;
729 u32 i, total; 744 u32 i, total;
730 745
@@ -747,6 +762,19 @@ static __init acpi_status parse_wdg(acpi_handle handle)
747 memcpy(gblock, obj->buffer.pointer, obj->buffer.length); 762 memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
748 763
749 for (i = 0; i < total; i++) { 764 for (i = 0; i < total; i++) {
765 /*
766 Some WMI devices, like those for nVidia hooks, have a
767 duplicate GUID. It's not clear what we should do in this
768 case yet, so for now, we'll just ignore the duplicate.
769 Anyone who wants to add support for that device can come
770 up with a better workaround for the mess then.
771 */
772 if (guid_already_parsed(gblock[i].guid) == true) {
773 wmi_gtoa(gblock[i].guid, guid_string);
774 printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n",
775 guid_string);
776 continue;
777 }
750 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); 778 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
751 if (!wblock) 779 if (!wblock)
752 return AE_NO_MEMORY; 780 return AE_NO_MEMORY;