]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/platform/x86/eeepc-laptop.c
eeepc-laptop: store_cpufv: return error if set_acpi fails
[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);
a5c155b1
FK
335 if (c->cur < 0)
336 return -ENODEV;
337
b31d0fde
CC
338 c->num = (c->cur >> 8) & 0xff;
339 c->cur &= 0xff;
a5c155b1 340 if (c->num == 0 || c->num > 12)
b31d0fde
CC
341 return -ENODEV;
342 return 0;
343}
344
8c72fc8b 345static ssize_t available_cpufv_show(struct device *dev,
b31d0fde
CC
346 struct device_attribute *attr,
347 char *buf)
348{
854c7836 349 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
b31d0fde
CC
350 struct eeepc_cpufv c;
351 int i;
352 ssize_t len = 0;
353
854c7836 354 if (get_cpufv(eeepc, &c))
b31d0fde
CC
355 return -ENODEV;
356 for (i = 0; i < c.num; i++)
357 len += sprintf(buf + len, "%d ", i);
358 len += sprintf(buf + len, "\n");
359 return len;
360}
361
8c72fc8b 362static ssize_t cpufv_show(struct device *dev,
b31d0fde
CC
363 struct device_attribute *attr,
364 char *buf)
365{
854c7836 366 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
b31d0fde
CC
367 struct eeepc_cpufv c;
368
854c7836 369 if (get_cpufv(eeepc, &c))
b31d0fde
CC
370 return -ENODEV;
371 return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);
372}
373
8c72fc8b 374static ssize_t cpufv_store(struct device *dev,
b31d0fde
CC
375 struct device_attribute *attr,
376 const char *buf, size_t count)
377{
854c7836 378 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
b31d0fde
CC
379 struct eeepc_cpufv c;
380 int rv, value;
381
da8ba01d
AJ
382 if (eeepc->cpufv_disabled)
383 return -EPERM;
854c7836 384 if (get_cpufv(eeepc, &c))
b31d0fde 385 return -ENODEV;
95369a73 386 rv = parse_arg(buf, &value);
b31d0fde
CC
387 if (rv < 0)
388 return rv;
95369a73 389 if (value < 0 || value >= c.num)
b31d0fde 390 return -EINVAL;
d4869038
FK
391 rv = set_acpi(eeepc, CM_ASL_CPUFV, value);
392 if (rv)
393 return rv;
95369a73 394 return count;
b31d0fde
CC
395}
396
8c72fc8b 397static ssize_t cpufv_disabled_show(struct device *dev,
da8ba01d
AJ
398 struct device_attribute *attr,
399 char *buf)
400{
401 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
402
403 return sprintf(buf, "%d\n", eeepc->cpufv_disabled);
404}
405
8c72fc8b 406static ssize_t cpufv_disabled_store(struct device *dev,
da8ba01d
AJ
407 struct device_attribute *attr,
408 const char *buf, size_t count)
409{
410 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
411 int rv, value;
412
95369a73 413 rv = parse_arg(buf, &value);
da8ba01d
AJ
414 if (rv < 0)
415 return rv;
416
417 switch (value) {
418 case 0:
419 if (eeepc->cpufv_disabled)
22441ffe 420 pr_warn("cpufv enabled (not officially supported "
da8ba01d
AJ
421 "on this model)\n");
422 eeepc->cpufv_disabled = false;
95369a73 423 return count;
da8ba01d
AJ
424 case 1:
425 return -EPERM;
426 default:
427 return -EINVAL;
428 }
429}
430
431
bb382dba
FK
432static DEVICE_ATTR_RW(cpufv);
433static DEVICE_ATTR_RO(available_cpufv);
434static DEVICE_ATTR_RW(cpufv_disabled);
da8ba01d 435
e59f8796
EC
436static struct attribute *platform_attributes[] = {
437 &dev_attr_camera.attr,
438 &dev_attr_cardr.attr,
439 &dev_attr_disp.attr,
158ca1d7 440 &dev_attr_cpufv.attr,
b31d0fde 441 &dev_attr_available_cpufv.attr,
da8ba01d 442 &dev_attr_cpufv_disabled.attr,
e59f8796
EC
443 NULL
444};
445
446static struct attribute_group platform_attribute_group = {
447 .attrs = platform_attributes
448};
449
854c7836 450static int eeepc_platform_init(struct eeepc_laptop *eeepc)
a195dcdc 451{
9db106be 452 int result;
a195dcdc 453
854c7836
AJ
454 eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, -1);
455 if (!eeepc->platform_device)
9db106be 456 return -ENOMEM;
854c7836 457 platform_set_drvdata(eeepc->platform_device, eeepc);
a195dcdc 458
854c7836 459 result = platform_device_add(eeepc->platform_device);
9db106be
AJ
460 if (result)
461 goto fail_platform_device;
a195dcdc 462
854c7836 463 result = sysfs_create_group(&eeepc->platform_device->dev.kobj,
9db106be
AJ
464 &platform_attribute_group);
465 if (result)
466 goto fail_sysfs;
467 return 0;
a195dcdc 468
9db106be 469fail_sysfs:
854c7836 470 platform_device_del(eeepc->platform_device);
9db106be 471fail_platform_device:
854c7836 472 platform_device_put(eeepc->platform_device);
9db106be 473 return result;
a195dcdc
MG
474}
475
854c7836 476static void eeepc_platform_exit(struct eeepc_laptop *eeepc)
a195dcdc 477{
854c7836 478 sysfs_remove_group(&eeepc->platform_device->dev.kobj,
9db106be 479 &platform_attribute_group);
854c7836 480 platform_device_unregister(eeepc->platform_device);
9db106be 481}
a195dcdc 482
3c0eb510
CC
483/*
484 * LEDs
485 */
486/*
487 * These functions actually update the LED's, and are called from a
488 * workqueue. By doing this as separate work rather than when the LED
489 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
490 * potentially bad time, such as a timer interrupt.
491 */
854c7836
AJ
492static void tpd_led_update(struct work_struct *work)
493 {
494 struct eeepc_laptop *eeepc;
a195dcdc 495
854c7836 496 eeepc = container_of(work, struct eeepc_laptop, tpd_led_work);
3c0eb510 497
854c7836 498 set_acpi(eeepc, CM_ASL_TPD, eeepc->tpd_led_wk);
a195dcdc
MG
499}
500
3c0eb510
CC
501static void tpd_led_set(struct led_classdev *led_cdev,
502 enum led_brightness value)
a195dcdc 503{
854c7836 504 struct eeepc_laptop *eeepc;
a195dcdc 505
854c7836 506 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
a195dcdc 507
854c7836
AJ
508 eeepc->tpd_led_wk = (value > 0) ? 1 : 0;
509 queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
a195dcdc
MG
510}
511
62a75d83
CC
512static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
513{
514 struct eeepc_laptop *eeepc;
515
516 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
517
518 return get_acpi(eeepc, CM_ASL_TPD);
519}
520
854c7836 521static int eeepc_led_init(struct eeepc_laptop *eeepc)
dbfa3ba9 522{
52bbe3c7 523 int rv;
dbfa3ba9 524
854c7836 525 if (get_acpi(eeepc, CM_ASL_TPD) == -ENODEV)
52bbe3c7 526 return 0;
dbfa3ba9 527
854c7836
AJ
528 eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
529 if (!eeepc->led_workqueue)
52bbe3c7 530 return -ENOMEM;
854c7836 531 INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
dbfa3ba9 532
854c7836
AJ
533 eeepc->tpd_led.name = "eeepc::touchpad";
534 eeepc->tpd_led.brightness_set = tpd_led_set;
62a75d83 535 if (get_acpi(eeepc, CM_ASL_TPD) >= 0) /* if method is available */
39a3e17e 536 eeepc->tpd_led.brightness_get = tpd_led_get;
854c7836 537 eeepc->tpd_led.max_brightness = 1;
e59f8796 538
854c7836
AJ
539 rv = led_classdev_register(&eeepc->platform_device->dev,
540 &eeepc->tpd_led);
52bbe3c7 541 if (rv) {
854c7836 542 destroy_workqueue(eeepc->led_workqueue);
52bbe3c7 543 return rv;
e59f8796 544 }
a195dcdc 545
e59f8796
EC
546 return 0;
547}
548
854c7836 549static void eeepc_led_exit(struct eeepc_laptop *eeepc)
a5fa429b 550{
5d6afd15 551 if (!IS_ERR_OR_NULL(eeepc->tpd_led.dev))
854c7836
AJ
552 led_classdev_unregister(&eeepc->tpd_led);
553 if (eeepc->led_workqueue)
554 destroy_workqueue(eeepc->led_workqueue);
a5fa429b
CC
555}
556
2b121bc2 557
52bbe3c7
AJ
558/*
559 * PCI hotplug (for wlan rfkill)
560 */
854c7836 561static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc)
52bbe3c7 562{
854c7836 563 if (get_acpi(eeepc, CM_ASL_WLAN) == 1)
52bbe3c7
AJ
564 return false;
565 return true;
2b121bc2
CC
566}
567
14fdb152 568static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
5740294c 569{
14fdb152 570 struct pci_dev *port;
5740294c 571 struct pci_dev *dev;
6d41839e 572 struct pci_bus *bus;
854c7836 573 bool blocked = eeepc_wlan_rfkill_blocked(eeepc);
bc9d24a3
AJ
574 bool absent;
575 u32 l;
5740294c 576
a7624b63
AJ
577 if (eeepc->wlan_rfkill)
578 rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);
6d41839e 579
a7624b63 580 mutex_lock(&eeepc->hotplug_lock);
8b9ec1da 581 pci_lock_rescan_remove();
dcf443b5 582
a7624b63 583 if (eeepc->hotplug_slot) {
14fdb152
MG
584 port = acpi_get_pci_dev(handle);
585 if (!port) {
586 pr_warning("Unable to find port\n");
587 goto out_unlock;
588 }
589
590 bus = port->subordinate;
591
07e84aa9 592 if (!bus) {
22441ffe 593 pr_warn("Unable to find PCI bus 1?\n");
f661848b 594 goto out_put_dev;
5740294c 595 }
07e84aa9 596
bc9d24a3
AJ
597 if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
598 pr_err("Unable to read PCI config space?\n");
f661848b 599 goto out_put_dev;
bc9d24a3 600 }
14fdb152 601
bc9d24a3
AJ
602 absent = (l == 0xffffffff);
603
604 if (blocked != absent) {
22441ffe
JP
605 pr_warn("BIOS says wireless lan is %s, "
606 "but the pci device is %s\n",
bc9d24a3
AJ
607 blocked ? "blocked" : "unblocked",
608 absent ? "absent" : "present");
22441ffe
JP
609 pr_warn("skipped wireless hotplug as probably "
610 "inappropriate for this model\n");
f661848b 611 goto out_put_dev;
bc9d24a3
AJ
612 }
613
07e84aa9
AJ
614 if (!blocked) {
615 dev = pci_get_slot(bus, 0);
616 if (dev) {
617 /* Device already present */
618 pci_dev_put(dev);
f661848b 619 goto out_put_dev;
07e84aa9
AJ
620 }
621 dev = pci_scan_single_device(bus, 0);
622 if (dev) {
623 pci_bus_assign_resources(bus);
c893d133 624 pci_bus_add_device(dev);
07e84aa9
AJ
625 }
626 } else {
627 dev = pci_get_slot(bus, 0);
628 if (dev) {
210647af 629 pci_stop_and_remove_bus_device(dev);
07e84aa9
AJ
630 pci_dev_put(dev);
631 }
5740294c 632 }
f661848b
JL
633out_put_dev:
634 pci_dev_put(port);
5740294c 635 }
dcf443b5
AJ
636
637out_unlock:
8b9ec1da 638 pci_unlock_rescan_remove();
a7624b63 639 mutex_unlock(&eeepc->hotplug_lock);
5740294c
MG
640}
641
14fdb152
MG
642static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node)
643{
644 acpi_status status = AE_OK;
645 acpi_handle handle;
646
647 status = acpi_get_handle(NULL, node, &handle);
648
649 if (ACPI_SUCCESS(status))
650 eeepc_rfkill_hotplug(eeepc, handle);
651}
652
96e9cfeb
AJ
653static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
654{
854c7836
AJ
655 struct eeepc_laptop *eeepc = data;
656
96e9cfeb
AJ
657 if (event != ACPI_NOTIFY_BUS_CHECK)
658 return;
659
14fdb152 660 eeepc_rfkill_hotplug(eeepc, handle);
e59f8796
EC
661}
662
854c7836
AJ
663static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,
664 char *node)
5740294c 665{
854c7836 666 acpi_status status;
5740294c
MG
667 acpi_handle handle;
668
669 status = acpi_get_handle(NULL, node, &handle);
670
671 if (ACPI_SUCCESS(status)) {
672 status = acpi_install_notify_handler(handle,
673 ACPI_SYSTEM_NOTIFY,
674 eeepc_rfkill_notify,
854c7836 675 eeepc);
5740294c 676 if (ACPI_FAILURE(status))
22441ffe
JP
677 pr_warn("Failed to register notify on %s\n", node);
678
14fdb152
MG
679 /*
680 * Refresh pci hotplug in case the rfkill state was
681 * changed during setup.
682 */
683 eeepc_rfkill_hotplug(eeepc, handle);
39a3e17e 684 } else {
5740294c 685 return -ENODEV;
39a3e17e 686 }
5740294c
MG
687
688 return 0;
689}
690
854c7836
AJ
691static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc,
692 char *node)
5740294c
MG
693{
694 acpi_status status = AE_OK;
695 acpi_handle handle;
696
697 status = acpi_get_handle(NULL, node, &handle);
698
699 if (ACPI_SUCCESS(status)) {
700 status = acpi_remove_notify_handler(handle,
701 ACPI_SYSTEM_NOTIFY,
702 eeepc_rfkill_notify);
703 if (ACPI_FAILURE(status))
19b53289 704 pr_err("Error removing rfkill notify handler %s\n",
5740294c 705 node);
14fdb152
MG
706 /*
707 * Refresh pci hotplug in case the rfkill
708 * state was changed after
709 * eeepc_unregister_rfkill_notifier()
710 */
711 eeepc_rfkill_hotplug(eeepc, handle);
5740294c
MG
712 }
713}
714
52bbe3c7
AJ
715static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
716 u8 *value)
717{
854c7836
AJ
718 struct eeepc_laptop *eeepc = hotplug_slot->private;
719 int val = get_acpi(eeepc, CM_ASL_WLAN);
52bbe3c7
AJ
720
721 if (val == 1 || val == 0)
722 *value = val;
723 else
724 return -EINVAL;
725
726 return 0;
727}
728
2b121bc2
CC
729static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
730{
731 kfree(hotplug_slot->info);
732 kfree(hotplug_slot);
733}
734
52bbe3c7
AJ
735static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
736 .owner = THIS_MODULE,
737 .get_adapter_status = eeepc_get_adapter_status,
738 .get_power_status = eeepc_get_adapter_status,
739};
740
854c7836 741static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc)
2b121bc2
CC
742{
743 int ret = -ENOMEM;
744 struct pci_bus *bus = pci_find_bus(0, 1);
745
746 if (!bus) {
19b53289 747 pr_err("Unable to find wifi PCI bus\n");
2b121bc2
CC
748 return -ENODEV;
749 }
750
a7624b63
AJ
751 eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
752 if (!eeepc->hotplug_slot)
2b121bc2
CC
753 goto error_slot;
754
a7624b63 755 eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
2b121bc2 756 GFP_KERNEL);
a7624b63 757 if (!eeepc->hotplug_slot->info)
2b121bc2
CC
758 goto error_info;
759
a7624b63
AJ
760 eeepc->hotplug_slot->private = eeepc;
761 eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
762 eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
763 eeepc_get_adapter_status(eeepc->hotplug_slot,
764 &eeepc->hotplug_slot->info->adapter_status);
2b121bc2 765
a7624b63 766 ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi");
2b121bc2 767 if (ret) {
19b53289 768 pr_err("Unable to register hotplug slot - %d\n", ret);
2b121bc2
CC
769 goto error_register;
770 }
771
772 return 0;
773
774error_register:
a7624b63 775 kfree(eeepc->hotplug_slot->info);
2b121bc2 776error_info:
a7624b63
AJ
777 kfree(eeepc->hotplug_slot);
778 eeepc->hotplug_slot = NULL;
2b121bc2
CC
779error_slot:
780 return ret;
781}
782
52bbe3c7
AJ
783/*
784 * Rfkill devices
785 */
786static int eeepc_rfkill_set(void *data, bool blocked)
96e9cfeb 787{
854c7836 788 acpi_handle handle = data;
c200da5d 789
854c7836 790 return write_acpi_int(handle, NULL, !blocked);
c200da5d 791}
96e9cfeb 792
52bbe3c7
AJ
793static const struct rfkill_ops eeepc_rfkill_ops = {
794 .set_block = eeepc_rfkill_set,
795};
796
854c7836
AJ
797static int eeepc_new_rfkill(struct eeepc_laptop *eeepc,
798 struct rfkill **rfkill,
799 const char *name,
52bbe3c7
AJ
800 enum rfkill_type type, int cm)
801{
854c7836 802 acpi_handle handle;
52bbe3c7
AJ
803 int result;
804
854c7836 805 result = acpi_setter_handle(eeepc, cm, &handle);
52bbe3c7
AJ
806 if (result < 0)
807 return result;
808
854c7836
AJ
809 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
810 &eeepc_rfkill_ops, handle);
96e9cfeb 811
52bbe3c7
AJ
812 if (!*rfkill)
813 return -EINVAL;
814
854c7836 815 rfkill_init_sw_state(*rfkill, get_acpi(eeepc, cm) != 1);
52bbe3c7
AJ
816 result = rfkill_register(*rfkill);
817 if (result) {
818 rfkill_destroy(*rfkill);
819 *rfkill = NULL;
820 return result;
821 }
96e9cfeb
AJ
822 return 0;
823}
824
854c7836 825static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc)
52bbe3c7 826{
854c7836
AJ
827 eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5");
828 eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6");
829 eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7");
a7624b63
AJ
830 if (eeepc->wlan_rfkill) {
831 rfkill_unregister(eeepc->wlan_rfkill);
832 rfkill_destroy(eeepc->wlan_rfkill);
833 eeepc->wlan_rfkill = NULL;
52bbe3c7 834 }
14fdb152 835
a7624b63
AJ
836 if (eeepc->hotplug_slot)
837 pci_hp_deregister(eeepc->hotplug_slot);
52bbe3c7 838
a7624b63
AJ
839 if (eeepc->bluetooth_rfkill) {
840 rfkill_unregister(eeepc->bluetooth_rfkill);
841 rfkill_destroy(eeepc->bluetooth_rfkill);
842 eeepc->bluetooth_rfkill = NULL;
52bbe3c7 843 }
a7624b63
AJ
844 if (eeepc->wwan3g_rfkill) {
845 rfkill_unregister(eeepc->wwan3g_rfkill);
846 rfkill_destroy(eeepc->wwan3g_rfkill);
847 eeepc->wwan3g_rfkill = NULL;
52bbe3c7 848 }
a7624b63
AJ
849 if (eeepc->wimax_rfkill) {
850 rfkill_unregister(eeepc->wimax_rfkill);
851 rfkill_destroy(eeepc->wimax_rfkill);
852 eeepc->wimax_rfkill = NULL;
52bbe3c7
AJ
853 }
854}
855
854c7836 856static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)
52bbe3c7
AJ
857{
858 int result = 0;
859
a7624b63 860 mutex_init(&eeepc->hotplug_lock);
52bbe3c7 861
854c7836
AJ
862 result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
863 "eeepc-wlan", RFKILL_TYPE_WLAN,
864 CM_ASL_WLAN);
52bbe3c7
AJ
865
866 if (result && result != -ENODEV)
867 goto exit;
868
854c7836
AJ
869 result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
870 "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
871 CM_ASL_BLUETOOTH);
52bbe3c7
AJ
872
873 if (result && result != -ENODEV)
874 goto exit;
875
854c7836
AJ
876 result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
877 "eeepc-wwan3g", RFKILL_TYPE_WWAN,
878 CM_ASL_3G);
52bbe3c7
AJ
879
880 if (result && result != -ENODEV)
881 goto exit;
882
854c7836
AJ
883 result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill,
884 "eeepc-wimax", RFKILL_TYPE_WIMAX,
885 CM_ASL_WIMAX);
52bbe3c7
AJ
886
887 if (result && result != -ENODEV)
888 goto exit;
889
10ae4b56
CC
890 if (eeepc->hotplug_disabled)
891 return 0;
892
854c7836 893 result = eeepc_setup_pci_hotplug(eeepc);
52bbe3c7
AJ
894 /*
895 * If we get -EBUSY then something else is handling the PCI hotplug -
896 * don't fail in this case
897 */
898 if (result == -EBUSY)
899 result = 0;
900
854c7836
AJ
901 eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5");
902 eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6");
903 eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7");
52bbe3c7
AJ
904
905exit:
906 if (result && result != -ENODEV)
854c7836 907 eeepc_rfkill_exit(eeepc);
52bbe3c7
AJ
908 return result;
909}
910
e1faa9da 911/*
52bbe3c7 912 * Platform driver - hibernate/resume callbacks
e1faa9da 913 */
854c7836 914static int eeepc_hotk_thaw(struct device *device)
96e9cfeb 915{
854c7836
AJ
916 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
917
a7624b63 918 if (eeepc->wlan_rfkill) {
96e9cfeb
AJ
919 bool wlan;
920
c1edd99f
AJ
921 /*
922 * Work around bios bug - acpi _PTS turns off the wireless led
923 * during suspend. Normally it restores it on resume, but
c200da5d 924 * we should kick it ourselves in case hibernation is aborted.
96e9cfeb 925 */
854c7836
AJ
926 wlan = get_acpi(eeepc, CM_ASL_WLAN);
927 set_acpi(eeepc, CM_ASL_WLAN, wlan);
c200da5d
AJ
928 }
929
930 return 0;
931}
96e9cfeb 932
854c7836 933static int eeepc_hotk_restore(struct device *device)
c200da5d 934{
854c7836
AJ
935 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
936
c200da5d 937 /* Refresh both wlan rfkill state and pci hotplug */
14fdb152
MG
938 if (eeepc->wlan_rfkill) {
939 eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P5");
940 eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P6");
941 eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P7");
942 }
96e9cfeb 943
a7624b63
AJ
944 if (eeepc->bluetooth_rfkill)
945 rfkill_set_sw_state(eeepc->bluetooth_rfkill,
854c7836 946 get_acpi(eeepc, CM_ASL_BLUETOOTH) != 1);
a7624b63
AJ
947 if (eeepc->wwan3g_rfkill)
948 rfkill_set_sw_state(eeepc->wwan3g_rfkill,
854c7836 949 get_acpi(eeepc, CM_ASL_3G) != 1);
a7624b63
AJ
950 if (eeepc->wimax_rfkill)
951 rfkill_set_sw_state(eeepc->wimax_rfkill,
854c7836 952 get_acpi(eeepc, CM_ASL_WIMAX) != 1);
96e9cfeb
AJ
953
954 return 0;
955}
956
9a3bff23 957static const struct dev_pm_ops eeepc_pm_ops = {
854c7836
AJ
958 .thaw = eeepc_hotk_thaw,
959 .restore = eeepc_hotk_restore,
52bbe3c7
AJ
960};
961
962static struct platform_driver platform_driver = {
963 .driver = {
a7624b63 964 .name = EEEPC_LAPTOP_FILE,
52bbe3c7
AJ
965 .owner = THIS_MODULE,
966 .pm = &eeepc_pm_ops,
967 }
968};
969
e1faa9da 970/*
52bbe3c7 971 * Hwmon device
e1faa9da 972 */
52bbe3c7
AJ
973
974#define EEEPC_EC_SC00 0x61
975#define EEEPC_EC_FAN_PWM (EEEPC_EC_SC00 + 2) /* Fan PWM duty cycle (%) */
976#define EEEPC_EC_FAN_HRPM (EEEPC_EC_SC00 + 5) /* High byte, fan speed (RPM) */
977#define EEEPC_EC_FAN_LRPM (EEEPC_EC_SC00 + 6) /* Low byte, fan speed (RPM) */
978
979#define EEEPC_EC_SFB0 0xD0
980#define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3) /* Byte containing SF25 */
981
e1faa9da
CC
982static int eeepc_get_fan_pwm(void)
983{
463b4e47 984 u8 value = 0;
e1faa9da 985
463b4e47
AJ
986 ec_read(EEEPC_EC_FAN_PWM, &value);
987 return value * 255 / 100;
e1faa9da
CC
988}
989
990static void eeepc_set_fan_pwm(int value)
991{
c73bad74 992 value = clamp_val(value, 0, 255);
04dcd84b 993 value = value * 100 / 255;
463b4e47 994 ec_write(EEEPC_EC_FAN_PWM, value);
e1faa9da
CC
995}
996
997static int eeepc_get_fan_rpm(void)
998{
463b4e47
AJ
999 u8 high = 0;
1000 u8 low = 0;
e1faa9da 1001
463b4e47
AJ
1002 ec_read(EEEPC_EC_FAN_HRPM, &high);
1003 ec_read(EEEPC_EC_FAN_LRPM, &low);
1004 return high << 8 | low;
e1faa9da
CC
1005}
1006
1007static int eeepc_get_fan_ctrl(void)
1008{
463b4e47 1009 u8 value = 0;
e1faa9da 1010
463b4e47 1011 ec_read(EEEPC_EC_FAN_CTRL, &value);
48718688
AJ
1012 if (value & 0x02)
1013 return 1; /* manual */
1014 else
1015 return 2; /* automatic */
e1faa9da
CC
1016}
1017
1018static void eeepc_set_fan_ctrl(int manual)
1019{
463b4e47 1020 u8 value = 0;
e1faa9da 1021
463b4e47 1022 ec_read(EEEPC_EC_FAN_CTRL, &value);
48718688 1023 if (manual == 1)
e1faa9da
CC
1024 value |= 0x02;
1025 else
1026 value &= ~0x02;
463b4e47 1027 ec_write(EEEPC_EC_FAN_CTRL, value);
e1faa9da
CC
1028}
1029
1030static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
1031{
1032 int rv, value;
1033
95369a73
PB
1034 rv = parse_arg(buf, &value);
1035 if (rv < 0)
1036 return rv;
1037 set(value);
1038 return count;
e1faa9da
CC
1039}
1040
1041static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
1042{
1043 return sprintf(buf, "%d\n", get());
1044}
1045
28ac85f7 1046#define EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
48d4a5b2 1047 static ssize_t _name##_show(struct device *dev, \
e1faa9da
CC
1048 struct device_attribute *attr, \
1049 char *buf) \
1050 { \
1ec9d399 1051 return show_sys_hwmon(_get, buf); \
28ac85f7
FK
1052 }
1053
1054#define EEEPC_SENSOR_STORE_FUNC(_name, _set) \
48d4a5b2 1055 static ssize_t _name##_store(struct device *dev, \
e1faa9da
CC
1056 struct device_attribute *attr, \
1057 const char *buf, size_t count) \
1058 { \
1ec9d399 1059 return store_sys_hwmon(_set, buf, count); \
28ac85f7
FK
1060 }
1061
48d4a5b2 1062#define EEEPC_CREATE_SENSOR_ATTR_RW(_name, _get, _set) \
28ac85f7
FK
1063 EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
1064 EEEPC_SENSOR_STORE_FUNC(_name, _set) \
48d4a5b2
FK
1065 static DEVICE_ATTR_RW(_name)
1066
1067#define EEEPC_CREATE_SENSOR_ATTR_RO(_name, _get) \
1068 EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
1069 static DEVICE_ATTR_RO(_name)
e1faa9da 1070
48d4a5b2
FK
1071EEEPC_CREATE_SENSOR_ATTR_RO(fan1_input, eeepc_get_fan_rpm);
1072EEEPC_CREATE_SENSOR_ATTR_RW(pwm1, eeepc_get_fan_pwm,
1073 eeepc_set_fan_pwm);
1074EEEPC_CREATE_SENSOR_ATTR_RW(pwm1_enable, eeepc_get_fan_ctrl,
1075 eeepc_set_fan_ctrl);
e1faa9da 1076
f0c34c97
GR
1077static struct attribute *hwmon_attrs[] = {
1078 &dev_attr_pwm1.attr,
1079 &dev_attr_fan1_input.attr,
1080 &dev_attr_pwm1_enable.attr,
e1faa9da
CC
1081 NULL
1082};
f0c34c97 1083ATTRIBUTE_GROUPS(hwmon);
a9df80c5 1084
854c7836 1085static int eeepc_hwmon_init(struct eeepc_laptop *eeepc)
a9df80c5 1086{
f0c34c97 1087 struct device *dev = &eeepc->platform_device->dev;
52bbe3c7 1088 struct device *hwmon;
7de39389 1089
f0c34c97
GR
1090 hwmon = devm_hwmon_device_register_with_groups(dev, "eeepc", NULL,
1091 hwmon_groups);
52bbe3c7
AJ
1092 if (IS_ERR(hwmon)) {
1093 pr_err("Could not register eeepc hwmon device\n");
52bbe3c7 1094 return PTR_ERR(hwmon);
a8258069 1095 }
f0c34c97 1096 return 0;
a9df80c5
CC
1097}
1098
52bbe3c7
AJ
1099/*
1100 * Backlight device
1101 */
1102static int read_brightness(struct backlight_device *bd)
a9df80c5 1103{
854c7836
AJ
1104 struct eeepc_laptop *eeepc = bl_get_data(bd);
1105
1106 return get_acpi(eeepc, CM_ASL_PANELBRIGHT);
a5fa429b
CC
1107}
1108
52bbe3c7 1109static int set_brightness(struct backlight_device *bd, int value)
e1faa9da 1110{
854c7836 1111 struct eeepc_laptop *eeepc = bl_get_data(bd);
e1faa9da 1112
854c7836 1113 return set_acpi(eeepc, CM_ASL_PANELBRIGHT, value);
e1faa9da
CC
1114}
1115
52bbe3c7 1116static int update_bl_status(struct backlight_device *bd)
7de39389 1117{
52bbe3c7
AJ
1118 return set_brightness(bd, bd->props.brightness);
1119}
7de39389 1120
acc2472e 1121static const struct backlight_ops eeepcbl_ops = {
52bbe3c7
AJ
1122 .get_brightness = read_brightness,
1123 .update_status = update_bl_status,
1124};
7de39389 1125
854c7836 1126static int eeepc_backlight_notify(struct eeepc_laptop *eeepc)
52bbe3c7 1127{
854c7836 1128 struct backlight_device *bd = eeepc->backlight_device;
52bbe3c7 1129 int old = bd->props.brightness;
7de39389 1130
52bbe3c7 1131 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
7de39389 1132
52bbe3c7 1133 return old;
7de39389
CC
1134}
1135
854c7836 1136static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
7de39389 1137{
a19a6ee6 1138 struct backlight_properties props;
a5fa429b 1139 struct backlight_device *bd;
7334546a 1140
a19a6ee6 1141 memset(&props, 0, sizeof(struct backlight_properties));
bb7ca747 1142 props.type = BACKLIGHT_PLATFORM;
a19a6ee6 1143 props.max_brightness = 15;
854c7836 1144 bd = backlight_device_register(EEEPC_LAPTOP_FILE,
a19a6ee6
MG
1145 &eeepc->platform_device->dev, eeepc,
1146 &eeepcbl_ops, &props);
a5fa429b 1147 if (IS_ERR(bd)) {
19b53289 1148 pr_err("Could not register eeepc backlight device\n");
854c7836 1149 eeepc->backlight_device = NULL;
a5fa429b
CC
1150 return PTR_ERR(bd);
1151 }
854c7836 1152 eeepc->backlight_device = bd;
854c7836 1153 bd->props.brightness = read_brightness(bd);
a5fa429b
CC
1154 bd->props.power = FB_BLANK_UNBLANK;
1155 backlight_update_status(bd);
1156 return 0;
1157}
7de39389 1158
854c7836 1159static void eeepc_backlight_exit(struct eeepc_laptop *eeepc)
e1faa9da 1160{
854c7836
AJ
1161 if (eeepc->backlight_device)
1162 backlight_device_unregister(eeepc->backlight_device);
1163 eeepc->backlight_device = NULL;
52bbe3c7 1164}
7de39389 1165
7de39389 1166
52bbe3c7
AJ
1167/*
1168 * Input device (i.e. hotkeys)
1169 */
642e0447 1170static int eeepc_input_init(struct eeepc_laptop *eeepc)
52bbe3c7 1171{
642e0447
DT
1172 struct input_dev *input;
1173 int error;
3cd530b5 1174
642e0447 1175 input = input_allocate_device();
b222cca6 1176 if (!input)
642e0447 1177 return -ENOMEM;
07e84aa9 1178
642e0447
DT
1179 input->name = "Asus EeePC extra buttons";
1180 input->phys = EEEPC_LAPTOP_FILE "/input0";
1181 input->id.bustype = BUS_HOST;
1182 input->dev.parent = &eeepc->platform_device->dev;
7de39389 1183
642e0447
DT
1184 error = sparse_keymap_setup(input, eeepc_keymap, NULL);
1185 if (error) {
1186 pr_err("Unable to setup input device keymap\n");
1187 goto err_free_dev;
a5fa429b 1188 }
52bbe3c7 1189
642e0447
DT
1190 error = input_register_device(input);
1191 if (error) {
1192 pr_err("Unable to register input device\n");
1193 goto err_free_keymap;
e1faa9da 1194 }
52bbe3c7 1195
642e0447 1196 eeepc->inputdev = input;
f2a9d5e8 1197 return 0;
642e0447 1198
71e687dc 1199err_free_keymap:
642e0447 1200 sparse_keymap_free(input);
71e687dc 1201err_free_dev:
642e0447
DT
1202 input_free_device(input);
1203 return error;
f2a9d5e8
AJ
1204}
1205
854c7836 1206static void eeepc_input_exit(struct eeepc_laptop *eeepc)
e59f8796 1207{
854c7836 1208 if (eeepc->inputdev) {
c9db3efe 1209 sparse_keymap_free(eeepc->inputdev);
a7624b63 1210 input_unregister_device(eeepc->inputdev);
854c7836 1211 }
71e687dc 1212 eeepc->inputdev = NULL;
52bbe3c7 1213}
3c0eb510 1214
52bbe3c7
AJ
1215/*
1216 * ACPI driver
1217 */
ce6c468f
CC
1218static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
1219{
1220 if (!eeepc->inputdev)
1221 return ;
1222 if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
1223 pr_info("Unknown key %x pressed\n", event);
1224}
1225
a7624b63 1226static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
52bbe3c7 1227{
854c7836 1228 struct eeepc_laptop *eeepc = acpi_driver_data(device);
52bbe3c7 1229 u16 count;
3c0eb510 1230
52bbe3c7
AJ
1231 if (event > ACPI_MAX_SYS_NOTIFY)
1232 return;
a7624b63 1233 count = eeepc->event_count[event % 128]++;
854c7836
AJ
1234 acpi_bus_generate_netlink_event(device->pnp.device_class,
1235 dev_name(&device->dev), event,
52bbe3c7 1236 count);
3c0eb510 1237
325fb8e9 1238 /* Brightness events are special */
52bbe3c7 1239 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) {
52bbe3c7 1240
325fb8e9
AJ
1241 /* Ignore them completely if the acpi video driver is used */
1242 if (eeepc->backlight_device != NULL) {
1243 int old_brightness, new_brightness;
1244
1245 /* Update the backlight device. */
1246 old_brightness = eeepc_backlight_notify(eeepc);
1247
1248 /* Convert event to keypress (obsolescent hack) */
1249 new_brightness = event - NOTIFY_BRN_MIN;
1250
1251 if (new_brightness < old_brightness) {
1252 event = NOTIFY_BRN_MIN; /* brightness down */
1253 } else if (new_brightness > old_brightness) {
1254 event = NOTIFY_BRN_MAX; /* brightness up */
1255 } else {
1256 /*
1257 * no change in brightness - already at min/max,
1258 * event will be desired value (or else ignored)
1259 */
1260 }
ce6c468f 1261 eeepc_input_notify(eeepc, event);
52bbe3c7 1262 }
325fb8e9
AJ
1263 } else {
1264 /* Everything else is a bona-fide keypress event */
ce6c468f 1265 eeepc_input_notify(eeepc, event);
52bbe3c7 1266 }
52bbe3c7
AJ
1267}
1268
da8ba01d
AJ
1269static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
1270{
1271 const char *model;
1272
10ae4b56
CC
1273 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1274 if (!model)
1275 return;
1276
da8ba01d
AJ
1277 /*
1278 * Blacklist for setting cpufv (cpu speed).
1279 *
1280 * EeePC 4G ("701") implements CFVS, but it is not supported
1281 * by the pre-installed OS, and the original option to change it
1282 * in the BIOS setup screen was removed in later versions.
1283 *
1284 * Judging by the lack of "Super Hybrid Engine" on Asus product pages,
1285 * this applies to all "701" models (4G/4G Surf/2G Surf).
1286 *
1287 * So Asus made a deliberate decision not to support it on this model.
1288 * We have several reports that using it can cause the system to hang
1289 *
1290 * The hang has also been reported on a "702" (Model name "8G"?).
1291 *
1292 * We avoid dmi_check_system() / dmi_match(), because they use
1293 * substring matching. We don't want to affect the "701SD"
1294 * and "701SDX" models, because they do support S.H.E.
1295 */
da8ba01d
AJ
1296 if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
1297 eeepc->cpufv_disabled = true;
1298 pr_info("model %s does not officially support setting cpu "
1299 "speed\n", model);
1300 pr_info("cpufv disabled to avoid instability\n");
1301 }
10ae4b56
CC
1302
1303 /*
1304 * Blacklist for wlan hotplug
1305 *
1306 * Eeepc 1005HA doesn't work like others models and don't need the
1307 * hotplug code. In fact, current hotplug code seems to unplug another
1308 * device...
1309 */
ced69c59
AJ
1310 if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 ||
1311 strcmp(model, "1005PE") == 0) {
10ae4b56
CC
1312 eeepc->hotplug_disabled = true;
1313 pr_info("wlan hotplug disabled\n");
1314 }
da8ba01d
AJ
1315}
1316
854c7836 1317static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
52bbe3c7
AJ
1318{
1319 int dummy;
1320
c8440336 1321 /* Some BIOSes do not report cm although it is available.
52bbe3c7 1322 Check if cm_getv[cm] works and, if yes, assume cm should be set. */
a7624b63
AJ
1323 if (!(eeepc->cm_supported & (1 << cm))
1324 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
52bbe3c7
AJ
1325 pr_info("%s (%x) not reported by BIOS,"
1326 " enabling anyway\n", name, 1 << cm);
a7624b63 1327 eeepc->cm_supported |= 1 << cm;
52bbe3c7
AJ
1328 }
1329}
1330
854c7836 1331static void cmsg_quirks(struct eeepc_laptop *eeepc)
52bbe3c7 1332{
854c7836
AJ
1333 cmsg_quirk(eeepc, CM_ASL_LID, "LID");
1334 cmsg_quirk(eeepc, CM_ASL_TYPE, "TYPE");
1335 cmsg_quirk(eeepc, CM_ASL_PANELPOWER, "PANELPOWER");
1336 cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");
52bbe3c7
AJ
1337}
1338
b859f159 1339static int eeepc_acpi_init(struct eeepc_laptop *eeepc)
52bbe3c7
AJ
1340{
1341 unsigned int init_flags;
e59f8796
EC
1342 int result;
1343
71e687dc 1344 result = acpi_bus_get_status(eeepc->device);
1e779854 1345 if (result)
52bbe3c7 1346 return result;
71e687dc 1347 if (!eeepc->device->status.present) {
52bbe3c7
AJ
1348 pr_err("Hotkey device not present, aborting\n");
1349 return -ENODEV;
1350 }
cede2cb6 1351
52bbe3c7
AJ
1352 init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
1353 pr_notice("Hotkey init flags 0x%x\n", init_flags);
1354
a7624b63 1355 if (write_acpi_int(eeepc->handle, "INIT", init_flags)) {
52bbe3c7
AJ
1356 pr_err("Hotkey initialization failed\n");
1357 return -ENODEV;
e59f8796 1358 }
52bbe3c7
AJ
1359
1360 /* get control methods supported */
a7624b63 1361 if (read_acpi_int(eeepc->handle, "CMSG", &eeepc->cm_supported)) {
52bbe3c7
AJ
1362 pr_err("Get control methods supported failed\n");
1363 return -ENODEV;
dc56ad9b 1364 }
854c7836 1365 cmsg_quirks(eeepc);
a7624b63 1366 pr_info("Get control methods supported: 0x%x\n", eeepc->cm_supported);
2b56f1c1 1367
3c0eb510
CC
1368 return 0;
1369}
1370
b859f159 1371static void eeepc_enable_camera(struct eeepc_laptop *eeepc)
52bbe3c7
AJ
1372{
1373 /*
1374 * If the following call to set_acpi() fails, it's because there's no
1375 * camera so we can ignore the error.
1376 */
854c7836
AJ
1377 if (get_acpi(eeepc, CM_ASL_CAMERA) == 0)
1378 set_acpi(eeepc, CM_ASL_CAMERA, 1);
52bbe3c7
AJ
1379}
1380
854c7836
AJ
1381static bool eeepc_device_present;
1382
b859f159 1383static int eeepc_acpi_add(struct acpi_device *device)
e59f8796 1384{
854c7836 1385 struct eeepc_laptop *eeepc;
e59f8796
EC
1386 int result;
1387
a7624b63
AJ
1388 pr_notice(EEEPC_LAPTOP_NAME "\n");
1389 eeepc = kzalloc(sizeof(struct eeepc_laptop), GFP_KERNEL);
1390 if (!eeepc)
1e779854 1391 return -ENOMEM;
a7624b63
AJ
1392 eeepc->handle = device->handle;
1393 strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
1394 strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
1395 device->driver_data = eeepc;
71e687dc 1396 eeepc->device = device;
cede2cb6 1397
322a1356
CC
1398 eeepc->hotplug_disabled = hotplug_disabled;
1399
da8ba01d
AJ
1400 eeepc_dmi_check(eeepc);
1401
71e687dc 1402 result = eeepc_acpi_init(eeepc);
e59f8796 1403 if (result)
9db106be 1404 goto fail_platform;
854c7836 1405 eeepc_enable_camera(eeepc);
7de39389 1406
854c7836
AJ
1407 /*
1408 * Register the platform device first. It is used as a parent for the
1409 * sub-devices below.
1410 *
1411 * Note that if there are multiple instances of this ACPI device it
1412 * will bail out, because the platform device is registered with a
1413 * fixed name. Of course it doesn't make sense to have more than one,
1414 * and machine-specific scripts find the fixed name convenient. But
1415 * It's also good for us to exclude multiple instances because both
1416 * our hwmon and our wlan rfkill subdevice use global ACPI objects
1417 * (the EC and the wlan PCI slot respectively).
1418 */
1419 result = eeepc_platform_init(eeepc);
e59f8796 1420 if (result)
9db106be 1421 goto fail_platform;
1ddec2f9
CC
1422
1423 if (!acpi_video_backlight_support()) {
854c7836 1424 result = eeepc_backlight_init(eeepc);
1ddec2f9
CC
1425 if (result)
1426 goto fail_backlight;
39a3e17e 1427 } else {
9db106be 1428 pr_info("Backlight controlled by ACPI video driver\n");
39a3e17e 1429 }
1ddec2f9 1430
854c7836 1431 result = eeepc_input_init(eeepc);
f2a9d5e8
AJ
1432 if (result)
1433 goto fail_input;
1434
854c7836 1435 result = eeepc_hwmon_init(eeepc);
1ddec2f9
CC
1436 if (result)
1437 goto fail_hwmon;
1438
854c7836 1439 result = eeepc_led_init(eeepc);
3c0eb510
CC
1440 if (result)
1441 goto fail_led;
1442
854c7836 1443 result = eeepc_rfkill_init(eeepc);
7de39389
CC
1444 if (result)
1445 goto fail_rfkill;
1446
854c7836 1447 eeepc_device_present = true;
e59f8796 1448 return 0;
1e779854 1449
7de39389 1450fail_rfkill:
854c7836 1451 eeepc_led_exit(eeepc);
3c0eb510 1452fail_led:
1ddec2f9 1453fail_hwmon:
854c7836 1454 eeepc_input_exit(eeepc);
f2a9d5e8 1455fail_input:
854c7836 1456 eeepc_backlight_exit(eeepc);
1ddec2f9 1457fail_backlight:
854c7836 1458 eeepc_platform_exit(eeepc);
9db106be 1459fail_platform:
a7624b63 1460 kfree(eeepc);
1e779854 1461
e59f8796
EC
1462 return result;
1463}
1464
51fac838 1465static int eeepc_acpi_remove(struct acpi_device *device)
1e779854 1466{
854c7836 1467 struct eeepc_laptop *eeepc = acpi_driver_data(device);
1e779854 1468
854c7836
AJ
1469 eeepc_backlight_exit(eeepc);
1470 eeepc_rfkill_exit(eeepc);
1471 eeepc_input_exit(eeepc);
854c7836
AJ
1472 eeepc_led_exit(eeepc);
1473 eeepc_platform_exit(eeepc);
1e779854 1474
a7624b63 1475 kfree(eeepc);
1e779854
AJ
1476 return 0;
1477}
1478
52bbe3c7
AJ
1479
1480static const struct acpi_device_id eeepc_device_ids[] = {
a7624b63 1481 {EEEPC_ACPI_HID, 0},
52bbe3c7
AJ
1482 {"", 0},
1483};
1484MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
1485
a7624b63
AJ
1486static struct acpi_driver eeepc_acpi_driver = {
1487 .name = EEEPC_LAPTOP_NAME,
1488 .class = EEEPC_ACPI_CLASS,
52bbe3c7
AJ
1489 .owner = THIS_MODULE,
1490 .ids = eeepc_device_ids,
1491 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1492 .ops = {
a7624b63
AJ
1493 .add = eeepc_acpi_add,
1494 .remove = eeepc_acpi_remove,
1495 .notify = eeepc_acpi_notify,
52bbe3c7
AJ
1496 },
1497};
1498
1499
1e779854
AJ
1500static int __init eeepc_laptop_init(void)
1501{
1502 int result;
1503
22072e92 1504 result = platform_driver_register(&platform_driver);
1e779854
AJ
1505 if (result < 0)
1506 return result;
22072e92 1507
a7624b63 1508 result = acpi_bus_register_driver(&eeepc_acpi_driver);
22072e92
AJ
1509 if (result < 0)
1510 goto fail_acpi_driver;
642e0447 1511
854c7836 1512 if (!eeepc_device_present) {
22072e92
AJ
1513 result = -ENODEV;
1514 goto fail_no_device;
1e779854 1515 }
642e0447 1516
1e779854 1517 return 0;
22072e92
AJ
1518
1519fail_no_device:
a7624b63 1520 acpi_bus_unregister_driver(&eeepc_acpi_driver);
22072e92
AJ
1521fail_acpi_driver:
1522 platform_driver_unregister(&platform_driver);
1523 return result;
1e779854
AJ
1524}
1525
1526static void __exit eeepc_laptop_exit(void)
1527{
a7624b63 1528 acpi_bus_unregister_driver(&eeepc_acpi_driver);
22072e92 1529 platform_driver_unregister(&platform_driver);
1e779854
AJ
1530}
1531
e59f8796
EC
1532module_init(eeepc_laptop_init);
1533module_exit(eeepc_laptop_exit);