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