]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/platform/x86/eeepc-laptop.c
eeepc-laptop: make fan1_input really read-only
[mirror_ubuntu-hirsute-kernel.git] / drivers / platform / x86 / eeepc-laptop.c
CommitLineData
e59f8796 1/*
a7624b63 2 * eeepc-laptop.c - Asus Eee PC extras
e59f8796
EC
3 *
4 * Based on asus_acpi.c as patched for the Eee PC by Asus:
5 * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar
6 * Based on eee.c from eeepc-linux
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19b53289
JP
19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
e59f8796
EC
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/types.h>
25#include <linux/platform_device.h>
a5fa429b
CC
26#include <linux/backlight.h>
27#include <linux/fb.h>
e1faa9da
CC
28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h>
5a0e3ad6 30#include <linux/slab.h>
8b48463f 31#include <linux/acpi.h>
e59f8796 32#include <linux/uaccess.h>
a195dcdc 33#include <linux/input.h>
642e0447 34#include <linux/input/sparse-keymap.h>
a195dcdc 35#include <linux/rfkill.h>
5740294c 36#include <linux/pci.h>
2b121bc2 37#include <linux/pci_hotplug.h>
3c0eb510 38#include <linux/leds.h>
da8ba01d 39#include <linux/dmi.h>
e59f8796
EC
40
41#define EEEPC_LAPTOP_VERSION "0.1"
a7624b63
AJ
42#define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver"
43#define EEEPC_LAPTOP_FILE "eeepc"
e59f8796 44
a7624b63
AJ
45#define EEEPC_ACPI_CLASS "hotkey"
46#define EEEPC_ACPI_DEVICE_NAME "Hotkey"
47#define EEEPC_ACPI_HID "ASUS010"
e59f8796 48
52bbe3c7 49MODULE_AUTHOR("Corentin Chary, Eric Cooper");
a7624b63 50MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME);
52bbe3c7 51MODULE_LICENSE("GPL");
e59f8796 52
322a1356
CC
53static bool hotplug_disabled;
54
bfa47960 55module_param(hotplug_disabled, bool, 0444);
322a1356
CC
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
e59f8796
EC
61/*
62 * Definitions for Asus EeePC
63 */
a5fa429b
CC
64#define NOTIFY_BRN_MIN 0x20
65#define NOTIFY_BRN_MAX 0x2f
e59f8796
EC
66
67enum {
68 DISABLE_ASL_WLAN = 0x0001,
69 DISABLE_ASL_BLUETOOTH = 0x0002,
70 DISABLE_ASL_IRDA = 0x0004,
71 DISABLE_ASL_CAMERA = 0x0008,
72 DISABLE_ASL_TV = 0x0010,
73 DISABLE_ASL_GPS = 0x0020,
74 DISABLE_ASL_DISPLAYSWITCH = 0x0040,
75 DISABLE_ASL_MODEM = 0x0080,
b7b700d4
CC
76 DISABLE_ASL_CARDREADER = 0x0100,
77 DISABLE_ASL_3G = 0x0200,
78 DISABLE_ASL_WIMAX = 0x0400,
79 DISABLE_ASL_HWCF = 0x0800
e59f8796
EC
80};
81
82enum {
83 CM_ASL_WLAN = 0,
84 CM_ASL_BLUETOOTH,
85 CM_ASL_IRDA,
86 CM_ASL_1394,
87 CM_ASL_CAMERA,
88 CM_ASL_TV,
89 CM_ASL_GPS,
90 CM_ASL_DVDROM,
91 CM_ASL_DISPLAYSWITCH,
92 CM_ASL_PANELBRIGHT,
93 CM_ASL_BIOSFLASH,
94 CM_ASL_ACPIFLASH,
95 CM_ASL_CPUFV,
96 CM_ASL_CPUTEMPERATURE,
97 CM_ASL_FANCPU,
98 CM_ASL_FANCHASSIS,
99 CM_ASL_USBPORT1,
100 CM_ASL_USBPORT2,
101 CM_ASL_USBPORT3,
102 CM_ASL_MODEM,
103 CM_ASL_CARDREADER,
b7b700d4
CC
104 CM_ASL_3G,
105 CM_ASL_WIMAX,
106 CM_ASL_HWCF,
107 CM_ASL_LID,
108 CM_ASL_TYPE,
109 CM_ASL_PANELPOWER, /*P901*/
110 CM_ASL_TPD
e59f8796
EC
111};
112
14109461 113static const char *cm_getv[] = {
3af9bfcb 114 "WLDG", "BTHG", NULL, NULL,
e59f8796
EC
115 "CAMG", NULL, NULL, NULL,
116 NULL, "PBLG", NULL, NULL,
117 "CFVG", NULL, NULL, NULL,
118 "USBG", NULL, NULL, "MODG",
b7b700d4
CC
119 "CRDG", "M3GG", "WIMG", "HWCF",
120 "LIDG", "TYPE", "PBPG", "TPDG"
e59f8796
EC
121};
122
14109461 123static const char *cm_setv[] = {
3af9bfcb 124 "WLDS", "BTHS", NULL, NULL,
e59f8796
EC
125 "CAMS", NULL, NULL, NULL,
126 "SDSP", "PBLS", "HDPS", NULL,
127 "CFVS", NULL, NULL, NULL,
128 "USBG", NULL, NULL, "MODS",
b7b700d4
CC
129 "CRDS", "M3GS", "WIMS", NULL,
130 NULL, NULL, "PBPS", "TPDS"
e59f8796
EC
131};
132
854c7836 133static const struct key_entry eeepc_keymap[] = {
642e0447
DT
134 { KE_KEY, 0x10, { KEY_WLAN } },
135 { KE_KEY, 0x11, { KEY_WLAN } },
136 { KE_KEY, 0x12, { KEY_PROG1 } },
137 { KE_KEY, 0x13, { KEY_MUTE } },
138 { KE_KEY, 0x14, { KEY_VOLUMEDOWN } },
139 { KE_KEY, 0x15, { KEY_VOLUMEUP } },
140 { KE_KEY, 0x16, { KEY_DISPLAY_OFF } },
141 { KE_KEY, 0x1a, { KEY_COFFEE } },
142 { KE_KEY, 0x1b, { KEY_ZOOM } },
143 { KE_KEY, 0x1c, { KEY_PROG2 } },
144 { KE_KEY, 0x1d, { KEY_PROG3 } },
145 { KE_KEY, NOTIFY_BRN_MIN, { KEY_BRIGHTNESSDOWN } },
146 { KE_KEY, NOTIFY_BRN_MAX, { KEY_BRIGHTNESSUP } },
147 { KE_KEY, 0x30, { KEY_SWITCHVIDEOMODE } },
148 { KE_KEY, 0x31, { KEY_SWITCHVIDEOMODE } },
149 { KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } },
150 { KE_KEY, 0x37, { KEY_F13 } }, /* Disable Touchpad */
151 { KE_KEY, 0x38, { KEY_F14 } },
152 { KE_END, 0 },
a195dcdc
MG
153};
154
e59f8796 155/*
52bbe3c7 156 * This is the main structure, we can use it to store useful information
e59f8796 157 */
a7624b63 158struct eeepc_laptop {
854c7836 159 acpi_handle handle; /* the handle of the acpi device */
52bbe3c7
AJ
160 u32 cm_supported; /* the control methods supported
161 by this BIOS */
da8ba01d 162 bool cpufv_disabled;
10ae4b56 163 bool hotplug_disabled;
52bbe3c7 164 u16 event_count[128]; /* count for each event */
e59f8796 165
854c7836 166 struct platform_device *platform_device;
71e687dc 167 struct acpi_device *device; /* the device we are in */
854c7836 168 struct backlight_device *backlight_device;
2b121bc2 169
52bbe3c7 170 struct input_dev *inputdev;
2b121bc2 171
52bbe3c7
AJ
172 struct rfkill *wlan_rfkill;
173 struct rfkill *bluetooth_rfkill;
174 struct rfkill *wwan3g_rfkill;
175 struct rfkill *wimax_rfkill;
a5fa429b 176
52bbe3c7
AJ
177 struct hotplug_slot *hotplug_slot;
178 struct mutex hotplug_lock;
e1faa9da 179
854c7836
AJ
180 struct led_classdev tpd_led;
181 int tpd_led_wk;
182 struct workqueue_struct *led_workqueue;
183 struct work_struct tpd_led_work;
a5fa429b
CC
184};
185
e59f8796
EC
186/*
187 * ACPI Helpers
188 */
6b188a7b 189static int write_acpi_int(acpi_handle handle, const char *method, int val)
e59f8796 190{
e59f8796
EC
191 acpi_status status;
192
fca41991 193 status = acpi_execute_simple_method(handle, (char *)method, val);
e59f8796 194
e59f8796
EC
195 return (status == AE_OK ? 0 : -1);
196}
197
198static int read_acpi_int(acpi_handle handle, const char *method, int *val)
199{
200 acpi_status status;
27663c58 201 unsigned long long result;
e59f8796
EC
202
203 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
204 if (ACPI_FAILURE(status)) {
205 *val = -1;
206 return -1;
207 } else {
208 *val = result;
209 return 0;
210 }
211}
212
854c7836 213static int set_acpi(struct eeepc_laptop *eeepc, int cm, int value)
e59f8796 214{
13f70029 215 const char *method = cm_setv[cm];
e59f8796 216
13f70029
AJ
217 if (method == NULL)
218 return -ENODEV;
a7624b63 219 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
13f70029 220 return -ENODEV;
a5fa429b 221
a7624b63 222 if (write_acpi_int(eeepc->handle, method, value))
22441ffe 223 pr_warn("Error writing %s\n", method);
e59f8796 224 return 0;
a5fa429b
CC
225}
226
854c7836 227static int get_acpi(struct eeepc_laptop *eeepc, int cm)
a5fa429b 228{
13f70029
AJ
229 const char *method = cm_getv[cm];
230 int value;
a5fa429b 231
13f70029
AJ
232 if (method == NULL)
233 return -ENODEV;
a7624b63 234 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
13f70029 235 return -ENODEV;
a195dcdc 236
a7624b63 237 if (read_acpi_int(eeepc->handle, method, &value))
22441ffe 238 pr_warn("Error reading %s\n", method);
e59f8796 239 return value;
a195dcdc
MG
240}
241
f90be874
CC
242static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm,
243 acpi_handle *handle)
a195dcdc 244{
854c7836
AJ
245 const char *method = cm_setv[cm];
246 acpi_status status;
a195dcdc 247
854c7836
AJ
248 if (method == NULL)
249 return -ENODEV;
250 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
251 return -ENODEV;
a195dcdc 252
854c7836 253 status = acpi_get_handle(eeepc->handle, (char *)method,
f90be874 254 handle);
854c7836 255 if (status != AE_OK) {
22441ffe 256 pr_warn("Error finding %s\n", method);
854c7836
AJ
257 return -ENODEV;
258 }
259 return 0;
cede2cb6
PE
260}
261
854c7836 262
e59f8796
EC
263/*
264 * Sys helpers
265 */
95369a73 266static int parse_arg(const char *buf, int *val)
e59f8796 267{
e59f8796
EC
268 if (sscanf(buf, "%i", val) != 1)
269 return -EINVAL;
95369a73 270 return 0;
e59f8796
EC
271}
272
854c7836
AJ
273static ssize_t store_sys_acpi(struct device *dev, int cm,
274 const char *buf, size_t count)
e59f8796 275{
854c7836 276 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
e59f8796
EC
277 int rv, value;
278
95369a73
PB
279 rv = parse_arg(buf, &value);
280 if (rv < 0)
281 return rv;
282 rv = set_acpi(eeepc, cm, value);
283 if (rv < 0)
6dff29b6 284 return -EIO;
95369a73 285 return count;
e59f8796
EC
286}
287
854c7836 288static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf)
e59f8796 289{
854c7836
AJ
290 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
291 int value = get_acpi(eeepc, cm);
f36509e7
CC
292
293 if (value < 0)
6dff29b6 294 return -EIO;
f36509e7 295 return sprintf(buf, "%d\n", value);
e59f8796
EC
296}
297
97971325 298#define EEEPC_ACPI_SHOW_FUNC(_name, _cm) \
8c72fc8b 299 static ssize_t _name##_show(struct device *dev, \
e59f8796
EC
300 struct device_attribute *attr, \
301 char *buf) \
302 { \
854c7836 303 return show_sys_acpi(dev, _cm, buf); \
97971325
FK
304 }
305
306#define EEEPC_ACPI_STORE_FUNC(_name, _cm) \
8c72fc8b 307 static ssize_t _name##_store(struct device *dev, \
e59f8796
EC
308 struct device_attribute *attr, \
309 const char *buf, size_t count) \
310 { \
854c7836 311 return store_sys_acpi(dev, _cm, buf, count); \
97971325
FK
312 }
313
6fe3a77f 314#define EEEPC_CREATE_DEVICE_ATTR_RW(_name, _cm) \
97971325
FK
315 EEEPC_ACPI_SHOW_FUNC(_name, _cm) \
316 EEEPC_ACPI_STORE_FUNC(_name, _cm) \
6fe3a77f 317 static DEVICE_ATTR_RW(_name)
e59f8796 318
6fe3a77f
FK
319#define EEEPC_CREATE_DEVICE_ATTR_WO(_name, _cm) \
320 EEEPC_ACPI_STORE_FUNC(_name, _cm) \
321 static DEVICE_ATTR_WO(_name)
322
323EEEPC_CREATE_DEVICE_ATTR_RW(camera, CM_ASL_CAMERA);
324EEEPC_CREATE_DEVICE_ATTR_RW(cardr, CM_ASL_CARDREADER);
325EEEPC_CREATE_DEVICE_ATTR_WO(disp, CM_ASL_DISPLAYSWITCH);
b31d0fde
CC
326
327struct eeepc_cpufv {
328 int num;
329 int cur;
330};
331
854c7836 332static int get_cpufv(struct eeepc_laptop *eeepc, struct eeepc_cpufv *c)
b31d0fde 333{
854c7836 334 c->cur = get_acpi(eeepc, CM_ASL_CPUFV);
b31d0fde
CC
335 c->num = (c->cur >> 8) & 0xff;
336 c->cur &= 0xff;
337 if (c->cur < 0 || c->num <= 0 || c->num > 12)
338 return -ENODEV;
339 return 0;
340}
341
8c72fc8b 342static ssize_t available_cpufv_show(struct device *dev,
b31d0fde
CC
343 struct device_attribute *attr,
344 char *buf)
345{
854c7836 346 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
b31d0fde
CC
347 struct eeepc_cpufv c;
348 int i;
349 ssize_t len = 0;
350
854c7836 351 if (get_cpufv(eeepc, &c))
b31d0fde
CC
352 return -ENODEV;
353 for (i = 0; i < c.num; i++)
354 len += sprintf(buf + len, "%d ", i);
355 len += sprintf(buf + len, "\n");
356 return len;
357}
358
8c72fc8b 359static ssize_t cpufv_show(struct device *dev,
b31d0fde
CC
360 struct device_attribute *attr,
361 char *buf)
362{
854c7836 363 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
b31d0fde
CC
364 struct eeepc_cpufv c;
365
854c7836 366 if (get_cpufv(eeepc, &c))
b31d0fde
CC
367 return -ENODEV;
368 return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);
369}
370
8c72fc8b 371static ssize_t cpufv_store(struct device *dev,
b31d0fde
CC
372 struct device_attribute *attr,
373 const char *buf, size_t count)
374{
854c7836 375 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
b31d0fde
CC
376 struct eeepc_cpufv c;
377 int rv, value;
378
da8ba01d
AJ
379 if (eeepc->cpufv_disabled)
380 return -EPERM;
854c7836 381 if (get_cpufv(eeepc, &c))
b31d0fde 382 return -ENODEV;
95369a73 383 rv = parse_arg(buf, &value);
b31d0fde
CC
384 if (rv < 0)
385 return rv;
95369a73 386 if (value < 0 || value >= c.num)
b31d0fde 387 return -EINVAL;
854c7836 388 set_acpi(eeepc, CM_ASL_CPUFV, value);
95369a73 389 return count;
b31d0fde
CC
390}
391
8c72fc8b 392static ssize_t cpufv_disabled_show(struct device *dev,
da8ba01d
AJ
393 struct device_attribute *attr,
394 char *buf)
395{
396 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
397
398 return sprintf(buf, "%d\n", eeepc->cpufv_disabled);
399}
400
8c72fc8b 401static ssize_t cpufv_disabled_store(struct device *dev,
da8ba01d
AJ
402 struct device_attribute *attr,
403 const char *buf, size_t count)
404{
405 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
406 int rv, value;
407
95369a73 408 rv = parse_arg(buf, &value);
da8ba01d
AJ
409 if (rv < 0)
410 return rv;
411
412 switch (value) {
413 case 0:
414 if (eeepc->cpufv_disabled)
22441ffe 415 pr_warn("cpufv enabled (not officially supported "
da8ba01d
AJ
416 "on this model)\n");
417 eeepc->cpufv_disabled = false;
95369a73 418 return count;
da8ba01d
AJ
419 case 1:
420 return -EPERM;
421 default:
422 return -EINVAL;
423 }
424}
425
426
bb382dba
FK
427static DEVICE_ATTR_RW(cpufv);
428static DEVICE_ATTR_RO(available_cpufv);
429static DEVICE_ATTR_RW(cpufv_disabled);
da8ba01d 430
e59f8796
EC
431static struct attribute *platform_attributes[] = {
432 &dev_attr_camera.attr,
433 &dev_attr_cardr.attr,
434 &dev_attr_disp.attr,
158ca1d7 435 &dev_attr_cpufv.attr,
b31d0fde 436 &dev_attr_available_cpufv.attr,
da8ba01d 437 &dev_attr_cpufv_disabled.attr,
e59f8796
EC
438 NULL
439};
440
441static struct attribute_group platform_attribute_group = {
442 .attrs = platform_attributes
443};
444
854c7836 445static int eeepc_platform_init(struct eeepc_laptop *eeepc)
a195dcdc 446{
9db106be 447 int result;
a195dcdc 448
854c7836
AJ
449 eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, -1);
450 if (!eeepc->platform_device)
9db106be 451 return -ENOMEM;
854c7836 452 platform_set_drvdata(eeepc->platform_device, eeepc);
a195dcdc 453
854c7836 454 result = platform_device_add(eeepc->platform_device);
9db106be
AJ
455 if (result)
456 goto fail_platform_device;
a195dcdc 457
854c7836 458 result = sysfs_create_group(&eeepc->platform_device->dev.kobj,
9db106be
AJ
459 &platform_attribute_group);
460 if (result)
461 goto fail_sysfs;
462 return 0;
a195dcdc 463
9db106be 464fail_sysfs:
854c7836 465 platform_device_del(eeepc->platform_device);
9db106be 466fail_platform_device:
854c7836 467 platform_device_put(eeepc->platform_device);
9db106be 468 return result;
a195dcdc
MG
469}
470
854c7836 471static void eeepc_platform_exit(struct eeepc_laptop *eeepc)
a195dcdc 472{
854c7836 473 sysfs_remove_group(&eeepc->platform_device->dev.kobj,
9db106be 474 &platform_attribute_group);
854c7836 475 platform_device_unregister(eeepc->platform_device);
9db106be 476}
a195dcdc 477
3c0eb510
CC
478/*
479 * LEDs
480 */
481/*
482 * These functions actually update the LED's, and are called from a
483 * workqueue. By doing this as separate work rather than when the LED
484 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
485 * potentially bad time, such as a timer interrupt.
486 */
854c7836
AJ
487static void tpd_led_update(struct work_struct *work)
488 {
489 struct eeepc_laptop *eeepc;
a195dcdc 490
854c7836 491 eeepc = container_of(work, struct eeepc_laptop, tpd_led_work);
3c0eb510 492
854c7836 493 set_acpi(eeepc, CM_ASL_TPD, eeepc->tpd_led_wk);
a195dcdc
MG
494}
495
3c0eb510
CC
496static void tpd_led_set(struct led_classdev *led_cdev,
497 enum led_brightness value)
a195dcdc 498{
854c7836 499 struct eeepc_laptop *eeepc;
a195dcdc 500
854c7836 501 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
a195dcdc 502
854c7836
AJ
503 eeepc->tpd_led_wk = (value > 0) ? 1 : 0;
504 queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
a195dcdc
MG
505}
506
62a75d83
CC
507static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
508{
509 struct eeepc_laptop *eeepc;
510
511 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
512
513 return get_acpi(eeepc, CM_ASL_TPD);
514}
515
854c7836 516static int eeepc_led_init(struct eeepc_laptop *eeepc)
dbfa3ba9 517{
52bbe3c7 518 int rv;
dbfa3ba9 519
854c7836 520 if (get_acpi(eeepc, CM_ASL_TPD) == -ENODEV)
52bbe3c7 521 return 0;
dbfa3ba9 522
854c7836
AJ
523 eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
524 if (!eeepc->led_workqueue)
52bbe3c7 525 return -ENOMEM;
854c7836 526 INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
dbfa3ba9 527
854c7836
AJ
528 eeepc->tpd_led.name = "eeepc::touchpad";
529 eeepc->tpd_led.brightness_set = tpd_led_set;
62a75d83 530 if (get_acpi(eeepc, CM_ASL_TPD) >= 0) /* if method is available */
39a3e17e 531 eeepc->tpd_led.brightness_get = tpd_led_get;
854c7836 532 eeepc->tpd_led.max_brightness = 1;
e59f8796 533
854c7836
AJ
534 rv = led_classdev_register(&eeepc->platform_device->dev,
535 &eeepc->tpd_led);
52bbe3c7 536 if (rv) {
854c7836 537 destroy_workqueue(eeepc->led_workqueue);
52bbe3c7 538 return rv;
e59f8796 539 }
a195dcdc 540
e59f8796
EC
541 return 0;
542}
543
854c7836 544static void eeepc_led_exit(struct eeepc_laptop *eeepc)
a5fa429b 545{
5d6afd15 546 if (!IS_ERR_OR_NULL(eeepc->tpd_led.dev))
854c7836
AJ
547 led_classdev_unregister(&eeepc->tpd_led);
548 if (eeepc->led_workqueue)
549 destroy_workqueue(eeepc->led_workqueue);
a5fa429b
CC
550}
551
2b121bc2 552
52bbe3c7
AJ
553/*
554 * PCI hotplug (for wlan rfkill)
555 */
854c7836 556static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc)
52bbe3c7 557{
854c7836 558 if (get_acpi(eeepc, CM_ASL_WLAN) == 1)
52bbe3c7
AJ
559 return false;
560 return true;
2b121bc2
CC
561}
562
14fdb152 563static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
5740294c 564{
14fdb152 565 struct pci_dev *port;
5740294c 566 struct pci_dev *dev;
6d41839e 567 struct pci_bus *bus;
854c7836 568 bool blocked = eeepc_wlan_rfkill_blocked(eeepc);
bc9d24a3
AJ
569 bool absent;
570 u32 l;
5740294c 571
a7624b63
AJ
572 if (eeepc->wlan_rfkill)
573 rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);
6d41839e 574
a7624b63 575 mutex_lock(&eeepc->hotplug_lock);
8b9ec1da 576 pci_lock_rescan_remove();
dcf443b5 577
a7624b63 578 if (eeepc->hotplug_slot) {
14fdb152
MG
579 port = acpi_get_pci_dev(handle);
580 if (!port) {
581 pr_warning("Unable to find port\n");
582 goto out_unlock;
583 }
584
585 bus = port->subordinate;
586
07e84aa9 587 if (!bus) {
22441ffe 588 pr_warn("Unable to find PCI bus 1?\n");
f661848b 589 goto out_put_dev;
5740294c 590 }
07e84aa9 591
bc9d24a3
AJ
592 if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
593 pr_err("Unable to read PCI config space?\n");
f661848b 594 goto out_put_dev;
bc9d24a3 595 }
14fdb152 596
bc9d24a3
AJ
597 absent = (l == 0xffffffff);
598
599 if (blocked != absent) {
22441ffe
JP
600 pr_warn("BIOS says wireless lan is %s, "
601 "but the pci device is %s\n",
bc9d24a3
AJ
602 blocked ? "blocked" : "unblocked",
603 absent ? "absent" : "present");
22441ffe
JP
604 pr_warn("skipped wireless hotplug as probably "
605 "inappropriate for this model\n");
f661848b 606 goto out_put_dev;
bc9d24a3
AJ
607 }
608
07e84aa9
AJ
609 if (!blocked) {
610 dev = pci_get_slot(bus, 0);
611 if (dev) {
612 /* Device already present */
613 pci_dev_put(dev);
f661848b 614 goto out_put_dev;
07e84aa9
AJ
615 }
616 dev = pci_scan_single_device(bus, 0);
617 if (dev) {
618 pci_bus_assign_resources(bus);
c893d133 619 pci_bus_add_device(dev);
07e84aa9
AJ
620 }
621 } else {
622 dev = pci_get_slot(bus, 0);
623 if (dev) {
210647af 624 pci_stop_and_remove_bus_device(dev);
07e84aa9
AJ
625 pci_dev_put(dev);
626 }
5740294c 627 }
f661848b
JL
628out_put_dev:
629 pci_dev_put(port);
5740294c 630 }
dcf443b5
AJ
631
632out_unlock:
8b9ec1da 633 pci_unlock_rescan_remove();
a7624b63 634 mutex_unlock(&eeepc->hotplug_lock);
5740294c
MG
635}
636
14fdb152
MG
637static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node)
638{
639 acpi_status status = AE_OK;
640 acpi_handle handle;
641
642 status = acpi_get_handle(NULL, node, &handle);
643
644 if (ACPI_SUCCESS(status))
645 eeepc_rfkill_hotplug(eeepc, handle);
646}
647
96e9cfeb
AJ
648static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
649{
854c7836
AJ
650 struct eeepc_laptop *eeepc = data;
651
96e9cfeb
AJ
652 if (event != ACPI_NOTIFY_BUS_CHECK)
653 return;
654
14fdb152 655 eeepc_rfkill_hotplug(eeepc, handle);
e59f8796
EC
656}
657
854c7836
AJ
658static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,
659 char *node)
5740294c 660{
854c7836 661 acpi_status status;
5740294c
MG
662 acpi_handle handle;
663
664 status = acpi_get_handle(NULL, node, &handle);
665
666 if (ACPI_SUCCESS(status)) {
667 status = acpi_install_notify_handler(handle,
668 ACPI_SYSTEM_NOTIFY,
669 eeepc_rfkill_notify,
854c7836 670 eeepc);
5740294c 671 if (ACPI_FAILURE(status))
22441ffe
JP
672 pr_warn("Failed to register notify on %s\n", node);
673
14fdb152
MG
674 /*
675 * Refresh pci hotplug in case the rfkill state was
676 * changed during setup.
677 */
678 eeepc_rfkill_hotplug(eeepc, handle);
39a3e17e 679 } else {
5740294c 680 return -ENODEV;
39a3e17e 681 }
5740294c
MG
682
683 return 0;
684}
685
854c7836
AJ
686static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc,
687 char *node)
5740294c
MG
688{
689 acpi_status status = AE_OK;
690 acpi_handle handle;
691
692 status = acpi_get_handle(NULL, node, &handle);
693
694 if (ACPI_SUCCESS(status)) {
695 status = acpi_remove_notify_handler(handle,
696 ACPI_SYSTEM_NOTIFY,
697 eeepc_rfkill_notify);
698 if (ACPI_FAILURE(status))
19b53289 699 pr_err("Error removing rfkill notify handler %s\n",
5740294c 700 node);
14fdb152
MG
701 /*
702 * Refresh pci hotplug in case the rfkill
703 * state was changed after
704 * eeepc_unregister_rfkill_notifier()
705 */
706 eeepc_rfkill_hotplug(eeepc, handle);
5740294c
MG
707 }
708}
709
52bbe3c7
AJ
710static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
711 u8 *value)
712{
854c7836
AJ
713 struct eeepc_laptop *eeepc = hotplug_slot->private;
714 int val = get_acpi(eeepc, CM_ASL_WLAN);
52bbe3c7
AJ
715
716 if (val == 1 || val == 0)
717 *value = val;
718 else
719 return -EINVAL;
720
721 return 0;
722}
723
2b121bc2
CC
724static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
725{
726 kfree(hotplug_slot->info);
727 kfree(hotplug_slot);
728}
729
52bbe3c7
AJ
730static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
731 .owner = THIS_MODULE,
732 .get_adapter_status = eeepc_get_adapter_status,
733 .get_power_status = eeepc_get_adapter_status,
734};
735
854c7836 736static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc)
2b121bc2
CC
737{
738 int ret = -ENOMEM;
739 struct pci_bus *bus = pci_find_bus(0, 1);
740
741 if (!bus) {
19b53289 742 pr_err("Unable to find wifi PCI bus\n");
2b121bc2
CC
743 return -ENODEV;
744 }
745
a7624b63
AJ
746 eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
747 if (!eeepc->hotplug_slot)
2b121bc2
CC
748 goto error_slot;
749
a7624b63 750 eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
2b121bc2 751 GFP_KERNEL);
a7624b63 752 if (!eeepc->hotplug_slot->info)
2b121bc2
CC
753 goto error_info;
754
a7624b63
AJ
755 eeepc->hotplug_slot->private = eeepc;
756 eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
757 eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
758 eeepc_get_adapter_status(eeepc->hotplug_slot,
759 &eeepc->hotplug_slot->info->adapter_status);
2b121bc2 760
a7624b63 761 ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi");
2b121bc2 762 if (ret) {
19b53289 763 pr_err("Unable to register hotplug slot - %d\n", ret);
2b121bc2
CC
764 goto error_register;
765 }
766
767 return 0;
768
769error_register:
a7624b63 770 kfree(eeepc->hotplug_slot->info);
2b121bc2 771error_info:
a7624b63
AJ
772 kfree(eeepc->hotplug_slot);
773 eeepc->hotplug_slot = NULL;
2b121bc2
CC
774error_slot:
775 return ret;
776}
777
52bbe3c7
AJ
778/*
779 * Rfkill devices
780 */
781static int eeepc_rfkill_set(void *data, bool blocked)
96e9cfeb 782{
854c7836 783 acpi_handle handle = data;
c200da5d 784
854c7836 785 return write_acpi_int(handle, NULL, !blocked);
c200da5d 786}
96e9cfeb 787
52bbe3c7
AJ
788static const struct rfkill_ops eeepc_rfkill_ops = {
789 .set_block = eeepc_rfkill_set,
790};
791
854c7836
AJ
792static int eeepc_new_rfkill(struct eeepc_laptop *eeepc,
793 struct rfkill **rfkill,
794 const char *name,
52bbe3c7
AJ
795 enum rfkill_type type, int cm)
796{
854c7836 797 acpi_handle handle;
52bbe3c7
AJ
798 int result;
799
854c7836 800 result = acpi_setter_handle(eeepc, cm, &handle);
52bbe3c7
AJ
801 if (result < 0)
802 return result;
803
854c7836
AJ
804 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
805 &eeepc_rfkill_ops, handle);
96e9cfeb 806
52bbe3c7
AJ
807 if (!*rfkill)
808 return -EINVAL;
809
854c7836 810 rfkill_init_sw_state(*rfkill, get_acpi(eeepc, cm) != 1);
52bbe3c7
AJ
811 result = rfkill_register(*rfkill);
812 if (result) {
813 rfkill_destroy(*rfkill);
814 *rfkill = NULL;
815 return result;
816 }
96e9cfeb
AJ
817 return 0;
818}
819
854c7836 820static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc)
52bbe3c7 821{
854c7836
AJ
822 eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5");
823 eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6");
824 eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7");
a7624b63
AJ
825 if (eeepc->wlan_rfkill) {
826 rfkill_unregister(eeepc->wlan_rfkill);
827 rfkill_destroy(eeepc->wlan_rfkill);
828 eeepc->wlan_rfkill = NULL;
52bbe3c7 829 }
14fdb152 830
a7624b63
AJ
831 if (eeepc->hotplug_slot)
832 pci_hp_deregister(eeepc->hotplug_slot);
52bbe3c7 833
a7624b63
AJ
834 if (eeepc->bluetooth_rfkill) {
835 rfkill_unregister(eeepc->bluetooth_rfkill);
836 rfkill_destroy(eeepc->bluetooth_rfkill);
837 eeepc->bluetooth_rfkill = NULL;
52bbe3c7 838 }
a7624b63
AJ
839 if (eeepc->wwan3g_rfkill) {
840 rfkill_unregister(eeepc->wwan3g_rfkill);
841 rfkill_destroy(eeepc->wwan3g_rfkill);
842 eeepc->wwan3g_rfkill = NULL;
52bbe3c7 843 }
a7624b63
AJ
844 if (eeepc->wimax_rfkill) {
845 rfkill_unregister(eeepc->wimax_rfkill);
846 rfkill_destroy(eeepc->wimax_rfkill);
847 eeepc->wimax_rfkill = NULL;
52bbe3c7
AJ
848 }
849}
850
854c7836 851static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)
52bbe3c7
AJ
852{
853 int result = 0;
854
a7624b63 855 mutex_init(&eeepc->hotplug_lock);
52bbe3c7 856
854c7836
AJ
857 result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
858 "eeepc-wlan", RFKILL_TYPE_WLAN,
859 CM_ASL_WLAN);
52bbe3c7
AJ
860
861 if (result && result != -ENODEV)
862 goto exit;
863
854c7836
AJ
864 result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
865 "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
866 CM_ASL_BLUETOOTH);
52bbe3c7
AJ
867
868 if (result && result != -ENODEV)
869 goto exit;
870
854c7836
AJ
871 result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
872 "eeepc-wwan3g", RFKILL_TYPE_WWAN,
873 CM_ASL_3G);
52bbe3c7
AJ
874
875 if (result && result != -ENODEV)
876 goto exit;
877
854c7836
AJ
878 result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill,
879 "eeepc-wimax", RFKILL_TYPE_WIMAX,
880 CM_ASL_WIMAX);
52bbe3c7
AJ
881
882 if (result && result != -ENODEV)
883 goto exit;
884
10ae4b56
CC
885 if (eeepc->hotplug_disabled)
886 return 0;
887
854c7836 888 result = eeepc_setup_pci_hotplug(eeepc);
52bbe3c7
AJ
889 /*
890 * If we get -EBUSY then something else is handling the PCI hotplug -
891 * don't fail in this case
892 */
893 if (result == -EBUSY)
894 result = 0;
895
854c7836
AJ
896 eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5");
897 eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6");
898 eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7");
52bbe3c7
AJ
899
900exit:
901 if (result && result != -ENODEV)
854c7836 902 eeepc_rfkill_exit(eeepc);
52bbe3c7
AJ
903 return result;
904}
905
e1faa9da 906/*
52bbe3c7 907 * Platform driver - hibernate/resume callbacks
e1faa9da 908 */
854c7836 909static int eeepc_hotk_thaw(struct device *device)
96e9cfeb 910{
854c7836
AJ
911 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
912
a7624b63 913 if (eeepc->wlan_rfkill) {
96e9cfeb
AJ
914 bool wlan;
915
c1edd99f
AJ
916 /*
917 * Work around bios bug - acpi _PTS turns off the wireless led
918 * during suspend. Normally it restores it on resume, but
c200da5d 919 * we should kick it ourselves in case hibernation is aborted.
96e9cfeb 920 */
854c7836
AJ
921 wlan = get_acpi(eeepc, CM_ASL_WLAN);
922 set_acpi(eeepc, CM_ASL_WLAN, wlan);
c200da5d
AJ
923 }
924
925 return 0;
926}
96e9cfeb 927
854c7836 928static int eeepc_hotk_restore(struct device *device)
c200da5d 929{
854c7836
AJ
930 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
931
c200da5d 932 /* Refresh both wlan rfkill state and pci hotplug */
14fdb152
MG
933 if (eeepc->wlan_rfkill) {
934 eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P5");
935 eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P6");
936 eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P7");
937 }
96e9cfeb 938
a7624b63
AJ
939 if (eeepc->bluetooth_rfkill)
940 rfkill_set_sw_state(eeepc->bluetooth_rfkill,
854c7836 941 get_acpi(eeepc, CM_ASL_BLUETOOTH) != 1);
a7624b63
AJ
942 if (eeepc->wwan3g_rfkill)
943 rfkill_set_sw_state(eeepc->wwan3g_rfkill,
854c7836 944 get_acpi(eeepc, CM_ASL_3G) != 1);
a7624b63
AJ
945 if (eeepc->wimax_rfkill)
946 rfkill_set_sw_state(eeepc->wimax_rfkill,
854c7836 947 get_acpi(eeepc, CM_ASL_WIMAX) != 1);
96e9cfeb
AJ
948
949 return 0;
950}
951
9a3bff23 952static const struct dev_pm_ops eeepc_pm_ops = {
854c7836
AJ
953 .thaw = eeepc_hotk_thaw,
954 .restore = eeepc_hotk_restore,
52bbe3c7
AJ
955};
956
957static struct platform_driver platform_driver = {
958 .driver = {
a7624b63 959 .name = EEEPC_LAPTOP_FILE,
52bbe3c7
AJ
960 .owner = THIS_MODULE,
961 .pm = &eeepc_pm_ops,
962 }
963};
964
e1faa9da 965/*
52bbe3c7 966 * Hwmon device
e1faa9da 967 */
52bbe3c7
AJ
968
969#define EEEPC_EC_SC00 0x61
970#define EEEPC_EC_FAN_PWM (EEEPC_EC_SC00 + 2) /* Fan PWM duty cycle (%) */
971#define EEEPC_EC_FAN_HRPM (EEEPC_EC_SC00 + 5) /* High byte, fan speed (RPM) */
972#define EEEPC_EC_FAN_LRPM (EEEPC_EC_SC00 + 6) /* Low byte, fan speed (RPM) */
973
974#define EEEPC_EC_SFB0 0xD0
975#define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3) /* Byte containing SF25 */
976
e1faa9da
CC
977static int eeepc_get_fan_pwm(void)
978{
463b4e47 979 u8 value = 0;
e1faa9da 980
463b4e47
AJ
981 ec_read(EEEPC_EC_FAN_PWM, &value);
982 return value * 255 / 100;
e1faa9da
CC
983}
984
985static void eeepc_set_fan_pwm(int value)
986{
c73bad74 987 value = clamp_val(value, 0, 255);
04dcd84b 988 value = value * 100 / 255;
463b4e47 989 ec_write(EEEPC_EC_FAN_PWM, value);
e1faa9da
CC
990}
991
992static int eeepc_get_fan_rpm(void)
993{
463b4e47
AJ
994 u8 high = 0;
995 u8 low = 0;
e1faa9da 996
463b4e47
AJ
997 ec_read(EEEPC_EC_FAN_HRPM, &high);
998 ec_read(EEEPC_EC_FAN_LRPM, &low);
999 return high << 8 | low;
e1faa9da
CC
1000}
1001
1002static int eeepc_get_fan_ctrl(void)
1003{
463b4e47 1004 u8 value = 0;
e1faa9da 1005
463b4e47 1006 ec_read(EEEPC_EC_FAN_CTRL, &value);
48718688
AJ
1007 if (value & 0x02)
1008 return 1; /* manual */
1009 else
1010 return 2; /* automatic */
e1faa9da
CC
1011}
1012
1013static void eeepc_set_fan_ctrl(int manual)
1014{
463b4e47 1015 u8 value = 0;
e1faa9da 1016
463b4e47 1017 ec_read(EEEPC_EC_FAN_CTRL, &value);
48718688 1018 if (manual == 1)
e1faa9da
CC
1019 value |= 0x02;
1020 else
1021 value &= ~0x02;
463b4e47 1022 ec_write(EEEPC_EC_FAN_CTRL, value);
e1faa9da
CC
1023}
1024
1025static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
1026{
1027 int rv, value;
1028
95369a73
PB
1029 rv = parse_arg(buf, &value);
1030 if (rv < 0)
1031 return rv;
1032 set(value);
1033 return count;
e1faa9da
CC
1034}
1035
1036static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
1037{
1038 return sprintf(buf, "%d\n", get());
1039}
1040
28ac85f7 1041#define EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
48d4a5b2 1042 static ssize_t _name##_show(struct device *dev, \
e1faa9da
CC
1043 struct device_attribute *attr, \
1044 char *buf) \
1045 { \
1ec9d399 1046 return show_sys_hwmon(_get, buf); \
28ac85f7
FK
1047 }
1048
1049#define EEEPC_SENSOR_STORE_FUNC(_name, _set) \
48d4a5b2 1050 static ssize_t _name##_store(struct device *dev, \
e1faa9da
CC
1051 struct device_attribute *attr, \
1052 const char *buf, size_t count) \
1053 { \
1ec9d399 1054 return store_sys_hwmon(_set, buf, count); \
28ac85f7
FK
1055 }
1056
48d4a5b2 1057#define EEEPC_CREATE_SENSOR_ATTR_RW(_name, _get, _set) \
28ac85f7
FK
1058 EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
1059 EEEPC_SENSOR_STORE_FUNC(_name, _set) \
48d4a5b2
FK
1060 static DEVICE_ATTR_RW(_name)
1061
1062#define EEEPC_CREATE_SENSOR_ATTR_RO(_name, _get) \
1063 EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
1064 static DEVICE_ATTR_RO(_name)
e1faa9da 1065
48d4a5b2
FK
1066EEEPC_CREATE_SENSOR_ATTR_RO(fan1_input, eeepc_get_fan_rpm);
1067EEEPC_CREATE_SENSOR_ATTR_RW(pwm1, eeepc_get_fan_pwm,
1068 eeepc_set_fan_pwm);
1069EEEPC_CREATE_SENSOR_ATTR_RW(pwm1_enable, eeepc_get_fan_ctrl,
1070 eeepc_set_fan_ctrl);
e1faa9da 1071
f0c34c97
GR
1072static struct attribute *hwmon_attrs[] = {
1073 &dev_attr_pwm1.attr,
1074 &dev_attr_fan1_input.attr,
1075 &dev_attr_pwm1_enable.attr,
e1faa9da
CC
1076 NULL
1077};
f0c34c97 1078ATTRIBUTE_GROUPS(hwmon);
a9df80c5 1079
854c7836 1080static int eeepc_hwmon_init(struct eeepc_laptop *eeepc)
a9df80c5 1081{
f0c34c97 1082 struct device *dev = &eeepc->platform_device->dev;
52bbe3c7 1083 struct device *hwmon;
7de39389 1084
f0c34c97
GR
1085 hwmon = devm_hwmon_device_register_with_groups(dev, "eeepc", NULL,
1086 hwmon_groups);
52bbe3c7
AJ
1087 if (IS_ERR(hwmon)) {
1088 pr_err("Could not register eeepc hwmon device\n");
52bbe3c7 1089 return PTR_ERR(hwmon);
a8258069 1090 }
f0c34c97 1091 return 0;
a9df80c5
CC
1092}
1093
52bbe3c7
AJ
1094/*
1095 * Backlight device
1096 */
1097static int read_brightness(struct backlight_device *bd)
a9df80c5 1098{
854c7836
AJ
1099 struct eeepc_laptop *eeepc = bl_get_data(bd);
1100
1101 return get_acpi(eeepc, CM_ASL_PANELBRIGHT);
a5fa429b
CC
1102}
1103
52bbe3c7 1104static int set_brightness(struct backlight_device *bd, int value)
e1faa9da 1105{
854c7836 1106 struct eeepc_laptop *eeepc = bl_get_data(bd);
e1faa9da 1107
854c7836 1108 return set_acpi(eeepc, CM_ASL_PANELBRIGHT, value);
e1faa9da
CC
1109}
1110
52bbe3c7 1111static int update_bl_status(struct backlight_device *bd)
7de39389 1112{
52bbe3c7
AJ
1113 return set_brightness(bd, bd->props.brightness);
1114}
7de39389 1115
acc2472e 1116static const struct backlight_ops eeepcbl_ops = {
52bbe3c7
AJ
1117 .get_brightness = read_brightness,
1118 .update_status = update_bl_status,
1119};
7de39389 1120
854c7836 1121static int eeepc_backlight_notify(struct eeepc_laptop *eeepc)
52bbe3c7 1122{
854c7836 1123 struct backlight_device *bd = eeepc->backlight_device;
52bbe3c7 1124 int old = bd->props.brightness;
7de39389 1125
52bbe3c7 1126 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
7de39389 1127
52bbe3c7 1128 return old;
7de39389
CC
1129}
1130
854c7836 1131static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
7de39389 1132{
a19a6ee6 1133 struct backlight_properties props;
a5fa429b 1134 struct backlight_device *bd;
7334546a 1135
a19a6ee6 1136 memset(&props, 0, sizeof(struct backlight_properties));
bb7ca747 1137 props.type = BACKLIGHT_PLATFORM;
a19a6ee6 1138 props.max_brightness = 15;
854c7836 1139 bd = backlight_device_register(EEEPC_LAPTOP_FILE,
a19a6ee6
MG
1140 &eeepc->platform_device->dev, eeepc,
1141 &eeepcbl_ops, &props);
a5fa429b 1142 if (IS_ERR(bd)) {
19b53289 1143 pr_err("Could not register eeepc backlight device\n");
854c7836 1144 eeepc->backlight_device = NULL;
a5fa429b
CC
1145 return PTR_ERR(bd);
1146 }
854c7836 1147 eeepc->backlight_device = bd;
854c7836 1148 bd->props.brightness = read_brightness(bd);
a5fa429b
CC
1149 bd->props.power = FB_BLANK_UNBLANK;
1150 backlight_update_status(bd);
1151 return 0;
1152}
7de39389 1153
854c7836 1154static void eeepc_backlight_exit(struct eeepc_laptop *eeepc)
e1faa9da 1155{
854c7836
AJ
1156 if (eeepc->backlight_device)
1157 backlight_device_unregister(eeepc->backlight_device);
1158 eeepc->backlight_device = NULL;
52bbe3c7 1159}
7de39389 1160
7de39389 1161
52bbe3c7
AJ
1162/*
1163 * Input device (i.e. hotkeys)
1164 */
642e0447 1165static int eeepc_input_init(struct eeepc_laptop *eeepc)
52bbe3c7 1166{
642e0447
DT
1167 struct input_dev *input;
1168 int error;
3cd530b5 1169
642e0447 1170 input = input_allocate_device();
b222cca6 1171 if (!input)
642e0447 1172 return -ENOMEM;
07e84aa9 1173
642e0447
DT
1174 input->name = "Asus EeePC extra buttons";
1175 input->phys = EEEPC_LAPTOP_FILE "/input0";
1176 input->id.bustype = BUS_HOST;
1177 input->dev.parent = &eeepc->platform_device->dev;
7de39389 1178
642e0447
DT
1179 error = sparse_keymap_setup(input, eeepc_keymap, NULL);
1180 if (error) {
1181 pr_err("Unable to setup input device keymap\n");
1182 goto err_free_dev;
a5fa429b 1183 }
52bbe3c7 1184
642e0447
DT
1185 error = input_register_device(input);
1186 if (error) {
1187 pr_err("Unable to register input device\n");
1188 goto err_free_keymap;
e1faa9da 1189 }
52bbe3c7 1190
642e0447 1191 eeepc->inputdev = input;
f2a9d5e8 1192 return 0;
642e0447 1193
71e687dc 1194err_free_keymap:
642e0447 1195 sparse_keymap_free(input);
71e687dc 1196err_free_dev:
642e0447
DT
1197 input_free_device(input);
1198 return error;
f2a9d5e8
AJ
1199}
1200
854c7836 1201static void eeepc_input_exit(struct eeepc_laptop *eeepc)
e59f8796 1202{
854c7836 1203 if (eeepc->inputdev) {
c9db3efe 1204 sparse_keymap_free(eeepc->inputdev);
a7624b63 1205 input_unregister_device(eeepc->inputdev);
854c7836 1206 }
71e687dc 1207 eeepc->inputdev = NULL;
52bbe3c7 1208}
3c0eb510 1209
52bbe3c7
AJ
1210/*
1211 * ACPI driver
1212 */
ce6c468f
CC
1213static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
1214{
1215 if (!eeepc->inputdev)
1216 return ;
1217 if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
1218 pr_info("Unknown key %x pressed\n", event);
1219}
1220
a7624b63 1221static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
52bbe3c7 1222{
854c7836 1223 struct eeepc_laptop *eeepc = acpi_driver_data(device);
52bbe3c7 1224 u16 count;
3c0eb510 1225
52bbe3c7
AJ
1226 if (event > ACPI_MAX_SYS_NOTIFY)
1227 return;
a7624b63 1228 count = eeepc->event_count[event % 128]++;
854c7836
AJ
1229 acpi_bus_generate_netlink_event(device->pnp.device_class,
1230 dev_name(&device->dev), event,
52bbe3c7 1231 count);
3c0eb510 1232
325fb8e9 1233 /* Brightness events are special */
52bbe3c7 1234 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) {
52bbe3c7 1235
325fb8e9
AJ
1236 /* Ignore them completely if the acpi video driver is used */
1237 if (eeepc->backlight_device != NULL) {
1238 int old_brightness, new_brightness;
1239
1240 /* Update the backlight device. */
1241 old_brightness = eeepc_backlight_notify(eeepc);
1242
1243 /* Convert event to keypress (obsolescent hack) */
1244 new_brightness = event - NOTIFY_BRN_MIN;
1245
1246 if (new_brightness < old_brightness) {
1247 event = NOTIFY_BRN_MIN; /* brightness down */
1248 } else if (new_brightness > old_brightness) {
1249 event = NOTIFY_BRN_MAX; /* brightness up */
1250 } else {
1251 /*
1252 * no change in brightness - already at min/max,
1253 * event will be desired value (or else ignored)
1254 */
1255 }
ce6c468f 1256 eeepc_input_notify(eeepc, event);
52bbe3c7 1257 }
325fb8e9
AJ
1258 } else {
1259 /* Everything else is a bona-fide keypress event */
ce6c468f 1260 eeepc_input_notify(eeepc, event);
52bbe3c7 1261 }
52bbe3c7
AJ
1262}
1263
da8ba01d
AJ
1264static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
1265{
1266 const char *model;
1267
10ae4b56
CC
1268 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1269 if (!model)
1270 return;
1271
da8ba01d
AJ
1272 /*
1273 * Blacklist for setting cpufv (cpu speed).
1274 *
1275 * EeePC 4G ("701") implements CFVS, but it is not supported
1276 * by the pre-installed OS, and the original option to change it
1277 * in the BIOS setup screen was removed in later versions.
1278 *
1279 * Judging by the lack of "Super Hybrid Engine" on Asus product pages,
1280 * this applies to all "701" models (4G/4G Surf/2G Surf).
1281 *
1282 * So Asus made a deliberate decision not to support it on this model.
1283 * We have several reports that using it can cause the system to hang
1284 *
1285 * The hang has also been reported on a "702" (Model name "8G"?).
1286 *
1287 * We avoid dmi_check_system() / dmi_match(), because they use
1288 * substring matching. We don't want to affect the "701SD"
1289 * and "701SDX" models, because they do support S.H.E.
1290 */
da8ba01d
AJ
1291 if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
1292 eeepc->cpufv_disabled = true;
1293 pr_info("model %s does not officially support setting cpu "
1294 "speed\n", model);
1295 pr_info("cpufv disabled to avoid instability\n");
1296 }
10ae4b56
CC
1297
1298 /*
1299 * Blacklist for wlan hotplug
1300 *
1301 * Eeepc 1005HA doesn't work like others models and don't need the
1302 * hotplug code. In fact, current hotplug code seems to unplug another
1303 * device...
1304 */
ced69c59
AJ
1305 if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 ||
1306 strcmp(model, "1005PE") == 0) {
10ae4b56
CC
1307 eeepc->hotplug_disabled = true;
1308 pr_info("wlan hotplug disabled\n");
1309 }
da8ba01d
AJ
1310}
1311
854c7836 1312static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
52bbe3c7
AJ
1313{
1314 int dummy;
1315
c8440336 1316 /* Some BIOSes do not report cm although it is available.
52bbe3c7 1317 Check if cm_getv[cm] works and, if yes, assume cm should be set. */
a7624b63
AJ
1318 if (!(eeepc->cm_supported & (1 << cm))
1319 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
52bbe3c7
AJ
1320 pr_info("%s (%x) not reported by BIOS,"
1321 " enabling anyway\n", name, 1 << cm);
a7624b63 1322 eeepc->cm_supported |= 1 << cm;
52bbe3c7
AJ
1323 }
1324}
1325
854c7836 1326static void cmsg_quirks(struct eeepc_laptop *eeepc)
52bbe3c7 1327{
854c7836
AJ
1328 cmsg_quirk(eeepc, CM_ASL_LID, "LID");
1329 cmsg_quirk(eeepc, CM_ASL_TYPE, "TYPE");
1330 cmsg_quirk(eeepc, CM_ASL_PANELPOWER, "PANELPOWER");
1331 cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");
52bbe3c7
AJ
1332}
1333
b859f159 1334static int eeepc_acpi_init(struct eeepc_laptop *eeepc)
52bbe3c7
AJ
1335{
1336 unsigned int init_flags;
e59f8796
EC
1337 int result;
1338
71e687dc 1339 result = acpi_bus_get_status(eeepc->device);
1e779854 1340 if (result)
52bbe3c7 1341 return result;
71e687dc 1342 if (!eeepc->device->status.present) {
52bbe3c7
AJ
1343 pr_err("Hotkey device not present, aborting\n");
1344 return -ENODEV;
1345 }
cede2cb6 1346
52bbe3c7
AJ
1347 init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
1348 pr_notice("Hotkey init flags 0x%x\n", init_flags);
1349
a7624b63 1350 if (write_acpi_int(eeepc->handle, "INIT", init_flags)) {
52bbe3c7
AJ
1351 pr_err("Hotkey initialization failed\n");
1352 return -ENODEV;
e59f8796 1353 }
52bbe3c7
AJ
1354
1355 /* get control methods supported */
a7624b63 1356 if (read_acpi_int(eeepc->handle, "CMSG", &eeepc->cm_supported)) {
52bbe3c7
AJ
1357 pr_err("Get control methods supported failed\n");
1358 return -ENODEV;
dc56ad9b 1359 }
854c7836 1360 cmsg_quirks(eeepc);
a7624b63 1361 pr_info("Get control methods supported: 0x%x\n", eeepc->cm_supported);
2b56f1c1 1362
3c0eb510
CC
1363 return 0;
1364}
1365
b859f159 1366static void eeepc_enable_camera(struct eeepc_laptop *eeepc)
52bbe3c7
AJ
1367{
1368 /*
1369 * If the following call to set_acpi() fails, it's because there's no
1370 * camera so we can ignore the error.
1371 */
854c7836
AJ
1372 if (get_acpi(eeepc, CM_ASL_CAMERA) == 0)
1373 set_acpi(eeepc, CM_ASL_CAMERA, 1);
52bbe3c7
AJ
1374}
1375
854c7836
AJ
1376static bool eeepc_device_present;
1377
b859f159 1378static int eeepc_acpi_add(struct acpi_device *device)
e59f8796 1379{
854c7836 1380 struct eeepc_laptop *eeepc;
e59f8796
EC
1381 int result;
1382
a7624b63
AJ
1383 pr_notice(EEEPC_LAPTOP_NAME "\n");
1384 eeepc = kzalloc(sizeof(struct eeepc_laptop), GFP_KERNEL);
1385 if (!eeepc)
1e779854 1386 return -ENOMEM;
a7624b63
AJ
1387 eeepc->handle = device->handle;
1388 strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
1389 strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
1390 device->driver_data = eeepc;
71e687dc 1391 eeepc->device = device;
cede2cb6 1392
322a1356
CC
1393 eeepc->hotplug_disabled = hotplug_disabled;
1394
da8ba01d
AJ
1395 eeepc_dmi_check(eeepc);
1396
71e687dc 1397 result = eeepc_acpi_init(eeepc);
e59f8796 1398 if (result)
9db106be 1399 goto fail_platform;
854c7836 1400 eeepc_enable_camera(eeepc);
7de39389 1401
854c7836
AJ
1402 /*
1403 * Register the platform device first. It is used as a parent for the
1404 * sub-devices below.
1405 *
1406 * Note that if there are multiple instances of this ACPI device it
1407 * will bail out, because the platform device is registered with a
1408 * fixed name. Of course it doesn't make sense to have more than one,
1409 * and machine-specific scripts find the fixed name convenient. But
1410 * It's also good for us to exclude multiple instances because both
1411 * our hwmon and our wlan rfkill subdevice use global ACPI objects
1412 * (the EC and the wlan PCI slot respectively).
1413 */
1414 result = eeepc_platform_init(eeepc);
e59f8796 1415 if (result)
9db106be 1416 goto fail_platform;
1ddec2f9
CC
1417
1418 if (!acpi_video_backlight_support()) {
854c7836 1419 result = eeepc_backlight_init(eeepc);
1ddec2f9
CC
1420 if (result)
1421 goto fail_backlight;
39a3e17e 1422 } else {
9db106be 1423 pr_info("Backlight controlled by ACPI video driver\n");
39a3e17e 1424 }
1ddec2f9 1425
854c7836 1426 result = eeepc_input_init(eeepc);
f2a9d5e8
AJ
1427 if (result)
1428 goto fail_input;
1429
854c7836 1430 result = eeepc_hwmon_init(eeepc);
1ddec2f9
CC
1431 if (result)
1432 goto fail_hwmon;
1433
854c7836 1434 result = eeepc_led_init(eeepc);
3c0eb510
CC
1435 if (result)
1436 goto fail_led;
1437
854c7836 1438 result = eeepc_rfkill_init(eeepc);
7de39389
CC
1439 if (result)
1440 goto fail_rfkill;
1441
854c7836 1442 eeepc_device_present = true;
e59f8796 1443 return 0;
1e779854 1444
7de39389 1445fail_rfkill:
854c7836 1446 eeepc_led_exit(eeepc);
3c0eb510 1447fail_led:
1ddec2f9 1448fail_hwmon:
854c7836 1449 eeepc_input_exit(eeepc);
f2a9d5e8 1450fail_input:
854c7836 1451 eeepc_backlight_exit(eeepc);
1ddec2f9 1452fail_backlight:
854c7836 1453 eeepc_platform_exit(eeepc);
9db106be 1454fail_platform:
a7624b63 1455 kfree(eeepc);
1e779854 1456
e59f8796
EC
1457 return result;
1458}
1459
51fac838 1460static int eeepc_acpi_remove(struct acpi_device *device)
1e779854 1461{
854c7836 1462 struct eeepc_laptop *eeepc = acpi_driver_data(device);
1e779854 1463
854c7836
AJ
1464 eeepc_backlight_exit(eeepc);
1465 eeepc_rfkill_exit(eeepc);
1466 eeepc_input_exit(eeepc);
854c7836
AJ
1467 eeepc_led_exit(eeepc);
1468 eeepc_platform_exit(eeepc);
1e779854 1469
a7624b63 1470 kfree(eeepc);
1e779854
AJ
1471 return 0;
1472}
1473
52bbe3c7
AJ
1474
1475static const struct acpi_device_id eeepc_device_ids[] = {
a7624b63 1476 {EEEPC_ACPI_HID, 0},
52bbe3c7
AJ
1477 {"", 0},
1478};
1479MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
1480
a7624b63
AJ
1481static struct acpi_driver eeepc_acpi_driver = {
1482 .name = EEEPC_LAPTOP_NAME,
1483 .class = EEEPC_ACPI_CLASS,
52bbe3c7
AJ
1484 .owner = THIS_MODULE,
1485 .ids = eeepc_device_ids,
1486 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1487 .ops = {
a7624b63
AJ
1488 .add = eeepc_acpi_add,
1489 .remove = eeepc_acpi_remove,
1490 .notify = eeepc_acpi_notify,
52bbe3c7
AJ
1491 },
1492};
1493
1494
1e779854
AJ
1495static int __init eeepc_laptop_init(void)
1496{
1497 int result;
1498
22072e92 1499 result = platform_driver_register(&platform_driver);
1e779854
AJ
1500 if (result < 0)
1501 return result;
22072e92 1502
a7624b63 1503 result = acpi_bus_register_driver(&eeepc_acpi_driver);
22072e92
AJ
1504 if (result < 0)
1505 goto fail_acpi_driver;
642e0447 1506
854c7836 1507 if (!eeepc_device_present) {
22072e92
AJ
1508 result = -ENODEV;
1509 goto fail_no_device;
1e779854 1510 }
642e0447 1511
1e779854 1512 return 0;
22072e92
AJ
1513
1514fail_no_device:
a7624b63 1515 acpi_bus_unregister_driver(&eeepc_acpi_driver);
22072e92
AJ
1516fail_acpi_driver:
1517 platform_driver_unregister(&platform_driver);
1518 return result;
1e779854
AJ
1519}
1520
1521static void __exit eeepc_laptop_exit(void)
1522{
a7624b63 1523 acpi_bus_unregister_driver(&eeepc_acpi_driver);
22072e92 1524 platform_driver_unregister(&platform_driver);
1e779854
AJ
1525}
1526
e59f8796
EC
1527module_init(eeepc_laptop_init);
1528module_exit(eeepc_laptop_exit);