summaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/sony-laptop.c97
1 files changed, 81 insertions, 16 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 6db1661a562..516dd22bbb2 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,
return -1;
}
-static int sony_find_snc_handle(int handle)
+struct sony_nc_handles {
+ u16 cap[0x10];
+ struct device_attribute devattr;
+};
+
+struct sony_nc_handles *handles;
+
+static ssize_t sony_nc_handles_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ ssize_t len = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+ len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
+ handles->cap[i]);
+ }
+ len += snprintf(buffer + len, PAGE_SIZE - len, "\n");
+
+ return len;
+}
+
+static int sony_nc_handles_setup(struct platform_device *pd)
{
int i;
int result;
- for (i = 0x20; i < 0x30; i++) {
- acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result);
- if (result == handle) {
- dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
- handle, i - 0x20);
- return i-0x20;
+ handles = kzalloc(sizeof(*handles), GFP_KERNEL);
+
+ sysfs_attr_init(&handles->devattr.attr);
+ handles->devattr.attr.name = "handles";
+ handles->devattr.attr.mode = S_IRUGO;
+ handles->devattr.show = sony_nc_handles_show;
+
+ for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+ if (!acpi_callsetfunc(sony_nc_acpi_handle,
+ "SN00", i + 0x20, &result)) {
+ dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
+ result, i);
+ handles->cap[i] = result;
}
}
+ /* allow reading capabilities via sysfs */
+ if (device_create_file(&pd->dev, &handles->devattr)) {
+ kfree(handles);
+ handles = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sony_nc_handles_cleanup(struct platform_device *pd)
+{
+ if (handles) {
+ device_remove_file(&pd->dev, &handles->devattr);
+ kfree(handles);
+ handles = NULL;
+ }
+ return 0;
+}
+
+static int sony_find_snc_handle(int handle)
+{
+ int i;
+ for (i = 0; i < 0x10; i++) {
+ if (handles->cap[i] == handle) {
+ dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
+ handle, i);
+ return i;
+ }
+ }
dprintk("handle 0x%.4x not found\n", handle);
return -1;
}
@@ -1274,6 +1333,10 @@ static int sony_nc_add(struct acpi_device *device)
goto outwalk;
}
+ result = sony_pf_add();
+ if (result)
+ goto outpresent;
+
if (debug) {
status = acpi_walk_namespace(ACPI_TYPE_METHOD,
sony_nc_acpi_handle, 1, sony_walk_callback,
@@ -1281,7 +1344,7 @@ static int sony_nc_add(struct acpi_device *device)
if (ACPI_FAILURE(status)) {
pr_warn(DRV_PFX "unable to walk acpi resources\n");
result = -ENODEV;
- goto outwalk;
+ goto outpresent;
}
}
@@ -1294,6 +1357,8 @@ static int sony_nc_add(struct acpi_device *device)
if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
&handle))) {
dprintk("Doing SNC setup\n");
+ if (sony_nc_handles_setup(sony_pf_device))
+ goto outpresent;
sony_nc_function_setup(device);
sony_nc_rfkill_setup(device);
}
@@ -1302,7 +1367,7 @@ static int sony_nc_add(struct acpi_device *device)
result = sony_laptop_setup_input(device);
if (result) {
pr_err(DRV_PFX "Unable to create input devices.\n");
- goto outwalk;
+ goto outsnc;
}
if (acpi_video_backlight_support()) {
@@ -1330,10 +1395,6 @@ static int sony_nc_add(struct acpi_device *device)
}
- result = sony_pf_add();
- if (result)
- goto outbacklight;
-
/* create sony_pf sysfs attributes related to the SNC device */
for (item = sony_nc_values; item->name; ++item) {
@@ -1379,14 +1440,17 @@ static int sony_nc_add(struct acpi_device *device)
for (item = sony_nc_values; item->name; ++item) {
device_remove_file(&sony_pf_device->dev, &item->devattr);
}
- sony_pf_remove();
-
- outbacklight:
if (sony_backlight_device)
backlight_device_unregister(sony_backlight_device);
sony_laptop_remove_input();
+ outsnc:
+ sony_nc_handles_cleanup(sony_pf_device);
+
+ outpresent:
+ sony_pf_remove();
+
outwalk:
sony_nc_rfkill_cleanup();
return result;
@@ -1405,6 +1469,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
device_remove_file(&sony_pf_device->dev, &item->devattr);
}
+ sony_nc_handles_cleanup(sony_pf_device);
sony_pf_remove();
sony_laptop_remove_input();
sony_nc_rfkill_cleanup();