diff options
author | Matthew Garrett <mjg59@srcf.ucam.org> | 2009-03-26 21:58:12 +0900 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-03-27 12:17:45 -0400 |
commit | badf26f00f2ed80615206d07bcfc2e3b78af5441 (patch) | |
tree | 73d0ebc2c0f8bae2f8a055ec059b8521d65b95c7 /drivers/platform/x86 | |
parent | 8e0ee43bc2c3e19db56a4adaa9a9b04ce885cd84 (diff) |
sony-laptop: Add support for new Sony platform API
Newer Sony Vaios provide a new API for accessing platform functionality. It
consists of a set of standardised methods for enabling events and performing
queries. These are each identified by a unique handle. This patch adds
support for calling functions based on their handle and ports the existing
code for these machines over to it.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Mattia Dongili <malattia@linux.it>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r-- | drivers/platform/x86/sony-laptop.c | 146 |
1 files changed, 65 insertions, 81 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 537959d07148..3c52ec9548ab 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -689,6 +689,31 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, return -1; } +static int sony_find_snc_handle(int handle) +{ + int i; + int result; + + for (i = 0x20; i < 0x30; i++) { + acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result); + if (result == handle) + return i-0x20; + } + + return -1; +} + +static int sony_call_snc_handle(int handle, int argument, int *result) +{ + int offset = sony_find_snc_handle(handle); + + if (offset < 0) + return -1; + + return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, + result); +} + /* * sony_nc_values input/output validate functions */ @@ -809,32 +834,6 @@ struct sony_nc_event { u8 event; }; -static struct sony_nc_event *sony_nc_events; - -/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence - * for Fn keys - */ -static int sony_nc_C_enable(const struct dmi_system_id *id) -{ - int result = 0; - - printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident); - - sony_nc_events = id->driver_data; - - if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0 - || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0 - || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0 - || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0 - || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0 - || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) { - printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some " - "functionalities may be missing\n"); - return 1; - } - return 0; -} - static struct sony_nc_event sony_C_events[] = { { 0x81, SONYPI_EVENT_FNKEY_F1 }, { 0x01, SONYPI_EVENT_FNKEY_RELEASED }, @@ -851,57 +850,17 @@ static struct sony_nc_event sony_C_events[] = { { 0, 0 }, }; -/* SNC-only model map */ -static const struct dmi_system_id sony_nc_ids[] = { - { - .ident = "Sony Vaio FE Series", - .callback = sony_nc_C_enable, - .driver_data = sony_C_events, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"), - }, - }, - { - .ident = "Sony Vaio FZ Series", - .callback = sony_nc_C_enable, - .driver_data = sony_C_events, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ"), - }, - }, - { - .ident = "Sony Vaio C Series", - .callback = sony_nc_C_enable, - .driver_data = sony_C_events, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), - }, - }, - { - .ident = "Sony Vaio N Series", - .callback = sony_nc_C_enable, - .driver_data = sony_C_events, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-N"), - }, - }, - { } -}; - /* * ACPI callbacks */ static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) { - struct sony_nc_event *evmap; + int i; u32 ev = event; int result; - if (ev == 0x92) { + if (ev == 0x92 || ev == 0x90) { + int origev = ev; /* read the key pressed from EC.GECR * A call to SN07 with 0x0202 will do it as well respecting * the current protocol on different OSes @@ -913,20 +872,23 @@ static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) * TODO: we may want to do the same for the older GHKE -need * dmi list- so this snippet may become one more callback. */ - if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0) + if (sony_call_snc_handle(0x100, 0x200, &result)) dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev); else ev = result & 0xFF; - } - if (sony_nc_events) - for (evmap = sony_nc_events; evmap->event; evmap++) { - if (evmap->data == ev) { - ev = evmap->event; + for (i = 0; sony_C_events[i].data; i++) { + if (sony_C_events[i].data == ev) { + ev = sony_C_events[i].event; break; } } + if (!sony_C_events[i].data) + printk(KERN_INFO DRV_PFX "Unknown event: %x %x\n", + origev, ev); + } + dprintk("sony_acpi_notify, event: 0x%.2x\n", ev); sony_laptop_report_input_event(ev); acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); @@ -953,9 +915,25 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, /* * ACPI device */ +static int sony_nc_function_setup(struct acpi_device *device) +{ + int result; + + /* Enable all events */ + acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result); + + /* Setup hotkeys */ + sony_call_snc_handle(0x0100, 0, &result); + sony_call_snc_handle(0x0101, 0, &result); + sony_call_snc_handle(0x0102, 0x100, &result); + + return 0; +} + static int sony_nc_resume(struct acpi_device *device) { struct sony_nc_value *item; + acpi_handle handle; for (item = sony_nc_values; item->name; item++) { int ret; @@ -970,14 +948,17 @@ static int sony_nc_resume(struct acpi_device *device) } } + if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", + &handle))) { + dprintk("Doing SNC setup\n"); + sony_nc_function_setup(device); + } + /* set the last requested brightness level */ if (sony_backlight_device && !sony_backlight_update_status(sony_backlight_device)) printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n"); - /* re-initialize models with specific requirements */ - dmi_check_system(sony_nc_ids); - return 0; } @@ -1024,6 +1005,12 @@ static int sony_nc_add(struct acpi_device *device) dprintk("_INI Method failed\n"); } + if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", + &handle))) { + dprintk("Doing SNC setup\n"); + sony_nc_function_setup(device); + } + /* setup input devices and helper fifo */ result = sony_laptop_setup_input(device); if (result) { @@ -1063,9 +1050,6 @@ static int sony_nc_add(struct acpi_device *device) } - /* initialize models with specific requirements */ - dmi_check_system(sony_nc_ids); - result = sony_pf_add(); if (result) goto outbacklight; |