diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/sony-laptop.c | 97 |
1 files changed, 81 insertions, 16 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 6db1661a5625..516dd22bbb26 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -727,20 +727,79 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, | |||
727 | return -1; | 727 | return -1; |
728 | } | 728 | } |
729 | 729 | ||
730 | static int sony_find_snc_handle(int handle) | 730 | struct sony_nc_handles { |
731 | u16 cap[0x10]; | ||
732 | struct device_attribute devattr; | ||
733 | }; | ||
734 | |||
735 | struct sony_nc_handles *handles; | ||
736 | |||
737 | static ssize_t sony_nc_handles_show(struct device *dev, | ||
738 | struct device_attribute *attr, char *buffer) | ||
739 | { | ||
740 | ssize_t len = 0; | ||
741 | int i; | ||
742 | |||
743 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | ||
744 | len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ", | ||
745 | handles->cap[i]); | ||
746 | } | ||
747 | len += snprintf(buffer + len, PAGE_SIZE - len, "\n"); | ||
748 | |||
749 | return len; | ||
750 | } | ||
751 | |||
752 | static int sony_nc_handles_setup(struct platform_device *pd) | ||
731 | { | 753 | { |
732 | int i; | 754 | int i; |
733 | int result; | 755 | int result; |
734 | 756 | ||
735 | for (i = 0x20; i < 0x30; i++) { | 757 | handles = kzalloc(sizeof(*handles), GFP_KERNEL); |
736 | acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result); | 758 | |
737 | if (result == handle) { | 759 | sysfs_attr_init(&handles->devattr.attr); |
738 | dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", | 760 | handles->devattr.attr.name = "handles"; |
739 | handle, i - 0x20); | 761 | handles->devattr.attr.mode = S_IRUGO; |
740 | return i-0x20; | 762 | handles->devattr.show = sony_nc_handles_show; |
763 | |||
764 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | ||
765 | if (!acpi_callsetfunc(sony_nc_acpi_handle, | ||
766 | "SN00", i + 0x20, &result)) { | ||
767 | dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", | ||
768 | result, i); | ||
769 | handles->cap[i] = result; | ||
741 | } | 770 | } |
742 | } | 771 | } |
743 | 772 | ||
773 | /* allow reading capabilities via sysfs */ | ||
774 | if (device_create_file(&pd->dev, &handles->devattr)) { | ||
775 | kfree(handles); | ||
776 | handles = NULL; | ||
777 | return -1; | ||
778 | } | ||
779 | |||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | static int sony_nc_handles_cleanup(struct platform_device *pd) | ||
784 | { | ||
785 | if (handles) { | ||
786 | device_remove_file(&pd->dev, &handles->devattr); | ||
787 | kfree(handles); | ||
788 | handles = NULL; | ||
789 | } | ||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static int sony_find_snc_handle(int handle) | ||
794 | { | ||
795 | int i; | ||
796 | for (i = 0; i < 0x10; i++) { | ||
797 | if (handles->cap[i] == handle) { | ||
798 | dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", | ||
799 | handle, i); | ||
800 | return i; | ||
801 | } | ||
802 | } | ||
744 | dprintk("handle 0x%.4x not found\n", handle); | 803 | dprintk("handle 0x%.4x not found\n", handle); |
745 | return -1; | 804 | return -1; |
746 | } | 805 | } |
@@ -1274,6 +1333,10 @@ static int sony_nc_add(struct acpi_device *device) | |||
1274 | goto outwalk; | 1333 | goto outwalk; |
1275 | } | 1334 | } |
1276 | 1335 | ||
1336 | result = sony_pf_add(); | ||
1337 | if (result) | ||
1338 | goto outpresent; | ||
1339 | |||
1277 | if (debug) { | 1340 | if (debug) { |
1278 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, | 1341 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, |
1279 | sony_nc_acpi_handle, 1, sony_walk_callback, | 1342 | sony_nc_acpi_handle, 1, sony_walk_callback, |
@@ -1281,7 +1344,7 @@ static int sony_nc_add(struct acpi_device *device) | |||
1281 | if (ACPI_FAILURE(status)) { | 1344 | if (ACPI_FAILURE(status)) { |
1282 | pr_warn(DRV_PFX "unable to walk acpi resources\n"); | 1345 | pr_warn(DRV_PFX "unable to walk acpi resources\n"); |
1283 | result = -ENODEV; | 1346 | result = -ENODEV; |
1284 | goto outwalk; | 1347 | goto outpresent; |
1285 | } | 1348 | } |
1286 | } | 1349 | } |
1287 | 1350 | ||
@@ -1294,6 +1357,8 @@ static int sony_nc_add(struct acpi_device *device) | |||
1294 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", | 1357 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", |
1295 | &handle))) { | 1358 | &handle))) { |
1296 | dprintk("Doing SNC setup\n"); | 1359 | dprintk("Doing SNC setup\n"); |
1360 | if (sony_nc_handles_setup(sony_pf_device)) | ||
1361 | goto outpresent; | ||
1297 | sony_nc_function_setup(device); | 1362 | sony_nc_function_setup(device); |
1298 | sony_nc_rfkill_setup(device); | 1363 | sony_nc_rfkill_setup(device); |
1299 | } | 1364 | } |
@@ -1302,7 +1367,7 @@ static int sony_nc_add(struct acpi_device *device) | |||
1302 | result = sony_laptop_setup_input(device); | 1367 | result = sony_laptop_setup_input(device); |
1303 | if (result) { | 1368 | if (result) { |
1304 | pr_err(DRV_PFX "Unable to create input devices.\n"); | 1369 | pr_err(DRV_PFX "Unable to create input devices.\n"); |
1305 | goto outwalk; | 1370 | goto outsnc; |
1306 | } | 1371 | } |
1307 | 1372 | ||
1308 | if (acpi_video_backlight_support()) { | 1373 | if (acpi_video_backlight_support()) { |
@@ -1330,10 +1395,6 @@ static int sony_nc_add(struct acpi_device *device) | |||
1330 | 1395 | ||
1331 | } | 1396 | } |
1332 | 1397 | ||
1333 | result = sony_pf_add(); | ||
1334 | if (result) | ||
1335 | goto outbacklight; | ||
1336 | |||
1337 | /* create sony_pf sysfs attributes related to the SNC device */ | 1398 | /* create sony_pf sysfs attributes related to the SNC device */ |
1338 | for (item = sony_nc_values; item->name; ++item) { | 1399 | for (item = sony_nc_values; item->name; ++item) { |
1339 | 1400 | ||
@@ -1379,14 +1440,17 @@ static int sony_nc_add(struct acpi_device *device) | |||
1379 | for (item = sony_nc_values; item->name; ++item) { | 1440 | for (item = sony_nc_values; item->name; ++item) { |
1380 | device_remove_file(&sony_pf_device->dev, &item->devattr); | 1441 | device_remove_file(&sony_pf_device->dev, &item->devattr); |
1381 | } | 1442 | } |
1382 | sony_pf_remove(); | ||
1383 | |||
1384 | outbacklight: | ||
1385 | if (sony_backlight_device) | 1443 | if (sony_backlight_device) |
1386 | backlight_device_unregister(sony_backlight_device); | 1444 | backlight_device_unregister(sony_backlight_device); |
1387 | 1445 | ||
1388 | sony_laptop_remove_input(); | 1446 | sony_laptop_remove_input(); |
1389 | 1447 | ||
1448 | outsnc: | ||
1449 | sony_nc_handles_cleanup(sony_pf_device); | ||
1450 | |||
1451 | outpresent: | ||
1452 | sony_pf_remove(); | ||
1453 | |||
1390 | outwalk: | 1454 | outwalk: |
1391 | sony_nc_rfkill_cleanup(); | 1455 | sony_nc_rfkill_cleanup(); |
1392 | return result; | 1456 | return result; |
@@ -1405,6 +1469,7 @@ static int sony_nc_remove(struct acpi_device *device, int type) | |||
1405 | device_remove_file(&sony_pf_device->dev, &item->devattr); | 1469 | device_remove_file(&sony_pf_device->dev, &item->devattr); |
1406 | } | 1470 | } |
1407 | 1471 | ||
1472 | sony_nc_handles_cleanup(sony_pf_device); | ||
1408 | sony_pf_remove(); | 1473 | sony_pf_remove(); |
1409 | sony_laptop_remove_input(); | 1474 | sony_laptop_remove_input(); |
1410 | sony_nc_rfkill_cleanup(); | 1475 | sony_nc_rfkill_cleanup(); |