]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/platform/x86/eeepc-laptop.c
eeepc-laptop: no need to check argument of set_brightness()
[mirror_ubuntu-hirsute-kernel.git] / drivers / platform / x86 / eeepc-laptop.c
CommitLineData
e59f8796
EC
1/*
2 * eepc-laptop.c - Asus Eee PC extras
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>
e59f8796
EC
30#include <acpi/acpi_drivers.h>
31#include <acpi/acpi_bus.h>
32#include <linux/uaccess.h>
a195dcdc
MG
33#include <linux/input.h>
34#include <linux/rfkill.h>
5740294c 35#include <linux/pci.h>
2b121bc2 36#include <linux/pci_hotplug.h>
3c0eb510 37#include <linux/leds.h>
e59f8796
EC
38
39#define EEEPC_LAPTOP_VERSION "0.1"
40
41#define EEEPC_HOTK_NAME "Eee PC Hotkey Driver"
42#define EEEPC_HOTK_FILE "eeepc"
43#define EEEPC_HOTK_CLASS "hotkey"
44#define EEEPC_HOTK_DEVICE_NAME "Hotkey"
45#define EEEPC_HOTK_HID "ASUS010"
46
e59f8796
EC
47
48/*
49 * Definitions for Asus EeePC
50 */
51#define NOTIFY_WLAN_ON 0x10
a5fa429b
CC
52#define NOTIFY_BRN_MIN 0x20
53#define NOTIFY_BRN_MAX 0x2f
e59f8796
EC
54
55enum {
56 DISABLE_ASL_WLAN = 0x0001,
57 DISABLE_ASL_BLUETOOTH = 0x0002,
58 DISABLE_ASL_IRDA = 0x0004,
59 DISABLE_ASL_CAMERA = 0x0008,
60 DISABLE_ASL_TV = 0x0010,
61 DISABLE_ASL_GPS = 0x0020,
62 DISABLE_ASL_DISPLAYSWITCH = 0x0040,
63 DISABLE_ASL_MODEM = 0x0080,
b7b700d4
CC
64 DISABLE_ASL_CARDREADER = 0x0100,
65 DISABLE_ASL_3G = 0x0200,
66 DISABLE_ASL_WIMAX = 0x0400,
67 DISABLE_ASL_HWCF = 0x0800
e59f8796
EC
68};
69
70enum {
71 CM_ASL_WLAN = 0,
72 CM_ASL_BLUETOOTH,
73 CM_ASL_IRDA,
74 CM_ASL_1394,
75 CM_ASL_CAMERA,
76 CM_ASL_TV,
77 CM_ASL_GPS,
78 CM_ASL_DVDROM,
79 CM_ASL_DISPLAYSWITCH,
80 CM_ASL_PANELBRIGHT,
81 CM_ASL_BIOSFLASH,
82 CM_ASL_ACPIFLASH,
83 CM_ASL_CPUFV,
84 CM_ASL_CPUTEMPERATURE,
85 CM_ASL_FANCPU,
86 CM_ASL_FANCHASSIS,
87 CM_ASL_USBPORT1,
88 CM_ASL_USBPORT2,
89 CM_ASL_USBPORT3,
90 CM_ASL_MODEM,
91 CM_ASL_CARDREADER,
b7b700d4
CC
92 CM_ASL_3G,
93 CM_ASL_WIMAX,
94 CM_ASL_HWCF,
95 CM_ASL_LID,
96 CM_ASL_TYPE,
97 CM_ASL_PANELPOWER, /*P901*/
98 CM_ASL_TPD
e59f8796
EC
99};
100
14109461 101static const char *cm_getv[] = {
3af9bfcb 102 "WLDG", "BTHG", NULL, NULL,
e59f8796
EC
103 "CAMG", NULL, NULL, NULL,
104 NULL, "PBLG", NULL, NULL,
105 "CFVG", NULL, NULL, NULL,
106 "USBG", NULL, NULL, "MODG",
b7b700d4
CC
107 "CRDG", "M3GG", "WIMG", "HWCF",
108 "LIDG", "TYPE", "PBPG", "TPDG"
e59f8796
EC
109};
110
14109461 111static const char *cm_setv[] = {
3af9bfcb 112 "WLDS", "BTHS", NULL, NULL,
e59f8796
EC
113 "CAMS", NULL, NULL, NULL,
114 "SDSP", "PBLS", "HDPS", NULL,
115 "CFVS", NULL, NULL, NULL,
116 "USBG", NULL, NULL, "MODS",
b7b700d4
CC
117 "CRDS", "M3GS", "WIMS", NULL,
118 NULL, NULL, "PBPS", "TPDS"
e59f8796
EC
119};
120
e1faa9da
CC
121#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0."
122
123#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */
124#define EEEPC_EC_SC02 0x63
125#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */
126#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */
127#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */
128#define EEEPC_EC_SFB3 0xD3
129
e59f8796
EC
130/*
131 * This is the main structure, we can use it to store useful information
132 * about the hotk device
133 */
134struct eeepc_hotk {
135 struct acpi_device *device; /* the device we are in */
136 acpi_handle handle; /* the handle of the hotk device */
137 u32 cm_supported; /* the control methods supported
138 by this BIOS */
139 uint init_flag; /* Init flags */
140 u16 event_count[128]; /* count for each event */
a195dcdc
MG
141 struct input_dev *inputdev;
142 u16 *keycode_map;
7de39389
CC
143 struct rfkill *wlan_rfkill;
144 struct rfkill *bluetooth_rfkill;
3cd530b5 145 struct rfkill *wwan3g_rfkill;
d1ec9c3d 146 struct rfkill *wimax_rfkill;
2b121bc2 147 struct hotplug_slot *hotplug_slot;
dcf443b5 148 struct mutex hotplug_lock;
e59f8796
EC
149};
150
151/* The actual device the driver binds to */
152static struct eeepc_hotk *ehotk;
153
154/* Platform device/driver */
c200da5d
AJ
155static int eeepc_hotk_thaw(struct device *device);
156static int eeepc_hotk_restore(struct device *device);
157
158static struct dev_pm_ops eeepc_pm_ops = {
159 .thaw = eeepc_hotk_thaw,
160 .restore = eeepc_hotk_restore,
161};
162
e59f8796
EC
163static struct platform_driver platform_driver = {
164 .driver = {
165 .name = EEEPC_HOTK_FILE,
166 .owner = THIS_MODULE,
c200da5d 167 .pm = &eeepc_pm_ops,
e59f8796
EC
168 }
169};
170
171static struct platform_device *platform_device;
172
a195dcdc
MG
173struct key_entry {
174 char type;
175 u8 code;
176 u16 keycode;
177};
178
179enum { KE_KEY, KE_END };
180
181static struct key_entry eeepc_keymap[] = {
182 /* Sleep already handled via generic ACPI code */
183 {KE_KEY, 0x10, KEY_WLAN },
978605c4 184 {KE_KEY, 0x11, KEY_WLAN },
a195dcdc
MG
185 {KE_KEY, 0x12, KEY_PROG1 },
186 {KE_KEY, 0x13, KEY_MUTE },
187 {KE_KEY, 0x14, KEY_VOLUMEDOWN },
188 {KE_KEY, 0x15, KEY_VOLUMEUP },
b5f6f265
MG
189 {KE_KEY, 0x1a, KEY_COFFEE },
190 {KE_KEY, 0x1b, KEY_ZOOM },
191 {KE_KEY, 0x1c, KEY_PROG2 },
192 {KE_KEY, 0x1d, KEY_PROG3 },
64b86b65
DS
193 {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN },
194 {KE_KEY, NOTIFY_BRN_MIN + 2, KEY_BRIGHTNESSUP },
a195dcdc
MG
195 {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
196 {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
197 {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
198 {KE_END, 0},
199};
200
e59f8796
EC
201/*
202 * The hotkey driver declaration
203 */
204static int eeepc_hotk_add(struct acpi_device *device);
205static int eeepc_hotk_remove(struct acpi_device *device, int type);
d9b9bd7b 206static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
e59f8796
EC
207
208static const struct acpi_device_id eeepc_device_ids[] = {
209 {EEEPC_HOTK_HID, 0},
210 {"", 0},
211};
212MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
213
214static struct acpi_driver eeepc_hotk_driver = {
215 .name = EEEPC_HOTK_NAME,
216 .class = EEEPC_HOTK_CLASS,
eacec303 217 .owner = THIS_MODULE,
e59f8796 218 .ids = eeepc_device_ids,
d9b9bd7b 219 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
e59f8796
EC
220 .ops = {
221 .add = eeepc_hotk_add,
222 .remove = eeepc_hotk_remove,
d9b9bd7b 223 .notify = eeepc_hotk_notify,
e59f8796
EC
224 },
225};
226
2b121bc2
CC
227/* PCI hotplug ops */
228static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value);
229
230static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
231 .owner = THIS_MODULE,
232 .get_adapter_status = eeepc_get_adapter_status,
233 .get_power_status = eeepc_get_adapter_status,
234};
235
a5fa429b
CC
236/* The backlight device /sys/class/backlight */
237static struct backlight_device *eeepc_backlight_device;
238
e1faa9da
CC
239/* The hwmon device */
240static struct device *eeepc_hwmon_device;
241
a5fa429b
CC
242/*
243 * The backlight class declaration
244 */
245static int read_brightness(struct backlight_device *bd);
246static int update_bl_status(struct backlight_device *bd);
247static struct backlight_ops eeepcbl_ops = {
248 .get_brightness = read_brightness,
249 .update_status = update_bl_status,
250};
251
e59f8796
EC
252MODULE_AUTHOR("Corentin Chary, Eric Cooper");
253MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
254MODULE_LICENSE("GPL");
255
256/*
257 * ACPI Helpers
258 */
259static int write_acpi_int(acpi_handle handle, const char *method, int val,
260 struct acpi_buffer *output)
261{
262 struct acpi_object_list params;
263 union acpi_object in_obj;
264 acpi_status status;
265
266 params.count = 1;
267 params.pointer = &in_obj;
268 in_obj.type = ACPI_TYPE_INTEGER;
269 in_obj.integer.value = val;
270
271 status = acpi_evaluate_object(handle, (char *)method, &params, output);
272 return (status == AE_OK ? 0 : -1);
273}
274
275static int read_acpi_int(acpi_handle handle, const char *method, int *val)
276{
277 acpi_status status;
27663c58 278 unsigned long long result;
e59f8796
EC
279
280 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
281 if (ACPI_FAILURE(status)) {
282 *val = -1;
283 return -1;
284 } else {
285 *val = result;
286 return 0;
287 }
288}
289
290static int set_acpi(int cm, int value)
291{
13f70029
AJ
292 const char *method = cm_setv[cm];
293
294 if (method == NULL)
295 return -ENODEV;
296 if ((ehotk->cm_supported & (0x1 << cm)) == 0)
297 return -ENODEV;
298
299 if (write_acpi_int(ehotk->handle, method, value, NULL))
300 pr_warning("Error writing %s\n", method);
e59f8796
EC
301 return 0;
302}
303
304static int get_acpi(int cm)
305{
13f70029
AJ
306 const char *method = cm_getv[cm];
307 int value;
308
309 if (method == NULL)
310 return -ENODEV;
311 if ((ehotk->cm_supported & (0x1 << cm)) == 0)
312 return -ENODEV;
313
314 if (read_acpi_int(ehotk->handle, method, &value))
315 pr_warning("Error reading %s\n", method);
e59f8796
EC
316 return value;
317}
318
a5fa429b
CC
319/*
320 * Backlight
321 */
322static int read_brightness(struct backlight_device *bd)
323{
324 return get_acpi(CM_ASL_PANELBRIGHT);
325}
326
327static int set_brightness(struct backlight_device *bd, int value)
328{
a5fa429b
CC
329 return set_acpi(CM_ASL_PANELBRIGHT, value);
330}
331
332static int update_bl_status(struct backlight_device *bd)
333{
334 return set_brightness(bd, bd->props.brightness);
335}
336
a195dcdc
MG
337/*
338 * Rfkill helpers
339 */
340
19d337df 341static bool eeepc_wlan_rfkill_blocked(void)
a195dcdc
MG
342{
343 if (get_acpi(CM_ASL_WLAN) == 1)
19d337df
JB
344 return false;
345 return true;
a195dcdc
MG
346}
347
19d337df 348static int eeepc_rfkill_set(void *data, bool blocked)
a195dcdc 349{
19d337df 350 unsigned long asl = (unsigned long)data;
58ce48a9 351 return set_acpi(asl, !blocked);
a195dcdc
MG
352}
353
19d337df
JB
354static const struct rfkill_ops eeepc_rfkill_ops = {
355 .set_block = eeepc_rfkill_set,
356};
a195dcdc 357
dcb73eed 358static void __devinit eeepc_enable_camera(void)
cede2cb6
PE
359{
360 /*
361 * If the following call to set_acpi() fails, it's because there's no
362 * camera so we can ignore the error.
363 */
80f0c895
LN
364 if (get_acpi(CM_ASL_CAMERA) == 0)
365 set_acpi(CM_ASL_CAMERA, 1);
cede2cb6
PE
366}
367
e59f8796
EC
368/*
369 * Sys helpers
370 */
371static int parse_arg(const char *buf, unsigned long count, int *val)
372{
373 if (!count)
374 return 0;
375 if (sscanf(buf, "%i", val) != 1)
376 return -EINVAL;
377 return count;
378}
379
380static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
381{
382 int rv, value;
383
384 rv = parse_arg(buf, count, &value);
385 if (rv > 0)
f36509e7
CC
386 value = set_acpi(cm, value);
387 if (value < 0)
6dff29b6 388 return -EIO;
e59f8796
EC
389 return rv;
390}
391
392static ssize_t show_sys_acpi(int cm, char *buf)
393{
f36509e7
CC
394 int value = get_acpi(cm);
395
396 if (value < 0)
6dff29b6 397 return -EIO;
f36509e7 398 return sprintf(buf, "%d\n", value);
e59f8796
EC
399}
400
6dff29b6 401#define EEEPC_CREATE_DEVICE_ATTR(_name, _mode, _cm) \
e59f8796
EC
402 static ssize_t show_##_name(struct device *dev, \
403 struct device_attribute *attr, \
404 char *buf) \
405 { \
406 return show_sys_acpi(_cm, buf); \
407 } \
408 static ssize_t store_##_name(struct device *dev, \
409 struct device_attribute *attr, \
410 const char *buf, size_t count) \
411 { \
412 return store_sys_acpi(_cm, buf, count); \
413 } \
414 static struct device_attribute dev_attr_##_name = { \
415 .attr = { \
416 .name = __stringify(_name), \
6dff29b6 417 .mode = _mode }, \
e59f8796
EC
418 .show = show_##_name, \
419 .store = store_##_name, \
420 }
421
6dff29b6
AJ
422EEEPC_CREATE_DEVICE_ATTR(camera, 0644, CM_ASL_CAMERA);
423EEEPC_CREATE_DEVICE_ATTR(cardr, 0644, CM_ASL_CARDREADER);
424EEEPC_CREATE_DEVICE_ATTR(disp, 0200, CM_ASL_DISPLAYSWITCH);
b31d0fde
CC
425
426struct eeepc_cpufv {
427 int num;
428 int cur;
429};
430
431static int get_cpufv(struct eeepc_cpufv *c)
432{
433 c->cur = get_acpi(CM_ASL_CPUFV);
434 c->num = (c->cur >> 8) & 0xff;
435 c->cur &= 0xff;
436 if (c->cur < 0 || c->num <= 0 || c->num > 12)
437 return -ENODEV;
438 return 0;
439}
440
441static ssize_t show_available_cpufv(struct device *dev,
442 struct device_attribute *attr,
443 char *buf)
444{
445 struct eeepc_cpufv c;
446 int i;
447 ssize_t len = 0;
448
449 if (get_cpufv(&c))
450 return -ENODEV;
451 for (i = 0; i < c.num; i++)
452 len += sprintf(buf + len, "%d ", i);
453 len += sprintf(buf + len, "\n");
454 return len;
455}
456
457static ssize_t show_cpufv(struct device *dev,
458 struct device_attribute *attr,
459 char *buf)
460{
461 struct eeepc_cpufv c;
462
463 if (get_cpufv(&c))
464 return -ENODEV;
465 return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);
466}
467
468static ssize_t store_cpufv(struct device *dev,
469 struct device_attribute *attr,
470 const char *buf, size_t count)
471{
472 struct eeepc_cpufv c;
473 int rv, value;
474
475 if (get_cpufv(&c))
476 return -ENODEV;
477 rv = parse_arg(buf, count, &value);
478 if (rv < 0)
479 return rv;
480 if (!rv || value < 0 || value >= c.num)
481 return -EINVAL;
482 set_acpi(CM_ASL_CPUFV, value);
483 return rv;
484}
485
486static struct device_attribute dev_attr_cpufv = {
487 .attr = {
488 .name = "cpufv",
489 .mode = 0644 },
490 .show = show_cpufv,
491 .store = store_cpufv
492};
493
494static struct device_attribute dev_attr_available_cpufv = {
495 .attr = {
496 .name = "available_cpufv",
497 .mode = 0444 },
498 .show = show_available_cpufv
499};
e59f8796
EC
500
501static struct attribute *platform_attributes[] = {
502 &dev_attr_camera.attr,
503 &dev_attr_cardr.attr,
504 &dev_attr_disp.attr,
158ca1d7 505 &dev_attr_cpufv.attr,
b31d0fde 506 &dev_attr_available_cpufv.attr,
e59f8796
EC
507 NULL
508};
509
510static struct attribute_group platform_attribute_group = {
511 .attrs = platform_attributes
512};
513
3c0eb510
CC
514/*
515 * LEDs
516 */
517/*
518 * These functions actually update the LED's, and are called from a
519 * workqueue. By doing this as separate work rather than when the LED
520 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
521 * potentially bad time, such as a timer interrupt.
522 */
523static int tpd_led_wk;
524
525static void tpd_led_update(struct work_struct *ignored)
526{
527 int value = tpd_led_wk;
528 set_acpi(CM_ASL_TPD, value);
529}
530
531static struct workqueue_struct *led_workqueue;
532static DECLARE_WORK(tpd_led_work, tpd_led_update);
533
534static void tpd_led_set(struct led_classdev *led_cdev,
535 enum led_brightness value)
536{
537 tpd_led_wk = (value > 0) ? 1 : 0;
538 queue_work(led_workqueue, &tpd_led_work);
539}
540
541static struct led_classdev tpd_led = {
542 .name = "eeepc::touchpad",
543 .brightness_set = tpd_led_set,
544 .max_brightness = 1
545};
546
e59f8796
EC
547/*
548 * Hotkey functions
549 */
a195dcdc
MG
550static struct key_entry *eepc_get_entry_by_scancode(int code)
551{
552 struct key_entry *key;
553
554 for (key = eeepc_keymap; key->type != KE_END; key++)
555 if (code == key->code)
556 return key;
557
558 return NULL;
559}
560
561static struct key_entry *eepc_get_entry_by_keycode(int code)
562{
563 struct key_entry *key;
564
565 for (key = eeepc_keymap; key->type != KE_END; key++)
566 if (code == key->keycode && key->type == KE_KEY)
567 return key;
568
569 return NULL;
570}
571
572static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
573{
574 struct key_entry *key = eepc_get_entry_by_scancode(scancode);
575
576 if (key && key->type == KE_KEY) {
577 *keycode = key->keycode;
578 return 0;
579 }
580
581 return -EINVAL;
582}
583
584static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
585{
586 struct key_entry *key;
587 int old_keycode;
588
589 if (keycode < 0 || keycode > KEY_MAX)
590 return -EINVAL;
591
592 key = eepc_get_entry_by_scancode(scancode);
593 if (key && key->type == KE_KEY) {
594 old_keycode = key->keycode;
595 key->keycode = keycode;
596 set_bit(keycode, dev->keybit);
597 if (!eepc_get_entry_by_keycode(old_keycode))
598 clear_bit(old_keycode, dev->keybit);
599 return 0;
600 }
601
602 return -EINVAL;
603}
604
dbfa3ba9
CC
605static void cmsg_quirk(int cm, const char *name)
606{
607 int dummy;
608
609 /* Some BIOSes do not report cm although it is avaliable.
610 Check if cm_getv[cm] works and, if yes, assume cm should be set. */
611 if (!(ehotk->cm_supported & (1 << cm))
612 && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) {
613 pr_info("%s (%x) not reported by BIOS,"
614 " enabling anyway\n", name, 1 << cm);
615 ehotk->cm_supported |= 1 << cm;
616 }
617}
618
619static void cmsg_quirks(void)
620{
621 cmsg_quirk(CM_ASL_LID, "LID");
622 cmsg_quirk(CM_ASL_TYPE, "TYPE");
623 cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER");
624 cmsg_quirk(CM_ASL_TPD, "TPD");
625}
626
e59f8796
EC
627static int eeepc_hotk_check(void)
628{
629 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
630 int result;
631
632 result = acpi_bus_get_status(ehotk->device);
633 if (result)
634 return result;
635 if (ehotk->device->status.present) {
636 if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
637 &buffer)) {
19b53289 638 pr_err("Hotkey initialization failed\n");
e59f8796
EC
639 return -ENODEV;
640 } else {
19b53289 641 pr_notice("Hotkey init flags 0x%x\n", ehotk->init_flag);
e59f8796
EC
642 }
643 /* get control methods supported */
644 if (read_acpi_int(ehotk->handle, "CMSG"
645 , &ehotk->cm_supported)) {
19b53289 646 pr_err("Get control methods supported failed\n");
e59f8796
EC
647 return -ENODEV;
648 } else {
dbfa3ba9 649 cmsg_quirks();
19b53289
JP
650 pr_info("Get control methods supported: 0x%x\n",
651 ehotk->cm_supported);
e59f8796
EC
652 }
653 } else {
19b53289 654 pr_err("Hotkey device not present, aborting\n");
e59f8796
EC
655 return -EINVAL;
656 }
657 return 0;
658}
659
64b86b65 660static int notify_brn(void)
a5fa429b 661{
64b86b65 662 /* returns the *previous* brightness, or -1 */
a5fa429b 663 struct backlight_device *bd = eeepc_backlight_device;
a2a1d36c
AJ
664 int old = bd->props.brightness;
665
666 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
667
668 return old;
a5fa429b
CC
669}
670
2b121bc2
CC
671static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
672 u8 *value)
673{
674 int val = get_acpi(CM_ASL_WLAN);
675
676 if (val == 1 || val == 0)
677 *value = val;
678 else
679 return -EINVAL;
680
681 return 0;
682}
683
58ce48a9 684static void eeepc_rfkill_hotplug(void)
5740294c
MG
685{
686 struct pci_dev *dev;
6d41839e 687 struct pci_bus *bus;
58ce48a9 688 bool blocked = eeepc_wlan_rfkill_blocked();
5740294c 689
58ce48a9 690 if (ehotk->wlan_rfkill)
07e84aa9 691 rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
6d41839e 692
dcf443b5
AJ
693 mutex_lock(&ehotk->hotplug_lock);
694
07e84aa9
AJ
695 if (ehotk->hotplug_slot) {
696 bus = pci_find_bus(0, 1);
697 if (!bus) {
698 pr_warning("Unable to find PCI bus 1?\n");
dcf443b5 699 goto out_unlock;
5740294c 700 }
07e84aa9
AJ
701
702 if (!blocked) {
703 dev = pci_get_slot(bus, 0);
704 if (dev) {
705 /* Device already present */
706 pci_dev_put(dev);
707 goto out_unlock;
708 }
709 dev = pci_scan_single_device(bus, 0);
710 if (dev) {
711 pci_bus_assign_resources(bus);
712 if (pci_bus_add_device(dev))
713 pr_err("Unable to hotplug wifi\n");
714 }
715 } else {
716 dev = pci_get_slot(bus, 0);
717 if (dev) {
718 pci_remove_bus_device(dev);
719 pci_dev_put(dev);
720 }
5740294c
MG
721 }
722 }
dcf443b5
AJ
723
724out_unlock:
725 mutex_unlock(&ehotk->hotplug_lock);
5740294c
MG
726}
727
96e9cfeb
AJ
728static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
729{
730 if (event != ACPI_NOTIFY_BUS_CHECK)
731 return;
732
58ce48a9 733 eeepc_rfkill_hotplug();
96e9cfeb
AJ
734}
735
d9b9bd7b 736static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
e59f8796 737{
a195dcdc 738 static struct key_entry *key;
7950b71c 739 u16 count;
64b86b65 740 int brn = -ENODEV;
7950b71c 741
d9b9bd7b
BH
742 if (event > ACPI_MAX_SYS_NOTIFY)
743 return;
a5fa429b 744 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
64b86b65 745 brn = notify_brn();
7950b71c
CC
746 count = ehotk->event_count[event % 128]++;
747 acpi_bus_generate_proc_event(ehotk->device, event, count);
2b25c9f0
CC
748 acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class,
749 dev_name(&ehotk->device->dev), event,
7950b71c 750 count);
a195dcdc 751 if (ehotk->inputdev) {
a2a1d36c
AJ
752 /* brightness-change events need special
753 * handling for conversion to key events
754 */
755 if (brn < 0)
756 brn = event;
757 else
758 brn += NOTIFY_BRN_MIN;
759 if (event < brn)
760 event = NOTIFY_BRN_MIN; /* brightness down */
761 else if (event > brn)
762 event = NOTIFY_BRN_MIN + 2; /* ... up */
763 else
764 event = NOTIFY_BRN_MIN + 1; /* ... unchanged */
765
a195dcdc
MG
766 key = eepc_get_entry_by_scancode(event);
767 if (key) {
768 switch (key->type) {
769 case KE_KEY:
770 input_report_key(ehotk->inputdev, key->keycode,
771 1);
772 input_sync(ehotk->inputdev);
773 input_report_key(ehotk->inputdev, key->keycode,
774 0);
775 input_sync(ehotk->inputdev);
776 break;
777 }
778 }
779 }
e59f8796
EC
780}
781
5740294c
MG
782static int eeepc_register_rfkill_notifier(char *node)
783{
784 acpi_status status = AE_OK;
785 acpi_handle handle;
786
787 status = acpi_get_handle(NULL, node, &handle);
788
789 if (ACPI_SUCCESS(status)) {
790 status = acpi_install_notify_handler(handle,
791 ACPI_SYSTEM_NOTIFY,
792 eeepc_rfkill_notify,
793 NULL);
794 if (ACPI_FAILURE(status))
19b53289 795 pr_warning("Failed to register notify on %s\n", node);
5740294c
MG
796 } else
797 return -ENODEV;
798
799 return 0;
800}
801
802static void eeepc_unregister_rfkill_notifier(char *node)
803{
804 acpi_status status = AE_OK;
805 acpi_handle handle;
806
807 status = acpi_get_handle(NULL, node, &handle);
808
809 if (ACPI_SUCCESS(status)) {
810 status = acpi_remove_notify_handler(handle,
811 ACPI_SYSTEM_NOTIFY,
812 eeepc_rfkill_notify);
813 if (ACPI_FAILURE(status))
19b53289 814 pr_err("Error removing rfkill notify handler %s\n",
5740294c
MG
815 node);
816 }
817}
818
2b121bc2
CC
819static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
820{
821 kfree(hotplug_slot->info);
822 kfree(hotplug_slot);
823}
824
825static int eeepc_setup_pci_hotplug(void)
826{
827 int ret = -ENOMEM;
828 struct pci_bus *bus = pci_find_bus(0, 1);
829
830 if (!bus) {
19b53289 831 pr_err("Unable to find wifi PCI bus\n");
2b121bc2
CC
832 return -ENODEV;
833 }
834
835 ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
836 if (!ehotk->hotplug_slot)
837 goto error_slot;
838
839 ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
840 GFP_KERNEL);
841 if (!ehotk->hotplug_slot->info)
842 goto error_info;
843
844 ehotk->hotplug_slot->private = ehotk;
845 ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
846 ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
847 eeepc_get_adapter_status(ehotk->hotplug_slot,
848 &ehotk->hotplug_slot->info->adapter_status);
849
850 ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi");
851 if (ret) {
19b53289 852 pr_err("Unable to register hotplug slot - %d\n", ret);
2b121bc2
CC
853 goto error_register;
854 }
855
856 return 0;
857
858error_register:
859 kfree(ehotk->hotplug_slot->info);
860error_info:
861 kfree(ehotk->hotplug_slot);
862 ehotk->hotplug_slot = NULL;
863error_slot:
864 return ret;
865}
866
c200da5d 867static int eeepc_hotk_thaw(struct device *device)
96e9cfeb 868{
7de39389 869 if (ehotk->wlan_rfkill) {
96e9cfeb
AJ
870 bool wlan;
871
c1edd99f
AJ
872 /*
873 * Work around bios bug - acpi _PTS turns off the wireless led
874 * during suspend. Normally it restores it on resume, but
c200da5d 875 * we should kick it ourselves in case hibernation is aborted.
96e9cfeb
AJ
876 */
877 wlan = get_acpi(CM_ASL_WLAN);
878 set_acpi(CM_ASL_WLAN, wlan);
c200da5d
AJ
879 }
880
881 return 0;
882}
96e9cfeb 883
c200da5d
AJ
884static int eeepc_hotk_restore(struct device *device)
885{
886 /* Refresh both wlan rfkill state and pci hotplug */
887 if (ehotk->wlan_rfkill)
58ce48a9 888 eeepc_rfkill_hotplug();
96e9cfeb 889
7de39389
CC
890 if (ehotk->bluetooth_rfkill)
891 rfkill_set_sw_state(ehotk->bluetooth_rfkill,
96e9cfeb 892 get_acpi(CM_ASL_BLUETOOTH) != 1);
a4746101
AJ
893 if (ehotk->wwan3g_rfkill)
894 rfkill_set_sw_state(ehotk->wwan3g_rfkill,
895 get_acpi(CM_ASL_3G) != 1);
d1ec9c3d
CC
896 if (ehotk->wimax_rfkill)
897 rfkill_set_sw_state(ehotk->wimax_rfkill,
898 get_acpi(CM_ASL_WIMAX) != 1);
96e9cfeb
AJ
899
900 return 0;
901}
902
e1faa9da
CC
903/*
904 * Hwmon
905 */
906static int eeepc_get_fan_pwm(void)
907{
908 int value = 0;
909
910 read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
04dcd84b 911 value = value * 255 / 100;
e1faa9da
CC
912 return (value);
913}
914
915static void eeepc_set_fan_pwm(int value)
916{
04dcd84b
CC
917 value = SENSORS_LIMIT(value, 0, 255);
918 value = value * 100 / 255;
e1faa9da
CC
919 ec_write(EEEPC_EC_SC02, value);
920}
921
922static int eeepc_get_fan_rpm(void)
923{
924 int high = 0;
925 int low = 0;
926
927 read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
928 read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
929 return (high << 8 | low);
930}
931
932static int eeepc_get_fan_ctrl(void)
933{
934 int value = 0;
935
936 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
48718688
AJ
937 if (value & 0x02)
938 return 1; /* manual */
939 else
940 return 2; /* automatic */
e1faa9da
CC
941}
942
943static void eeepc_set_fan_ctrl(int manual)
944{
945 int value = 0;
946
947 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
48718688 948 if (manual == 1)
e1faa9da
CC
949 value |= 0x02;
950 else
951 value &= ~0x02;
952 ec_write(EEEPC_EC_SFB3, value);
953}
954
955static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
956{
957 int rv, value;
958
959 rv = parse_arg(buf, count, &value);
960 if (rv > 0)
961 set(value);
962 return rv;
963}
964
965static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
966{
967 return sprintf(buf, "%d\n", get());
968}
969
970#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
971 static ssize_t show_##_name(struct device *dev, \
972 struct device_attribute *attr, \
973 char *buf) \
974 { \
975 return show_sys_hwmon(_set, buf); \
976 } \
977 static ssize_t store_##_name(struct device *dev, \
978 struct device_attribute *attr, \
979 const char *buf, size_t count) \
980 { \
981 return store_sys_hwmon(_get, buf, count); \
982 } \
983 static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
984
985EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
04dcd84b 986EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
e1faa9da
CC
987 eeepc_get_fan_pwm, eeepc_set_fan_pwm);
988EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
989 eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
990
04dcd84b
CC
991static ssize_t
992show_name(struct device *dev, struct device_attribute *attr, char *buf)
993{
994 return sprintf(buf, "eeepc\n");
995}
996static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
997
e1faa9da 998static struct attribute *hwmon_attributes[] = {
04dcd84b 999 &sensor_dev_attr_pwm1.dev_attr.attr,
e1faa9da
CC
1000 &sensor_dev_attr_fan1_input.dev_attr.attr,
1001 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
04dcd84b 1002 &sensor_dev_attr_name.dev_attr.attr,
e1faa9da
CC
1003 NULL
1004};
1005
1006static struct attribute_group hwmon_attribute_group = {
1007 .attrs = hwmon_attributes
1008};
1009
e59f8796
EC
1010/*
1011 * exit/init
1012 */
a5fa429b
CC
1013static void eeepc_backlight_exit(void)
1014{
1015 if (eeepc_backlight_device)
1016 backlight_device_unregister(eeepc_backlight_device);
a9df80c5
CC
1017 eeepc_backlight_device = NULL;
1018}
1019
1020static void eeepc_rfkill_exit(void)
1021{
52cc96bd 1022 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5");
7de39389
CC
1023 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
1024 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
07e84aa9 1025 if (ehotk->wlan_rfkill) {
7de39389 1026 rfkill_unregister(ehotk->wlan_rfkill);
a8258069 1027 rfkill_destroy(ehotk->wlan_rfkill);
07e84aa9
AJ
1028 ehotk->wlan_rfkill = NULL;
1029 }
1030 /*
1031 * Refresh pci hotplug in case the rfkill state was changed after
1032 * eeepc_unregister_rfkill_notifier()
1033 */
58ce48a9 1034 eeepc_rfkill_hotplug();
07e84aa9
AJ
1035 if (ehotk->hotplug_slot)
1036 pci_hp_deregister(ehotk->hotplug_slot);
1037
a8258069 1038 if (ehotk->bluetooth_rfkill) {
7de39389 1039 rfkill_unregister(ehotk->bluetooth_rfkill);
a8258069
AJ
1040 rfkill_destroy(ehotk->bluetooth_rfkill);
1041 ehotk->bluetooth_rfkill = NULL;
1042 }
1043 if (ehotk->wwan3g_rfkill) {
3cd530b5 1044 rfkill_unregister(ehotk->wwan3g_rfkill);
a8258069
AJ
1045 rfkill_destroy(ehotk->wwan3g_rfkill);
1046 ehotk->wwan3g_rfkill = NULL;
1047 }
1048 if (ehotk->wimax_rfkill) {
d1ec9c3d 1049 rfkill_unregister(ehotk->wimax_rfkill);
a8258069
AJ
1050 rfkill_destroy(ehotk->wimax_rfkill);
1051 ehotk->wimax_rfkill = NULL;
1052 }
a9df80c5
CC
1053}
1054
1055static void eeepc_input_exit(void)
1056{
1057 if (ehotk->inputdev)
1058 input_unregister_device(ehotk->inputdev);
a5fa429b
CC
1059}
1060
e1faa9da
CC
1061static void eeepc_hwmon_exit(void)
1062{
1063 struct device *hwmon;
1064
1065 hwmon = eeepc_hwmon_device;
1066 if (!hwmon)
1067 return ;
e1faa9da
CC
1068 sysfs_remove_group(&hwmon->kobj,
1069 &hwmon_attribute_group);
f1441318 1070 hwmon_device_unregister(hwmon);
e1faa9da
CC
1071 eeepc_hwmon_device = NULL;
1072}
1073
3c0eb510
CC
1074static void eeepc_led_exit(void)
1075{
3c0eb510
CC
1076 if (tpd_led.dev)
1077 led_classdev_unregister(&tpd_led);
2b56f1c1
AJ
1078 if (led_workqueue)
1079 destroy_workqueue(led_workqueue);
3c0eb510
CC
1080}
1081
7de39389
CC
1082static int eeepc_new_rfkill(struct rfkill **rfkill,
1083 const char *name, struct device *dev,
1084 enum rfkill_type type, int cm)
1085{
1086 int result;
1087
f36509e7
CC
1088 result = get_acpi(cm);
1089 if (result < 0)
1090 return result;
7de39389
CC
1091
1092 *rfkill = rfkill_alloc(name, dev, type,
1093 &eeepc_rfkill_ops, (void *)(unsigned long)cm);
1094
1095 if (!*rfkill)
1096 return -EINVAL;
1097
1098 rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1);
1099 result = rfkill_register(*rfkill);
1100 if (result) {
1101 rfkill_destroy(*rfkill);
1102 *rfkill = NULL;
1103 return result;
1104 }
1105 return 0;
1106}
1107
1108
1109static int eeepc_rfkill_init(struct device *dev)
1110{
1111 int result = 0;
1112
dcf443b5 1113 mutex_init(&ehotk->hotplug_lock);
7334546a 1114
7de39389
CC
1115 result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
1116 "eeepc-wlan", dev,
1117 RFKILL_TYPE_WLAN, CM_ASL_WLAN);
1118
1119 if (result && result != -ENODEV)
1120 goto exit;
1121
1122 result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill,
1123 "eeepc-bluetooth", dev,
1124 RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH);
1125
1126 if (result && result != -ENODEV)
1127 goto exit;
1128
3cd530b5
CC
1129 result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill,
1130 "eeepc-wwan3g", dev,
1131 RFKILL_TYPE_WWAN, CM_ASL_3G);
1132
1133 if (result && result != -ENODEV)
1134 goto exit;
1135
d1ec9c3d
CC
1136 result = eeepc_new_rfkill(&ehotk->wimax_rfkill,
1137 "eeepc-wimax", dev,
1138 RFKILL_TYPE_WIMAX, CM_ASL_WIMAX);
1139
1140 if (result && result != -ENODEV)
1141 goto exit;
1142
7de39389
CC
1143 result = eeepc_setup_pci_hotplug();
1144 /*
1145 * If we get -EBUSY then something else is handling the PCI hotplug -
1146 * don't fail in this case
1147 */
1148 if (result == -EBUSY)
1149 result = 0;
1150
52cc96bd 1151 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5");
07e84aa9
AJ
1152 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
1153 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
1154 /*
1155 * Refresh pci hotplug in case the rfkill state was changed during
1156 * setup.
1157 */
58ce48a9 1158 eeepc_rfkill_hotplug();
07e84aa9 1159
7de39389
CC
1160exit:
1161 if (result && result != -ENODEV)
1162 eeepc_rfkill_exit();
1163 return result;
1164}
1165
a5fa429b
CC
1166static int eeepc_backlight_init(struct device *dev)
1167{
1168 struct backlight_device *bd;
1169
1170 bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
1171 NULL, &eeepcbl_ops);
1172 if (IS_ERR(bd)) {
19b53289 1173 pr_err("Could not register eeepc backlight device\n");
a5fa429b
CC
1174 eeepc_backlight_device = NULL;
1175 return PTR_ERR(bd);
1176 }
1177 eeepc_backlight_device = bd;
1178 bd->props.max_brightness = 15;
1179 bd->props.brightness = read_brightness(NULL);
1180 bd->props.power = FB_BLANK_UNBLANK;
1181 backlight_update_status(bd);
1182 return 0;
1183}
1184
e1faa9da
CC
1185static int eeepc_hwmon_init(struct device *dev)
1186{
1187 struct device *hwmon;
1188 int result;
1189
1190 hwmon = hwmon_device_register(dev);
1191 if (IS_ERR(hwmon)) {
19b53289 1192 pr_err("Could not register eeepc hwmon device\n");
e1faa9da
CC
1193 eeepc_hwmon_device = NULL;
1194 return PTR_ERR(hwmon);
1195 }
1196 eeepc_hwmon_device = hwmon;
1197 result = sysfs_create_group(&hwmon->kobj,
1198 &hwmon_attribute_group);
1199 if (result)
1200 eeepc_hwmon_exit();
1201 return result;
1202}
1203
f2a9d5e8
AJ
1204static int eeepc_input_init(struct device *dev)
1205{
1206 const struct key_entry *key;
1207 int result;
1208
1209 ehotk->inputdev = input_allocate_device();
1210 if (!ehotk->inputdev) {
1211 pr_info("Unable to allocate input device\n");
1212 return -ENOMEM;
1213 }
1214 ehotk->inputdev->name = "Asus EeePC extra buttons";
1215 ehotk->inputdev->dev.parent = dev;
1216 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
1217 ehotk->inputdev->id.bustype = BUS_HOST;
1218 ehotk->inputdev->getkeycode = eeepc_getkeycode;
1219 ehotk->inputdev->setkeycode = eeepc_setkeycode;
1220
1221 for (key = eeepc_keymap; key->type != KE_END; key++) {
1222 switch (key->type) {
1223 case KE_KEY:
1224 set_bit(EV_KEY, ehotk->inputdev->evbit);
1225 set_bit(key->keycode, ehotk->inputdev->keybit);
1226 break;
1227 }
1228 }
1229 result = input_register_device(ehotk->inputdev);
1230 if (result) {
1231 pr_info("Unable to register input device\n");
1232 input_free_device(ehotk->inputdev);
1233 return result;
1234 }
1235 return 0;
1236}
1237
3c0eb510
CC
1238static int eeepc_led_init(struct device *dev)
1239{
1240 int rv;
1241
1242 if (get_acpi(CM_ASL_TPD) == -ENODEV)
1243 return 0;
1244
3c0eb510
CC
1245 led_workqueue = create_singlethread_workqueue("led_workqueue");
1246 if (!led_workqueue)
1247 return -ENOMEM;
1248
2b56f1c1 1249 rv = led_classdev_register(dev, &tpd_led);
dc56ad9b
AJ
1250 if (rv) {
1251 destroy_workqueue(led_workqueue);
2b56f1c1 1252 return rv;
dc56ad9b 1253 }
2b56f1c1 1254
3c0eb510
CC
1255 return 0;
1256}
1257
dcb73eed 1258static int __devinit eeepc_hotk_add(struct acpi_device *device)
e59f8796
EC
1259{
1260 struct device *dev;
1261 int result;
1262
1e779854
AJ
1263 pr_notice(EEEPC_HOTK_NAME "\n");
1264 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
1265 if (!ehotk)
1266 return -ENOMEM;
1267 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
1268 ehotk->handle = device->handle;
1269 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
1270 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
1271 device->driver_data = ehotk;
1272 ehotk->device = device;
cede2cb6 1273
1e779854
AJ
1274 result = eeepc_hotk_check();
1275 if (result)
f2a9d5e8 1276 goto fail_platform_driver;
cede2cb6
PE
1277 eeepc_enable_camera();
1278
e59f8796
EC
1279 /* Register platform stuff */
1280 result = platform_driver_register(&platform_driver);
1281 if (result)
1282 goto fail_platform_driver;
1283 platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
1284 if (!platform_device) {
1285 result = -ENOMEM;
1286 goto fail_platform_device1;
1287 }
1288 result = platform_device_add(platform_device);
1289 if (result)
1290 goto fail_platform_device2;
1291 result = sysfs_create_group(&platform_device->dev.kobj,
1292 &platform_attribute_group);
1293 if (result)
1294 goto fail_sysfs;
7de39389 1295
1ddec2f9
CC
1296 dev = &platform_device->dev;
1297
1298 if (!acpi_video_backlight_support()) {
1299 result = eeepc_backlight_init(dev);
1300 if (result)
1301 goto fail_backlight;
1302 } else
1303 pr_info("Backlight controlled by ACPI video "
1304 "driver\n");
1305
f2a9d5e8
AJ
1306 result = eeepc_input_init(dev);
1307 if (result)
1308 goto fail_input;
1309
1ddec2f9
CC
1310 result = eeepc_hwmon_init(dev);
1311 if (result)
1312 goto fail_hwmon;
1313
3c0eb510
CC
1314 result = eeepc_led_init(dev);
1315 if (result)
1316 goto fail_led;
1317
7de39389
CC
1318 result = eeepc_rfkill_init(dev);
1319 if (result)
1320 goto fail_rfkill;
1321
e59f8796 1322 return 0;
1e779854 1323
7de39389 1324fail_rfkill:
3c0eb510
CC
1325 eeepc_led_exit();
1326fail_led:
1ddec2f9
CC
1327 eeepc_hwmon_exit();
1328fail_hwmon:
f2a9d5e8
AJ
1329 eeepc_input_exit();
1330fail_input:
1ddec2f9
CC
1331 eeepc_backlight_exit();
1332fail_backlight:
7de39389
CC
1333 sysfs_remove_group(&platform_device->dev.kobj,
1334 &platform_attribute_group);
e59f8796
EC
1335fail_sysfs:
1336 platform_device_del(platform_device);
1337fail_platform_device2:
1338 platform_device_put(platform_device);
1339fail_platform_device1:
1340 platform_driver_unregister(&platform_driver);
1341fail_platform_driver:
1e779854
AJ
1342 kfree(ehotk);
1343
e59f8796
EC
1344 return result;
1345}
1346
1e779854
AJ
1347static int eeepc_hotk_remove(struct acpi_device *device, int type)
1348{
1e779854
AJ
1349 eeepc_backlight_exit();
1350 eeepc_rfkill_exit();
1351 eeepc_input_exit();
1352 eeepc_hwmon_exit();
3c0eb510 1353 eeepc_led_exit();
1e779854
AJ
1354 sysfs_remove_group(&platform_device->dev.kobj,
1355 &platform_attribute_group);
1356 platform_device_unregister(platform_device);
1357 platform_driver_unregister(&platform_driver);
1358
1359 kfree(ehotk);
1360 return 0;
1361}
1362
1363static int __init eeepc_laptop_init(void)
1364{
1365 int result;
1366
1e779854
AJ
1367 result = acpi_bus_register_driver(&eeepc_hotk_driver);
1368 if (result < 0)
1369 return result;
1370 if (!ehotk) {
1371 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1372 return -ENODEV;
1373 }
1374 return 0;
1375}
1376
1377static void __exit eeepc_laptop_exit(void)
1378{
1379 acpi_bus_unregister_driver(&eeepc_hotk_driver);
1380}
1381
e59f8796
EC
1382module_init(eeepc_laptop_init);
1383module_exit(eeepc_laptop_exit);