diff options
Diffstat (limited to 'drivers/platform/x86/eeepc-laptop.c')
-rw-r--r-- | drivers/platform/x86/eeepc-laptop.c | 108 |
1 files changed, 74 insertions, 34 deletions
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 6b8e06206c46..1c45d92e2163 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
@@ -165,6 +165,7 @@ struct eeepc_laptop { | |||
165 | u16 event_count[128]; /* count for each event */ | 165 | u16 event_count[128]; /* count for each event */ |
166 | 166 | ||
167 | struct platform_device *platform_device; | 167 | struct platform_device *platform_device; |
168 | struct acpi_device *device; /* the device we are in */ | ||
168 | struct device *hwmon_device; | 169 | struct device *hwmon_device; |
169 | struct backlight_device *backlight_device; | 170 | struct backlight_device *backlight_device; |
170 | 171 | ||
@@ -227,7 +228,7 @@ static int set_acpi(struct eeepc_laptop *eeepc, int cm, int value) | |||
227 | return -ENODEV; | 228 | return -ENODEV; |
228 | 229 | ||
229 | if (write_acpi_int(eeepc->handle, method, value)) | 230 | if (write_acpi_int(eeepc->handle, method, value)) |
230 | pr_warning("Error writing %s\n", method); | 231 | pr_warn("Error writing %s\n", method); |
231 | return 0; | 232 | return 0; |
232 | } | 233 | } |
233 | 234 | ||
@@ -242,7 +243,7 @@ static int get_acpi(struct eeepc_laptop *eeepc, int cm) | |||
242 | return -ENODEV; | 243 | return -ENODEV; |
243 | 244 | ||
244 | if (read_acpi_int(eeepc->handle, method, &value)) | 245 | if (read_acpi_int(eeepc->handle, method, &value)) |
245 | pr_warning("Error reading %s\n", method); | 246 | pr_warn("Error reading %s\n", method); |
246 | return value; | 247 | return value; |
247 | } | 248 | } |
248 | 249 | ||
@@ -260,7 +261,7 @@ static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm, | |||
260 | status = acpi_get_handle(eeepc->handle, (char *)method, | 261 | status = acpi_get_handle(eeepc->handle, (char *)method, |
261 | handle); | 262 | handle); |
262 | if (status != AE_OK) { | 263 | if (status != AE_OK) { |
263 | pr_warning("Error finding %s\n", method); | 264 | pr_warn("Error finding %s\n", method); |
264 | return -ENODEV; | 265 | return -ENODEV; |
265 | } | 266 | } |
266 | return 0; | 267 | return 0; |
@@ -416,7 +417,7 @@ static ssize_t store_cpufv_disabled(struct device *dev, | |||
416 | switch (value) { | 417 | switch (value) { |
417 | case 0: | 418 | case 0: |
418 | if (eeepc->cpufv_disabled) | 419 | if (eeepc->cpufv_disabled) |
419 | pr_warning("cpufv enabled (not officially supported " | 420 | pr_warn("cpufv enabled (not officially supported " |
420 | "on this model)\n"); | 421 | "on this model)\n"); |
421 | eeepc->cpufv_disabled = false; | 422 | eeepc->cpufv_disabled = false; |
422 | return rv; | 423 | return rv; |
@@ -528,6 +529,15 @@ static void tpd_led_set(struct led_classdev *led_cdev, | |||
528 | queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); | 529 | queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); |
529 | } | 530 | } |
530 | 531 | ||
532 | static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) | ||
533 | { | ||
534 | struct eeepc_laptop *eeepc; | ||
535 | |||
536 | eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led); | ||
537 | |||
538 | return get_acpi(eeepc, CM_ASL_TPD); | ||
539 | } | ||
540 | |||
531 | static int eeepc_led_init(struct eeepc_laptop *eeepc) | 541 | static int eeepc_led_init(struct eeepc_laptop *eeepc) |
532 | { | 542 | { |
533 | int rv; | 543 | int rv; |
@@ -542,6 +552,8 @@ static int eeepc_led_init(struct eeepc_laptop *eeepc) | |||
542 | 552 | ||
543 | eeepc->tpd_led.name = "eeepc::touchpad"; | 553 | eeepc->tpd_led.name = "eeepc::touchpad"; |
544 | eeepc->tpd_led.brightness_set = tpd_led_set; | 554 | eeepc->tpd_led.brightness_set = tpd_led_set; |
555 | if (get_acpi(eeepc, CM_ASL_TPD) >= 0) /* if method is available */ | ||
556 | eeepc->tpd_led.brightness_get = tpd_led_get; | ||
545 | eeepc->tpd_led.max_brightness = 1; | 557 | eeepc->tpd_led.max_brightness = 1; |
546 | 558 | ||
547 | rv = led_classdev_register(&eeepc->platform_device->dev, | 559 | rv = led_classdev_register(&eeepc->platform_device->dev, |
@@ -573,8 +585,9 @@ static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc) | |||
573 | return true; | 585 | return true; |
574 | } | 586 | } |
575 | 587 | ||
576 | static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) | 588 | static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) |
577 | { | 589 | { |
590 | struct pci_dev *port; | ||
578 | struct pci_dev *dev; | 591 | struct pci_dev *dev; |
579 | struct pci_bus *bus; | 592 | struct pci_bus *bus; |
580 | bool blocked = eeepc_wlan_rfkill_blocked(eeepc); | 593 | bool blocked = eeepc_wlan_rfkill_blocked(eeepc); |
@@ -587,9 +600,16 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) | |||
587 | mutex_lock(&eeepc->hotplug_lock); | 600 | mutex_lock(&eeepc->hotplug_lock); |
588 | 601 | ||
589 | if (eeepc->hotplug_slot) { | 602 | if (eeepc->hotplug_slot) { |
590 | bus = pci_find_bus(0, 1); | 603 | port = acpi_get_pci_dev(handle); |
604 | if (!port) { | ||
605 | pr_warning("Unable to find port\n"); | ||
606 | goto out_unlock; | ||
607 | } | ||
608 | |||
609 | bus = port->subordinate; | ||
610 | |||
591 | if (!bus) { | 611 | if (!bus) { |
592 | pr_warning("Unable to find PCI bus 1?\n"); | 612 | pr_warn("Unable to find PCI bus 1?\n"); |
593 | goto out_unlock; | 613 | goto out_unlock; |
594 | } | 614 | } |
595 | 615 | ||
@@ -597,15 +617,16 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) | |||
597 | pr_err("Unable to read PCI config space?\n"); | 617 | pr_err("Unable to read PCI config space?\n"); |
598 | goto out_unlock; | 618 | goto out_unlock; |
599 | } | 619 | } |
620 | |||
600 | absent = (l == 0xffffffff); | 621 | absent = (l == 0xffffffff); |
601 | 622 | ||
602 | if (blocked != absent) { | 623 | if (blocked != absent) { |
603 | pr_warning("BIOS says wireless lan is %s, " | 624 | pr_warn("BIOS says wireless lan is %s, " |
604 | "but the pci device is %s\n", | 625 | "but the pci device is %s\n", |
605 | blocked ? "blocked" : "unblocked", | 626 | blocked ? "blocked" : "unblocked", |
606 | absent ? "absent" : "present"); | 627 | absent ? "absent" : "present"); |
607 | pr_warning("skipped wireless hotplug as probably " | 628 | pr_warn("skipped wireless hotplug as probably " |
608 | "inappropriate for this model\n"); | 629 | "inappropriate for this model\n"); |
609 | goto out_unlock; | 630 | goto out_unlock; |
610 | } | 631 | } |
611 | 632 | ||
@@ -635,6 +656,17 @@ out_unlock: | |||
635 | mutex_unlock(&eeepc->hotplug_lock); | 656 | mutex_unlock(&eeepc->hotplug_lock); |
636 | } | 657 | } |
637 | 658 | ||
659 | static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node) | ||
660 | { | ||
661 | acpi_status status = AE_OK; | ||
662 | acpi_handle handle; | ||
663 | |||
664 | status = acpi_get_handle(NULL, node, &handle); | ||
665 | |||
666 | if (ACPI_SUCCESS(status)) | ||
667 | eeepc_rfkill_hotplug(eeepc, handle); | ||
668 | } | ||
669 | |||
638 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | 670 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) |
639 | { | 671 | { |
640 | struct eeepc_laptop *eeepc = data; | 672 | struct eeepc_laptop *eeepc = data; |
@@ -642,7 +674,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | |||
642 | if (event != ACPI_NOTIFY_BUS_CHECK) | 674 | if (event != ACPI_NOTIFY_BUS_CHECK) |
643 | return; | 675 | return; |
644 | 676 | ||
645 | eeepc_rfkill_hotplug(eeepc); | 677 | eeepc_rfkill_hotplug(eeepc, handle); |
646 | } | 678 | } |
647 | 679 | ||
648 | static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, | 680 | static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, |
@@ -659,7 +691,13 @@ static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, | |||
659 | eeepc_rfkill_notify, | 691 | eeepc_rfkill_notify, |
660 | eeepc); | 692 | eeepc); |
661 | if (ACPI_FAILURE(status)) | 693 | if (ACPI_FAILURE(status)) |
662 | pr_warning("Failed to register notify on %s\n", node); | 694 | pr_warn("Failed to register notify on %s\n", node); |
695 | |||
696 | /* | ||
697 | * Refresh pci hotplug in case the rfkill state was | ||
698 | * changed during setup. | ||
699 | */ | ||
700 | eeepc_rfkill_hotplug(eeepc, handle); | ||
663 | } else | 701 | } else |
664 | return -ENODEV; | 702 | return -ENODEV; |
665 | 703 | ||
@@ -681,6 +719,12 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc, | |||
681 | if (ACPI_FAILURE(status)) | 719 | if (ACPI_FAILURE(status)) |
682 | pr_err("Error removing rfkill notify handler %s\n", | 720 | pr_err("Error removing rfkill notify handler %s\n", |
683 | node); | 721 | node); |
722 | /* | ||
723 | * Refresh pci hotplug in case the rfkill | ||
724 | * state was changed after | ||
725 | * eeepc_unregister_rfkill_notifier() | ||
726 | */ | ||
727 | eeepc_rfkill_hotplug(eeepc, handle); | ||
684 | } | 728 | } |
685 | } | 729 | } |
686 | 730 | ||
@@ -804,11 +848,7 @@ static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) | |||
804 | rfkill_destroy(eeepc->wlan_rfkill); | 848 | rfkill_destroy(eeepc->wlan_rfkill); |
805 | eeepc->wlan_rfkill = NULL; | 849 | eeepc->wlan_rfkill = NULL; |
806 | } | 850 | } |
807 | /* | 851 | |
808 | * Refresh pci hotplug in case the rfkill state was changed after | ||
809 | * eeepc_unregister_rfkill_notifier() | ||
810 | */ | ||
811 | eeepc_rfkill_hotplug(eeepc); | ||
812 | if (eeepc->hotplug_slot) | 852 | if (eeepc->hotplug_slot) |
813 | pci_hp_deregister(eeepc->hotplug_slot); | 853 | pci_hp_deregister(eeepc->hotplug_slot); |
814 | 854 | ||
@@ -877,11 +917,6 @@ static int eeepc_rfkill_init(struct eeepc_laptop *eeepc) | |||
877 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); | 917 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); |
878 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); | 918 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); |
879 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); | 919 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); |
880 | /* | ||
881 | * Refresh pci hotplug in case the rfkill state was changed during | ||
882 | * setup. | ||
883 | */ | ||
884 | eeepc_rfkill_hotplug(eeepc); | ||
885 | 920 | ||
886 | exit: | 921 | exit: |
887 | if (result && result != -ENODEV) | 922 | if (result && result != -ENODEV) |
@@ -916,8 +951,11 @@ static int eeepc_hotk_restore(struct device *device) | |||
916 | struct eeepc_laptop *eeepc = dev_get_drvdata(device); | 951 | struct eeepc_laptop *eeepc = dev_get_drvdata(device); |
917 | 952 | ||
918 | /* Refresh both wlan rfkill state and pci hotplug */ | 953 | /* Refresh both wlan rfkill state and pci hotplug */ |
919 | if (eeepc->wlan_rfkill) | 954 | if (eeepc->wlan_rfkill) { |
920 | eeepc_rfkill_hotplug(eeepc); | 955 | eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P5"); |
956 | eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P6"); | ||
957 | eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P7"); | ||
958 | } | ||
921 | 959 | ||
922 | if (eeepc->bluetooth_rfkill) | 960 | if (eeepc->bluetooth_rfkill) |
923 | rfkill_set_sw_state(eeepc->bluetooth_rfkill, | 961 | rfkill_set_sw_state(eeepc->bluetooth_rfkill, |
@@ -1114,7 +1152,7 @@ static int update_bl_status(struct backlight_device *bd) | |||
1114 | return set_brightness(bd, bd->props.brightness); | 1152 | return set_brightness(bd, bd->props.brightness); |
1115 | } | 1153 | } |
1116 | 1154 | ||
1117 | static struct backlight_ops eeepcbl_ops = { | 1155 | static const struct backlight_ops eeepcbl_ops = { |
1118 | .get_brightness = read_brightness, | 1156 | .get_brightness = read_brightness, |
1119 | .update_status = update_bl_status, | 1157 | .update_status = update_bl_status, |
1120 | }; | 1158 | }; |
@@ -1135,6 +1173,7 @@ static int eeepc_backlight_init(struct eeepc_laptop *eeepc) | |||
1135 | struct backlight_device *bd; | 1173 | struct backlight_device *bd; |
1136 | 1174 | ||
1137 | memset(&props, 0, sizeof(struct backlight_properties)); | 1175 | memset(&props, 0, sizeof(struct backlight_properties)); |
1176 | props.type = BACKLIGHT_PLATFORM; | ||
1138 | props.max_brightness = 15; | 1177 | props.max_brightness = 15; |
1139 | bd = backlight_device_register(EEEPC_LAPTOP_FILE, | 1178 | bd = backlight_device_register(EEEPC_LAPTOP_FILE, |
1140 | &eeepc->platform_device->dev, eeepc, | 1179 | &eeepc->platform_device->dev, eeepc, |
@@ -1193,9 +1232,9 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc) | |||
1193 | eeepc->inputdev = input; | 1232 | eeepc->inputdev = input; |
1194 | return 0; | 1233 | return 0; |
1195 | 1234 | ||
1196 | err_free_keymap: | 1235 | err_free_keymap: |
1197 | sparse_keymap_free(input); | 1236 | sparse_keymap_free(input); |
1198 | err_free_dev: | 1237 | err_free_dev: |
1199 | input_free_device(input); | 1238 | input_free_device(input); |
1200 | return error; | 1239 | return error; |
1201 | } | 1240 | } |
@@ -1206,6 +1245,7 @@ static void eeepc_input_exit(struct eeepc_laptop *eeepc) | |||
1206 | sparse_keymap_free(eeepc->inputdev); | 1245 | sparse_keymap_free(eeepc->inputdev); |
1207 | input_unregister_device(eeepc->inputdev); | 1246 | input_unregister_device(eeepc->inputdev); |
1208 | } | 1247 | } |
1248 | eeepc->inputdev = NULL; | ||
1209 | } | 1249 | } |
1210 | 1250 | ||
1211 | /* | 1251 | /* |
@@ -1308,7 +1348,7 @@ static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name) | |||
1308 | { | 1348 | { |
1309 | int dummy; | 1349 | int dummy; |
1310 | 1350 | ||
1311 | /* Some BIOSes do not report cm although it is avaliable. | 1351 | /* Some BIOSes do not report cm although it is available. |
1312 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ | 1352 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ |
1313 | if (!(eeepc->cm_supported & (1 << cm)) | 1353 | if (!(eeepc->cm_supported & (1 << cm)) |
1314 | && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { | 1354 | && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { |
@@ -1326,16 +1366,15 @@ static void cmsg_quirks(struct eeepc_laptop *eeepc) | |||
1326 | cmsg_quirk(eeepc, CM_ASL_TPD, "TPD"); | 1366 | cmsg_quirk(eeepc, CM_ASL_TPD, "TPD"); |
1327 | } | 1367 | } |
1328 | 1368 | ||
1329 | static int eeepc_acpi_init(struct eeepc_laptop *eeepc, | 1369 | static int __devinit eeepc_acpi_init(struct eeepc_laptop *eeepc) |
1330 | struct acpi_device *device) | ||
1331 | { | 1370 | { |
1332 | unsigned int init_flags; | 1371 | unsigned int init_flags; |
1333 | int result; | 1372 | int result; |
1334 | 1373 | ||
1335 | result = acpi_bus_get_status(device); | 1374 | result = acpi_bus_get_status(eeepc->device); |
1336 | if (result) | 1375 | if (result) |
1337 | return result; | 1376 | return result; |
1338 | if (!device->status.present) { | 1377 | if (!eeepc->device->status.present) { |
1339 | pr_err("Hotkey device not present, aborting\n"); | 1378 | pr_err("Hotkey device not present, aborting\n"); |
1340 | return -ENODEV; | 1379 | return -ENODEV; |
1341 | } | 1380 | } |
@@ -1384,12 +1423,13 @@ static int __devinit eeepc_acpi_add(struct acpi_device *device) | |||
1384 | strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME); | 1423 | strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME); |
1385 | strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS); | 1424 | strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS); |
1386 | device->driver_data = eeepc; | 1425 | device->driver_data = eeepc; |
1426 | eeepc->device = device; | ||
1387 | 1427 | ||
1388 | eeepc->hotplug_disabled = hotplug_disabled; | 1428 | eeepc->hotplug_disabled = hotplug_disabled; |
1389 | 1429 | ||
1390 | eeepc_dmi_check(eeepc); | 1430 | eeepc_dmi_check(eeepc); |
1391 | 1431 | ||
1392 | result = eeepc_acpi_init(eeepc, device); | 1432 | result = eeepc_acpi_init(eeepc); |
1393 | if (result) | 1433 | if (result) |
1394 | goto fail_platform; | 1434 | goto fail_platform; |
1395 | eeepc_enable_camera(eeepc); | 1435 | eeepc_enable_camera(eeepc); |