diff options
Diffstat (limited to 'drivers/platform/x86/eeepc-laptop.c')
-rw-r--r-- | drivers/platform/x86/eeepc-laptop.c | 500 |
1 files changed, 376 insertions, 124 deletions
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 03bf522bd7ab..ec560f16d720 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
@@ -16,6 +16,8 @@ | |||
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
20 | |||
19 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
20 | #include <linux/module.h> | 22 | #include <linux/module.h> |
21 | #include <linux/init.h> | 23 | #include <linux/init.h> |
@@ -31,6 +33,7 @@ | |||
31 | #include <linux/input.h> | 33 | #include <linux/input.h> |
32 | #include <linux/rfkill.h> | 34 | #include <linux/rfkill.h> |
33 | #include <linux/pci.h> | 35 | #include <linux/pci.h> |
36 | #include <linux/pci_hotplug.h> | ||
34 | 37 | ||
35 | #define EEEPC_LAPTOP_VERSION "0.1" | 38 | #define EEEPC_LAPTOP_VERSION "0.1" |
36 | 39 | ||
@@ -40,11 +43,6 @@ | |||
40 | #define EEEPC_HOTK_DEVICE_NAME "Hotkey" | 43 | #define EEEPC_HOTK_DEVICE_NAME "Hotkey" |
41 | #define EEEPC_HOTK_HID "ASUS010" | 44 | #define EEEPC_HOTK_HID "ASUS010" |
42 | 45 | ||
43 | #define EEEPC_LOG EEEPC_HOTK_FILE ": " | ||
44 | #define EEEPC_ERR KERN_ERR EEEPC_LOG | ||
45 | #define EEEPC_WARNING KERN_WARNING EEEPC_LOG | ||
46 | #define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG | ||
47 | #define EEEPC_INFO KERN_INFO EEEPC_LOG | ||
48 | 46 | ||
49 | /* | 47 | /* |
50 | * Definitions for Asus EeePC | 48 | * Definitions for Asus EeePC |
@@ -62,7 +60,10 @@ enum { | |||
62 | DISABLE_ASL_GPS = 0x0020, | 60 | DISABLE_ASL_GPS = 0x0020, |
63 | DISABLE_ASL_DISPLAYSWITCH = 0x0040, | 61 | DISABLE_ASL_DISPLAYSWITCH = 0x0040, |
64 | DISABLE_ASL_MODEM = 0x0080, | 62 | DISABLE_ASL_MODEM = 0x0080, |
65 | DISABLE_ASL_CARDREADER = 0x0100 | 63 | DISABLE_ASL_CARDREADER = 0x0100, |
64 | DISABLE_ASL_3G = 0x0200, | ||
65 | DISABLE_ASL_WIMAX = 0x0400, | ||
66 | DISABLE_ASL_HWCF = 0x0800 | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | enum { | 69 | enum { |
@@ -87,7 +88,13 @@ enum { | |||
87 | CM_ASL_USBPORT3, | 88 | CM_ASL_USBPORT3, |
88 | CM_ASL_MODEM, | 89 | CM_ASL_MODEM, |
89 | CM_ASL_CARDREADER, | 90 | CM_ASL_CARDREADER, |
90 | CM_ASL_LID | 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 | ||
91 | }; | 98 | }; |
92 | 99 | ||
93 | static const char *cm_getv[] = { | 100 | static const char *cm_getv[] = { |
@@ -96,7 +103,8 @@ static const char *cm_getv[] = { | |||
96 | NULL, "PBLG", NULL, NULL, | 103 | NULL, "PBLG", NULL, NULL, |
97 | "CFVG", NULL, NULL, NULL, | 104 | "CFVG", NULL, NULL, NULL, |
98 | "USBG", NULL, NULL, "MODG", | 105 | "USBG", NULL, NULL, "MODG", |
99 | "CRDG", "LIDG" | 106 | "CRDG", "M3GG", "WIMG", "HWCF", |
107 | "LIDG", "TYPE", "PBPG", "TPDG" | ||
100 | }; | 108 | }; |
101 | 109 | ||
102 | static const char *cm_setv[] = { | 110 | static const char *cm_setv[] = { |
@@ -105,7 +113,8 @@ static const char *cm_setv[] = { | |||
105 | "SDSP", "PBLS", "HDPS", NULL, | 113 | "SDSP", "PBLS", "HDPS", NULL, |
106 | "CFVS", NULL, NULL, NULL, | 114 | "CFVS", NULL, NULL, NULL, |
107 | "USBG", NULL, NULL, "MODS", | 115 | "USBG", NULL, NULL, "MODS", |
108 | "CRDS", NULL | 116 | "CRDS", "M3GS", "WIMS", NULL, |
117 | NULL, NULL, "PBPS", "TPDS" | ||
109 | }; | 118 | }; |
110 | 119 | ||
111 | #define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." | 120 | #define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." |
@@ -130,8 +139,10 @@ struct eeepc_hotk { | |||
130 | u16 event_count[128]; /* count for each event */ | 139 | u16 event_count[128]; /* count for each event */ |
131 | struct input_dev *inputdev; | 140 | struct input_dev *inputdev; |
132 | u16 *keycode_map; | 141 | u16 *keycode_map; |
133 | struct rfkill *eeepc_wlan_rfkill; | 142 | struct rfkill *wlan_rfkill; |
134 | struct rfkill *eeepc_bluetooth_rfkill; | 143 | struct rfkill *bluetooth_rfkill; |
144 | struct rfkill *wwan3g_rfkill; | ||
145 | struct hotplug_slot *hotplug_slot; | ||
135 | }; | 146 | }; |
136 | 147 | ||
137 | /* The actual device the driver binds to */ | 148 | /* The actual device the driver binds to */ |
@@ -180,6 +191,8 @@ static struct key_entry eeepc_keymap[] = { | |||
180 | */ | 191 | */ |
181 | static int eeepc_hotk_add(struct acpi_device *device); | 192 | static int eeepc_hotk_add(struct acpi_device *device); |
182 | static int eeepc_hotk_remove(struct acpi_device *device, int type); | 193 | static int eeepc_hotk_remove(struct acpi_device *device, int type); |
194 | static int eeepc_hotk_resume(struct acpi_device *device); | ||
195 | static void eeepc_hotk_notify(struct acpi_device *device, u32 event); | ||
183 | 196 | ||
184 | static const struct acpi_device_id eeepc_device_ids[] = { | 197 | static const struct acpi_device_id eeepc_device_ids[] = { |
185 | {EEEPC_HOTK_HID, 0}, | 198 | {EEEPC_HOTK_HID, 0}, |
@@ -191,12 +204,24 @@ static struct acpi_driver eeepc_hotk_driver = { | |||
191 | .name = EEEPC_HOTK_NAME, | 204 | .name = EEEPC_HOTK_NAME, |
192 | .class = EEEPC_HOTK_CLASS, | 205 | .class = EEEPC_HOTK_CLASS, |
193 | .ids = eeepc_device_ids, | 206 | .ids = eeepc_device_ids, |
207 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, | ||
194 | .ops = { | 208 | .ops = { |
195 | .add = eeepc_hotk_add, | 209 | .add = eeepc_hotk_add, |
196 | .remove = eeepc_hotk_remove, | 210 | .remove = eeepc_hotk_remove, |
211 | .resume = eeepc_hotk_resume, | ||
212 | .notify = eeepc_hotk_notify, | ||
197 | }, | 213 | }, |
198 | }; | 214 | }; |
199 | 215 | ||
216 | /* PCI hotplug ops */ | ||
217 | static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value); | ||
218 | |||
219 | static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { | ||
220 | .owner = THIS_MODULE, | ||
221 | .get_adapter_status = eeepc_get_adapter_status, | ||
222 | .get_power_status = eeepc_get_adapter_status, | ||
223 | }; | ||
224 | |||
200 | /* The backlight device /sys/class/backlight */ | 225 | /* The backlight device /sys/class/backlight */ |
201 | static struct backlight_device *eeepc_backlight_device; | 226 | static struct backlight_device *eeepc_backlight_device; |
202 | 227 | ||
@@ -258,20 +283,20 @@ static int set_acpi(int cm, int value) | |||
258 | if (method == NULL) | 283 | if (method == NULL) |
259 | return -ENODEV; | 284 | return -ENODEV; |
260 | if (write_acpi_int(ehotk->handle, method, value, NULL)) | 285 | if (write_acpi_int(ehotk->handle, method, value, NULL)) |
261 | printk(EEEPC_WARNING "Error writing %s\n", method); | 286 | pr_warning("Error writing %s\n", method); |
262 | } | 287 | } |
263 | return 0; | 288 | return 0; |
264 | } | 289 | } |
265 | 290 | ||
266 | static int get_acpi(int cm) | 291 | static int get_acpi(int cm) |
267 | { | 292 | { |
268 | int value = -1; | 293 | int value = -ENODEV; |
269 | if ((ehotk->cm_supported & (0x1 << cm))) { | 294 | if ((ehotk->cm_supported & (0x1 << cm))) { |
270 | const char *method = cm_getv[cm]; | 295 | const char *method = cm_getv[cm]; |
271 | if (method == NULL) | 296 | if (method == NULL) |
272 | return -ENODEV; | 297 | return -ENODEV; |
273 | if (read_acpi_int(ehotk->handle, method, &value)) | 298 | if (read_acpi_int(ehotk->handle, method, &value)) |
274 | printk(EEEPC_WARNING "Error reading %s\n", method); | 299 | pr_warning("Error reading %s\n", method); |
275 | } | 300 | } |
276 | return value; | 301 | return value; |
277 | } | 302 | } |
@@ -316,6 +341,15 @@ static const struct rfkill_ops eeepc_rfkill_ops = { | |||
316 | .set_block = eeepc_rfkill_set, | 341 | .set_block = eeepc_rfkill_set, |
317 | }; | 342 | }; |
318 | 343 | ||
344 | static void __init eeepc_enable_camera(void) | ||
345 | { | ||
346 | /* | ||
347 | * If the following call to set_acpi() fails, it's because there's no | ||
348 | * camera so we can ignore the error. | ||
349 | */ | ||
350 | set_acpi(CM_ASL_CAMERA, 1); | ||
351 | } | ||
352 | |||
319 | /* | 353 | /* |
320 | * Sys helpers | 354 | * Sys helpers |
321 | */ | 355 | */ |
@@ -334,13 +368,19 @@ static ssize_t store_sys_acpi(int cm, const char *buf, size_t count) | |||
334 | 368 | ||
335 | rv = parse_arg(buf, count, &value); | 369 | rv = parse_arg(buf, count, &value); |
336 | if (rv > 0) | 370 | if (rv > 0) |
337 | set_acpi(cm, value); | 371 | value = set_acpi(cm, value); |
372 | if (value < 0) | ||
373 | return value; | ||
338 | return rv; | 374 | return rv; |
339 | } | 375 | } |
340 | 376 | ||
341 | static ssize_t show_sys_acpi(int cm, char *buf) | 377 | static ssize_t show_sys_acpi(int cm, char *buf) |
342 | { | 378 | { |
343 | return sprintf(buf, "%d\n", get_acpi(cm)); | 379 | int value = get_acpi(cm); |
380 | |||
381 | if (value < 0) | ||
382 | return value; | ||
383 | return sprintf(buf, "%d\n", value); | ||
344 | } | 384 | } |
345 | 385 | ||
346 | #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \ | 386 | #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \ |
@@ -367,13 +407,88 @@ static ssize_t show_sys_acpi(int cm, char *buf) | |||
367 | EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); | 407 | EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); |
368 | EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); | 408 | EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); |
369 | EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); | 409 | EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); |
370 | EEEPC_CREATE_DEVICE_ATTR(cpufv, CM_ASL_CPUFV); | 410 | |
411 | struct eeepc_cpufv { | ||
412 | int num; | ||
413 | int cur; | ||
414 | }; | ||
415 | |||
416 | static int get_cpufv(struct eeepc_cpufv *c) | ||
417 | { | ||
418 | c->cur = get_acpi(CM_ASL_CPUFV); | ||
419 | c->num = (c->cur >> 8) & 0xff; | ||
420 | c->cur &= 0xff; | ||
421 | if (c->cur < 0 || c->num <= 0 || c->num > 12) | ||
422 | return -ENODEV; | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static ssize_t show_available_cpufv(struct device *dev, | ||
427 | struct device_attribute *attr, | ||
428 | char *buf) | ||
429 | { | ||
430 | struct eeepc_cpufv c; | ||
431 | int i; | ||
432 | ssize_t len = 0; | ||
433 | |||
434 | if (get_cpufv(&c)) | ||
435 | return -ENODEV; | ||
436 | for (i = 0; i < c.num; i++) | ||
437 | len += sprintf(buf + len, "%d ", i); | ||
438 | len += sprintf(buf + len, "\n"); | ||
439 | return len; | ||
440 | } | ||
441 | |||
442 | static ssize_t show_cpufv(struct device *dev, | ||
443 | struct device_attribute *attr, | ||
444 | char *buf) | ||
445 | { | ||
446 | struct eeepc_cpufv c; | ||
447 | |||
448 | if (get_cpufv(&c)) | ||
449 | return -ENODEV; | ||
450 | return sprintf(buf, "%#x\n", (c.num << 8) | c.cur); | ||
451 | } | ||
452 | |||
453 | static ssize_t store_cpufv(struct device *dev, | ||
454 | struct device_attribute *attr, | ||
455 | const char *buf, size_t count) | ||
456 | { | ||
457 | struct eeepc_cpufv c; | ||
458 | int rv, value; | ||
459 | |||
460 | if (get_cpufv(&c)) | ||
461 | return -ENODEV; | ||
462 | rv = parse_arg(buf, count, &value); | ||
463 | if (rv < 0) | ||
464 | return rv; | ||
465 | if (!rv || value < 0 || value >= c.num) | ||
466 | return -EINVAL; | ||
467 | set_acpi(CM_ASL_CPUFV, value); | ||
468 | return rv; | ||
469 | } | ||
470 | |||
471 | static struct device_attribute dev_attr_cpufv = { | ||
472 | .attr = { | ||
473 | .name = "cpufv", | ||
474 | .mode = 0644 }, | ||
475 | .show = show_cpufv, | ||
476 | .store = store_cpufv | ||
477 | }; | ||
478 | |||
479 | static struct device_attribute dev_attr_available_cpufv = { | ||
480 | .attr = { | ||
481 | .name = "available_cpufv", | ||
482 | .mode = 0444 }, | ||
483 | .show = show_available_cpufv | ||
484 | }; | ||
371 | 485 | ||
372 | static struct attribute *platform_attributes[] = { | 486 | static struct attribute *platform_attributes[] = { |
373 | &dev_attr_camera.attr, | 487 | &dev_attr_camera.attr, |
374 | &dev_attr_cardr.attr, | 488 | &dev_attr_cardr.attr, |
375 | &dev_attr_disp.attr, | 489 | &dev_attr_disp.attr, |
376 | &dev_attr_cpufv.attr, | 490 | &dev_attr_cpufv.attr, |
491 | &dev_attr_available_cpufv.attr, | ||
377 | NULL | 492 | NULL |
378 | }; | 493 | }; |
379 | 494 | ||
@@ -439,6 +554,28 @@ static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) | |||
439 | return -EINVAL; | 554 | return -EINVAL; |
440 | } | 555 | } |
441 | 556 | ||
557 | static void cmsg_quirk(int cm, const char *name) | ||
558 | { | ||
559 | int dummy; | ||
560 | |||
561 | /* Some BIOSes do not report cm although it is avaliable. | ||
562 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ | ||
563 | if (!(ehotk->cm_supported & (1 << cm)) | ||
564 | && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) { | ||
565 | pr_info("%s (%x) not reported by BIOS," | ||
566 | " enabling anyway\n", name, 1 << cm); | ||
567 | ehotk->cm_supported |= 1 << cm; | ||
568 | } | ||
569 | } | ||
570 | |||
571 | static void cmsg_quirks(void) | ||
572 | { | ||
573 | cmsg_quirk(CM_ASL_LID, "LID"); | ||
574 | cmsg_quirk(CM_ASL_TYPE, "TYPE"); | ||
575 | cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER"); | ||
576 | cmsg_quirk(CM_ASL_TPD, "TPD"); | ||
577 | } | ||
578 | |||
442 | static int eeepc_hotk_check(void) | 579 | static int eeepc_hotk_check(void) |
443 | { | 580 | { |
444 | const struct key_entry *key; | 581 | const struct key_entry *key; |
@@ -451,26 +588,24 @@ static int eeepc_hotk_check(void) | |||
451 | if (ehotk->device->status.present) { | 588 | if (ehotk->device->status.present) { |
452 | if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag, | 589 | if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag, |
453 | &buffer)) { | 590 | &buffer)) { |
454 | printk(EEEPC_ERR "Hotkey initialization failed\n"); | 591 | pr_err("Hotkey initialization failed\n"); |
455 | return -ENODEV; | 592 | return -ENODEV; |
456 | } else { | 593 | } else { |
457 | printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n", | 594 | pr_notice("Hotkey init flags 0x%x\n", ehotk->init_flag); |
458 | ehotk->init_flag); | ||
459 | } | 595 | } |
460 | /* get control methods supported */ | 596 | /* get control methods supported */ |
461 | if (read_acpi_int(ehotk->handle, "CMSG" | 597 | if (read_acpi_int(ehotk->handle, "CMSG" |
462 | , &ehotk->cm_supported)) { | 598 | , &ehotk->cm_supported)) { |
463 | printk(EEEPC_ERR | 599 | pr_err("Get control methods supported failed\n"); |
464 | "Get control methods supported failed\n"); | ||
465 | return -ENODEV; | 600 | return -ENODEV; |
466 | } else { | 601 | } else { |
467 | printk(EEEPC_INFO | 602 | cmsg_quirks(); |
468 | "Get control methods supported: 0x%x\n", | 603 | pr_info("Get control methods supported: 0x%x\n", |
469 | ehotk->cm_supported); | 604 | ehotk->cm_supported); |
470 | } | 605 | } |
471 | ehotk->inputdev = input_allocate_device(); | 606 | ehotk->inputdev = input_allocate_device(); |
472 | if (!ehotk->inputdev) { | 607 | if (!ehotk->inputdev) { |
473 | printk(EEEPC_INFO "Unable to allocate input device\n"); | 608 | pr_info("Unable to allocate input device\n"); |
474 | return 0; | 609 | return 0; |
475 | } | 610 | } |
476 | ehotk->inputdev->name = "Asus EeePC extra buttons"; | 611 | ehotk->inputdev->name = "Asus EeePC extra buttons"; |
@@ -489,12 +624,12 @@ static int eeepc_hotk_check(void) | |||
489 | } | 624 | } |
490 | result = input_register_device(ehotk->inputdev); | 625 | result = input_register_device(ehotk->inputdev); |
491 | if (result) { | 626 | if (result) { |
492 | printk(EEEPC_INFO "Unable to register input device\n"); | 627 | pr_info("Unable to register input device\n"); |
493 | input_free_device(ehotk->inputdev); | 628 | input_free_device(ehotk->inputdev); |
494 | return 0; | 629 | return 0; |
495 | } | 630 | } |
496 | } else { | 631 | } else { |
497 | printk(EEEPC_ERR "Hotkey device not present, aborting\n"); | 632 | pr_err("Hotkey device not present, aborting\n"); |
498 | return -EINVAL; | 633 | return -EINVAL; |
499 | } | 634 | } |
500 | return 0; | 635 | return 0; |
@@ -512,17 +647,27 @@ static int notify_brn(void) | |||
512 | return -1; | 647 | return -1; |
513 | } | 648 | } |
514 | 649 | ||
515 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | 650 | static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, |
651 | u8 *value) | ||
652 | { | ||
653 | int val = get_acpi(CM_ASL_WLAN); | ||
654 | |||
655 | if (val == 1 || val == 0) | ||
656 | *value = val; | ||
657 | else | ||
658 | return -EINVAL; | ||
659 | |||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | static void eeepc_rfkill_hotplug(void) | ||
516 | { | 664 | { |
517 | struct pci_dev *dev; | 665 | struct pci_dev *dev; |
518 | struct pci_bus *bus = pci_find_bus(0, 1); | 666 | struct pci_bus *bus = pci_find_bus(0, 1); |
519 | bool blocked; | 667 | bool blocked; |
520 | 668 | ||
521 | if (event != ACPI_NOTIFY_BUS_CHECK) | ||
522 | return; | ||
523 | |||
524 | if (!bus) { | 669 | if (!bus) { |
525 | printk(EEEPC_WARNING "Unable to find PCI bus 1?\n"); | 670 | pr_warning("Unable to find PCI bus 1?\n"); |
526 | return; | 671 | return; |
527 | } | 672 | } |
528 | 673 | ||
@@ -538,7 +683,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | |||
538 | if (dev) { | 683 | if (dev) { |
539 | pci_bus_assign_resources(bus); | 684 | pci_bus_assign_resources(bus); |
540 | if (pci_bus_add_device(dev)) | 685 | if (pci_bus_add_device(dev)) |
541 | printk(EEEPC_ERR "Unable to hotplug wifi\n"); | 686 | pr_err("Unable to hotplug wifi\n"); |
542 | } | 687 | } |
543 | } else { | 688 | } else { |
544 | dev = pci_get_slot(bus, 0); | 689 | dev = pci_get_slot(bus, 0); |
@@ -548,10 +693,18 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | |||
548 | } | 693 | } |
549 | } | 694 | } |
550 | 695 | ||
551 | rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked); | 696 | rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); |
552 | } | 697 | } |
553 | 698 | ||
554 | static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) | 699 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) |
700 | { | ||
701 | if (event != ACPI_NOTIFY_BUS_CHECK) | ||
702 | return; | ||
703 | |||
704 | eeepc_rfkill_hotplug(); | ||
705 | } | ||
706 | |||
707 | static void eeepc_hotk_notify(struct acpi_device *device, u32 event) | ||
555 | { | 708 | { |
556 | static struct key_entry *key; | 709 | static struct key_entry *key; |
557 | u16 count; | 710 | u16 count; |
@@ -559,6 +712,8 @@ static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data) | |||
559 | 712 | ||
560 | if (!ehotk) | 713 | if (!ehotk) |
561 | return; | 714 | return; |
715 | if (event > ACPI_MAX_SYS_NOTIFY) | ||
716 | return; | ||
562 | if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) | 717 | if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) |
563 | brn = notify_brn(); | 718 | brn = notify_brn(); |
564 | count = ehotk->event_count[event % 128]++; | 719 | count = ehotk->event_count[event % 128]++; |
@@ -611,8 +766,7 @@ static int eeepc_register_rfkill_notifier(char *node) | |||
611 | eeepc_rfkill_notify, | 766 | eeepc_rfkill_notify, |
612 | NULL); | 767 | NULL); |
613 | if (ACPI_FAILURE(status)) | 768 | if (ACPI_FAILURE(status)) |
614 | printk(EEEPC_WARNING | 769 | pr_warning("Failed to register notify on %s\n", node); |
615 | "Failed to register notify on %s\n", node); | ||
616 | } else | 770 | } else |
617 | return -ENODEV; | 771 | return -ENODEV; |
618 | 772 | ||
@@ -631,20 +785,66 @@ static void eeepc_unregister_rfkill_notifier(char *node) | |||
631 | ACPI_SYSTEM_NOTIFY, | 785 | ACPI_SYSTEM_NOTIFY, |
632 | eeepc_rfkill_notify); | 786 | eeepc_rfkill_notify); |
633 | if (ACPI_FAILURE(status)) | 787 | if (ACPI_FAILURE(status)) |
634 | printk(EEEPC_ERR | 788 | pr_err("Error removing rfkill notify handler %s\n", |
635 | "Error removing rfkill notify handler %s\n", | ||
636 | node); | 789 | node); |
637 | } | 790 | } |
638 | } | 791 | } |
639 | 792 | ||
793 | static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) | ||
794 | { | ||
795 | kfree(hotplug_slot->info); | ||
796 | kfree(hotplug_slot); | ||
797 | } | ||
798 | |||
799 | static int eeepc_setup_pci_hotplug(void) | ||
800 | { | ||
801 | int ret = -ENOMEM; | ||
802 | struct pci_bus *bus = pci_find_bus(0, 1); | ||
803 | |||
804 | if (!bus) { | ||
805 | pr_err("Unable to find wifi PCI bus\n"); | ||
806 | return -ENODEV; | ||
807 | } | ||
808 | |||
809 | ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); | ||
810 | if (!ehotk->hotplug_slot) | ||
811 | goto error_slot; | ||
812 | |||
813 | ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), | ||
814 | GFP_KERNEL); | ||
815 | if (!ehotk->hotplug_slot->info) | ||
816 | goto error_info; | ||
817 | |||
818 | ehotk->hotplug_slot->private = ehotk; | ||
819 | ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; | ||
820 | ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops; | ||
821 | eeepc_get_adapter_status(ehotk->hotplug_slot, | ||
822 | &ehotk->hotplug_slot->info->adapter_status); | ||
823 | |||
824 | ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi"); | ||
825 | if (ret) { | ||
826 | pr_err("Unable to register hotplug slot - %d\n", ret); | ||
827 | goto error_register; | ||
828 | } | ||
829 | |||
830 | return 0; | ||
831 | |||
832 | error_register: | ||
833 | kfree(ehotk->hotplug_slot->info); | ||
834 | error_info: | ||
835 | kfree(ehotk->hotplug_slot); | ||
836 | ehotk->hotplug_slot = NULL; | ||
837 | error_slot: | ||
838 | return ret; | ||
839 | } | ||
840 | |||
640 | static int eeepc_hotk_add(struct acpi_device *device) | 841 | static int eeepc_hotk_add(struct acpi_device *device) |
641 | { | 842 | { |
642 | acpi_status status = AE_OK; | ||
643 | int result; | 843 | int result; |
644 | 844 | ||
645 | if (!device) | 845 | if (!device) |
646 | return -EINVAL; | 846 | return -EINVAL; |
647 | printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n"); | 847 | pr_notice(EEEPC_HOTK_NAME "\n"); |
648 | ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); | 848 | ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); |
649 | if (!ehotk) | 849 | if (!ehotk) |
650 | return -ENOMEM; | 850 | return -ENOMEM; |
@@ -657,58 +857,9 @@ static int eeepc_hotk_add(struct acpi_device *device) | |||
657 | result = eeepc_hotk_check(); | 857 | result = eeepc_hotk_check(); |
658 | if (result) | 858 | if (result) |
659 | goto ehotk_fail; | 859 | goto ehotk_fail; |
660 | status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, | ||
661 | eeepc_hotk_notify, ehotk); | ||
662 | if (ACPI_FAILURE(status)) | ||
663 | printk(EEEPC_ERR "Error installing notify handler\n"); | ||
664 | |||
665 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); | ||
666 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); | ||
667 | |||
668 | if (get_acpi(CM_ASL_WLAN) != -1) { | ||
669 | ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan", | ||
670 | &device->dev, | ||
671 | RFKILL_TYPE_WLAN, | ||
672 | &eeepc_rfkill_ops, | ||
673 | (void *)CM_ASL_WLAN); | ||
674 | |||
675 | if (!ehotk->eeepc_wlan_rfkill) | ||
676 | goto wlan_fail; | ||
677 | |||
678 | rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, | ||
679 | get_acpi(CM_ASL_WLAN) != 1); | ||
680 | result = rfkill_register(ehotk->eeepc_wlan_rfkill); | ||
681 | if (result) | ||
682 | goto wlan_fail; | ||
683 | } | ||
684 | |||
685 | if (get_acpi(CM_ASL_BLUETOOTH) != -1) { | ||
686 | ehotk->eeepc_bluetooth_rfkill = | ||
687 | rfkill_alloc("eeepc-bluetooth", | ||
688 | &device->dev, | ||
689 | RFKILL_TYPE_BLUETOOTH, | ||
690 | &eeepc_rfkill_ops, | ||
691 | (void *)CM_ASL_BLUETOOTH); | ||
692 | |||
693 | if (!ehotk->eeepc_bluetooth_rfkill) | ||
694 | goto bluetooth_fail; | ||
695 | |||
696 | rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill, | ||
697 | get_acpi(CM_ASL_BLUETOOTH) != 1); | ||
698 | result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); | ||
699 | if (result) | ||
700 | goto bluetooth_fail; | ||
701 | } | ||
702 | 860 | ||
703 | return 0; | 861 | return 0; |
704 | 862 | ||
705 | bluetooth_fail: | ||
706 | rfkill_destroy(ehotk->eeepc_bluetooth_rfkill); | ||
707 | rfkill_unregister(ehotk->eeepc_wlan_rfkill); | ||
708 | wlan_fail: | ||
709 | rfkill_destroy(ehotk->eeepc_wlan_rfkill); | ||
710 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); | ||
711 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); | ||
712 | ehotk_fail: | 863 | ehotk_fail: |
713 | kfree(ehotk); | 864 | kfree(ehotk); |
714 | ehotk = NULL; | 865 | ehotk = NULL; |
@@ -718,22 +869,39 @@ static int eeepc_hotk_add(struct acpi_device *device) | |||
718 | 869 | ||
719 | static int eeepc_hotk_remove(struct acpi_device *device, int type) | 870 | static int eeepc_hotk_remove(struct acpi_device *device, int type) |
720 | { | 871 | { |
721 | acpi_status status = 0; | ||
722 | |||
723 | if (!device || !acpi_driver_data(device)) | 872 | if (!device || !acpi_driver_data(device)) |
724 | return -EINVAL; | 873 | return -EINVAL; |
725 | status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY, | ||
726 | eeepc_hotk_notify); | ||
727 | if (ACPI_FAILURE(status)) | ||
728 | printk(EEEPC_ERR "Error removing notify handler\n"); | ||
729 | |||
730 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); | ||
731 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); | ||
732 | 874 | ||
733 | kfree(ehotk); | 875 | kfree(ehotk); |
734 | return 0; | 876 | return 0; |
735 | } | 877 | } |
736 | 878 | ||
879 | static int eeepc_hotk_resume(struct acpi_device *device) | ||
880 | { | ||
881 | if (ehotk->wlan_rfkill) { | ||
882 | bool wlan; | ||
883 | |||
884 | /* Workaround - it seems that _PTS disables the wireless | ||
885 | without notification or changing the value read by WLAN. | ||
886 | Normally this is fine because the correct value is restored | ||
887 | from the non-volatile storage on resume, but we need to do | ||
888 | it ourself if case suspend is aborted, or we lose wireless. | ||
889 | */ | ||
890 | wlan = get_acpi(CM_ASL_WLAN); | ||
891 | set_acpi(CM_ASL_WLAN, wlan); | ||
892 | |||
893 | rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1); | ||
894 | |||
895 | eeepc_rfkill_hotplug(); | ||
896 | } | ||
897 | |||
898 | if (ehotk->bluetooth_rfkill) | ||
899 | rfkill_set_sw_state(ehotk->bluetooth_rfkill, | ||
900 | get_acpi(CM_ASL_BLUETOOTH) != 1); | ||
901 | |||
902 | return 0; | ||
903 | } | ||
904 | |||
737 | /* | 905 | /* |
738 | * Hwmon | 906 | * Hwmon |
739 | */ | 907 | */ |
@@ -850,10 +1018,16 @@ static void eeepc_backlight_exit(void) | |||
850 | 1018 | ||
851 | static void eeepc_rfkill_exit(void) | 1019 | static void eeepc_rfkill_exit(void) |
852 | { | 1020 | { |
853 | if (ehotk->eeepc_wlan_rfkill) | 1021 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); |
854 | rfkill_unregister(ehotk->eeepc_wlan_rfkill); | 1022 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); |
855 | if (ehotk->eeepc_bluetooth_rfkill) | 1023 | if (ehotk->wlan_rfkill) |
856 | rfkill_unregister(ehotk->eeepc_bluetooth_rfkill); | 1024 | rfkill_unregister(ehotk->wlan_rfkill); |
1025 | if (ehotk->bluetooth_rfkill) | ||
1026 | rfkill_unregister(ehotk->bluetooth_rfkill); | ||
1027 | if (ehotk->wwan3g_rfkill) | ||
1028 | rfkill_unregister(ehotk->wwan3g_rfkill); | ||
1029 | if (ehotk->hotplug_slot) | ||
1030 | pci_hp_deregister(ehotk->hotplug_slot); | ||
857 | } | 1031 | } |
858 | 1032 | ||
859 | static void eeepc_input_exit(void) | 1033 | static void eeepc_input_exit(void) |
@@ -888,6 +1062,75 @@ static void __exit eeepc_laptop_exit(void) | |||
888 | platform_driver_unregister(&platform_driver); | 1062 | platform_driver_unregister(&platform_driver); |
889 | } | 1063 | } |
890 | 1064 | ||
1065 | static int eeepc_new_rfkill(struct rfkill **rfkill, | ||
1066 | const char *name, struct device *dev, | ||
1067 | enum rfkill_type type, int cm) | ||
1068 | { | ||
1069 | int result; | ||
1070 | |||
1071 | result = get_acpi(cm); | ||
1072 | if (result < 0) | ||
1073 | return result; | ||
1074 | |||
1075 | *rfkill = rfkill_alloc(name, dev, type, | ||
1076 | &eeepc_rfkill_ops, (void *)(unsigned long)cm); | ||
1077 | |||
1078 | if (!*rfkill) | ||
1079 | return -EINVAL; | ||
1080 | |||
1081 | rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1); | ||
1082 | result = rfkill_register(*rfkill); | ||
1083 | if (result) { | ||
1084 | rfkill_destroy(*rfkill); | ||
1085 | *rfkill = NULL; | ||
1086 | return result; | ||
1087 | } | ||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | |||
1092 | static int eeepc_rfkill_init(struct device *dev) | ||
1093 | { | ||
1094 | int result = 0; | ||
1095 | |||
1096 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); | ||
1097 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); | ||
1098 | |||
1099 | result = eeepc_new_rfkill(&ehotk->wlan_rfkill, | ||
1100 | "eeepc-wlan", dev, | ||
1101 | RFKILL_TYPE_WLAN, CM_ASL_WLAN); | ||
1102 | |||
1103 | if (result && result != -ENODEV) | ||
1104 | goto exit; | ||
1105 | |||
1106 | result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill, | ||
1107 | "eeepc-bluetooth", dev, | ||
1108 | RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH); | ||
1109 | |||
1110 | if (result && result != -ENODEV) | ||
1111 | goto exit; | ||
1112 | |||
1113 | result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill, | ||
1114 | "eeepc-wwan3g", dev, | ||
1115 | RFKILL_TYPE_WWAN, CM_ASL_3G); | ||
1116 | |||
1117 | if (result && result != -ENODEV) | ||
1118 | goto exit; | ||
1119 | |||
1120 | result = eeepc_setup_pci_hotplug(); | ||
1121 | /* | ||
1122 | * If we get -EBUSY then something else is handling the PCI hotplug - | ||
1123 | * don't fail in this case | ||
1124 | */ | ||
1125 | if (result == -EBUSY) | ||
1126 | result = 0; | ||
1127 | |||
1128 | exit: | ||
1129 | if (result && result != -ENODEV) | ||
1130 | eeepc_rfkill_exit(); | ||
1131 | return result; | ||
1132 | } | ||
1133 | |||
891 | static int eeepc_backlight_init(struct device *dev) | 1134 | static int eeepc_backlight_init(struct device *dev) |
892 | { | 1135 | { |
893 | struct backlight_device *bd; | 1136 | struct backlight_device *bd; |
@@ -895,8 +1138,7 @@ static int eeepc_backlight_init(struct device *dev) | |||
895 | bd = backlight_device_register(EEEPC_HOTK_FILE, dev, | 1138 | bd = backlight_device_register(EEEPC_HOTK_FILE, dev, |
896 | NULL, &eeepcbl_ops); | 1139 | NULL, &eeepcbl_ops); |
897 | if (IS_ERR(bd)) { | 1140 | if (IS_ERR(bd)) { |
898 | printk(EEEPC_ERR | 1141 | pr_err("Could not register eeepc backlight device\n"); |
899 | "Could not register eeepc backlight device\n"); | ||
900 | eeepc_backlight_device = NULL; | 1142 | eeepc_backlight_device = NULL; |
901 | return PTR_ERR(bd); | 1143 | return PTR_ERR(bd); |
902 | } | 1144 | } |
@@ -915,8 +1157,7 @@ static int eeepc_hwmon_init(struct device *dev) | |||
915 | 1157 | ||
916 | hwmon = hwmon_device_register(dev); | 1158 | hwmon = hwmon_device_register(dev); |
917 | if (IS_ERR(hwmon)) { | 1159 | if (IS_ERR(hwmon)) { |
918 | printk(EEEPC_ERR | 1160 | pr_err("Could not register eeepc hwmon device\n"); |
919 | "Could not register eeepc hwmon device\n"); | ||
920 | eeepc_hwmon_device = NULL; | 1161 | eeepc_hwmon_device = NULL; |
921 | return PTR_ERR(hwmon); | 1162 | return PTR_ERR(hwmon); |
922 | } | 1163 | } |
@@ -942,19 +1183,9 @@ static int __init eeepc_laptop_init(void) | |||
942 | acpi_bus_unregister_driver(&eeepc_hotk_driver); | 1183 | acpi_bus_unregister_driver(&eeepc_hotk_driver); |
943 | return -ENODEV; | 1184 | return -ENODEV; |
944 | } | 1185 | } |
945 | dev = acpi_get_physical_device(ehotk->device->handle); | ||
946 | 1186 | ||
947 | if (!acpi_video_backlight_support()) { | 1187 | eeepc_enable_camera(); |
948 | result = eeepc_backlight_init(dev); | ||
949 | if (result) | ||
950 | goto fail_backlight; | ||
951 | } else | ||
952 | printk(EEEPC_INFO "Backlight controlled by ACPI video " | ||
953 | "driver\n"); | ||
954 | 1188 | ||
955 | result = eeepc_hwmon_init(dev); | ||
956 | if (result) | ||
957 | goto fail_hwmon; | ||
958 | /* Register platform stuff */ | 1189 | /* Register platform stuff */ |
959 | result = platform_driver_register(&platform_driver); | 1190 | result = platform_driver_register(&platform_driver); |
960 | if (result) | 1191 | if (result) |
@@ -971,7 +1202,33 @@ static int __init eeepc_laptop_init(void) | |||
971 | &platform_attribute_group); | 1202 | &platform_attribute_group); |
972 | if (result) | 1203 | if (result) |
973 | goto fail_sysfs; | 1204 | goto fail_sysfs; |
1205 | |||
1206 | dev = &platform_device->dev; | ||
1207 | |||
1208 | if (!acpi_video_backlight_support()) { | ||
1209 | result = eeepc_backlight_init(dev); | ||
1210 | if (result) | ||
1211 | goto fail_backlight; | ||
1212 | } else | ||
1213 | pr_info("Backlight controlled by ACPI video " | ||
1214 | "driver\n"); | ||
1215 | |||
1216 | result = eeepc_hwmon_init(dev); | ||
1217 | if (result) | ||
1218 | goto fail_hwmon; | ||
1219 | |||
1220 | result = eeepc_rfkill_init(dev); | ||
1221 | if (result) | ||
1222 | goto fail_rfkill; | ||
1223 | |||
974 | return 0; | 1224 | return 0; |
1225 | fail_rfkill: | ||
1226 | eeepc_hwmon_exit(); | ||
1227 | fail_hwmon: | ||
1228 | eeepc_backlight_exit(); | ||
1229 | fail_backlight: | ||
1230 | sysfs_remove_group(&platform_device->dev.kobj, | ||
1231 | &platform_attribute_group); | ||
975 | fail_sysfs: | 1232 | fail_sysfs: |
976 | platform_device_del(platform_device); | 1233 | platform_device_del(platform_device); |
977 | fail_platform_device2: | 1234 | fail_platform_device2: |
@@ -979,12 +1236,7 @@ fail_platform_device2: | |||
979 | fail_platform_device1: | 1236 | fail_platform_device1: |
980 | platform_driver_unregister(&platform_driver); | 1237 | platform_driver_unregister(&platform_driver); |
981 | fail_platform_driver: | 1238 | fail_platform_driver: |
982 | eeepc_hwmon_exit(); | ||
983 | fail_hwmon: | ||
984 | eeepc_backlight_exit(); | ||
985 | fail_backlight: | ||
986 | eeepc_input_exit(); | 1239 | eeepc_input_exit(); |
987 | eeepc_rfkill_exit(); | ||
988 | return result; | 1240 | return result; |
989 | } | 1241 | } |
990 | 1242 | ||