diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-08-18 11:08:22 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-08-18 11:08:22 +1000 |
commit | ef41fa33e776eaff466bc4158276d5df5fe937f2 (patch) | |
tree | 26ed67d0f652c2a476d748ae693d8925f6db3659 | |
parent | 3f84e346d8249fb41e007c8f2551cedfb545375e (diff) | |
parent | 35989e9d7e19deb4b395aee7d120b1536337b4af (diff) |
Merge remote branch 'drivers-x86/linux-next'
-rw-r--r-- | Documentation/laptops/thinkpad-acpi.txt | 4 | ||||
-rw-r--r-- | drivers/platform/x86/Kconfig | 6 | ||||
-rw-r--r-- | drivers/platform/x86/asus_acpi.c | 6 | ||||
-rw-r--r-- | drivers/platform/x86/compal-laptop.c | 9 | ||||
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 7 | ||||
-rw-r--r-- | drivers/platform/x86/dell-wmi.c | 256 | ||||
-rw-r--r-- | drivers/platform/x86/hp-wmi.c | 172 | ||||
-rw-r--r-- | drivers/platform/x86/intel_ips.c | 15 | ||||
-rw-r--r-- | drivers/platform/x86/panasonic-laptop.c | 172 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 171 | ||||
-rw-r--r-- | drivers/platform/x86/topstar-laptop.c | 161 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 191 |
12 files changed, 452 insertions, 718 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index f6f80257addb..1565eefd6fd5 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -1024,6 +1024,10 @@ ThinkPad-specific interface. The driver will disable its native backlight brightness control interface if it detects that the standard ACPI interface is available in the ThinkPad. +If you want to use the thinkpad-acpi backlight brightness control +instead of the generic ACPI video backlight brightness control for some +reason, you should use the acpi_backlight=vendor kernel parameter. + The brightness_enable module parameter can be used to control whether the LCD brightness control feature will be enabled when available. brightness_enable=0 forces it to be disabled. brightness_enable=1 diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 044f430f3b43..84983898a512 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -92,6 +92,7 @@ config DELL_WMI tristate "Dell WMI extras" depends on ACPI_WMI depends on INPUT + select INPUT_SPARSEKMAP ---help--- Say Y here if you want to support WMI-based hotkeys on Dell laptops. @@ -140,6 +141,7 @@ config HP_WMI depends on ACPI_WMI depends on INPUT depends on RFKILL || RFKILL = n + select INPUT_SPARSEKMAP help Say Y here if you want to support WMI-based hotkeys on HP laptops and to read data from WMI such as docking or ambient light sensor state. @@ -171,6 +173,7 @@ config PANASONIC_LAPTOP tristate "Panasonic Laptop Extras" depends on INPUT && ACPI depends on BACKLIGHT_CLASS_DEVICE + select INPUT_SPARSEKMAP ---help--- This driver adds support for access to backlight control and hotkeys on Panasonic Let's Note laptops. @@ -478,6 +481,7 @@ config TOPSTAR_LAPTOP tristate "Topstar Laptop Extras" depends on ACPI depends on INPUT + select INPUT_SPARSEKMAP ---help--- This driver adds support for hotkeys found on Topstar laptops. @@ -488,7 +492,7 @@ config ACPI_TOSHIBA depends on ACPI depends on INPUT depends on RFKILL || RFKILL = n - select INPUT_POLLDEV + select INPUT_SPARSEKMAP select BACKLIGHT_CLASS_DEVICE ---help--- This driver adds support for access to certain system settings diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index e058c2ba2a15..ca05aefd03bf 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c @@ -938,10 +938,11 @@ static int set_brightness(int value) /* SPLV laptop */ if (hotk->methods->brightness_set) { if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set, - value, NULL)) + value, NULL)) { printk(KERN_WARNING "Asus ACPI: Error changing brightness\n"); ret = -EIO; + } goto out; } @@ -953,10 +954,11 @@ static int set_brightness(int value) hotk->methods->brightness_down, NULL, NULL); (value > 0) ? value-- : value++; - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { printk(KERN_WARNING "Asus ACPI: Error changing brightness\n"); ret = -EIO; + } } out: return ret; diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index d071ce056322..097083cac413 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -841,6 +841,14 @@ static struct dmi_system_id __initdata compal_dmi_table[] = { .callback = dmi_check_cb }, { + .ident = "Dell Mini 1012", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), + }, + .callback = dmi_check_cb + }, + { .ident = "Dell Inspiron 11z", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), @@ -1092,5 +1100,6 @@ MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*"); +MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1012:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*"); diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index b41ed5cab3e7..4413975912e0 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -122,6 +122,13 @@ static struct dmi_system_id __devinitdata dell_blacklist[] = { }, }, { + .ident = "Dell Mini 1012", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), + }, + }, + { .ident = "Dell Inspiron 11z", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 08fb70f6d9bf..77f1d55414c6 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/input.h> +#include <linux/input/sparse-keymap.h> #include <acpi/acpi_drivers.h> #include <linux/acpi.h> #include <linux/string.h> @@ -44,78 +45,70 @@ static int acpi_video; MODULE_ALIAS("wmi:"DELL_EVENT_GUID); -struct key_entry { - char type; /* See KE_* below */ - u16 code; - u16 keycode; -}; - -enum { KE_KEY, KE_SW, KE_IGNORE, KE_END }; - /* * Certain keys are flagged as KE_IGNORE. All of these are either * notifications (rather than requests for change) or are also sent * via the keyboard controller so should not be sent again. */ -static struct key_entry dell_legacy_wmi_keymap[] = { - {KE_KEY, 0xe045, KEY_PROG1}, - {KE_KEY, 0xe009, KEY_EJECTCD}, +static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { + { KE_KEY, 0xe045, { KEY_PROG1 } }, + { KE_KEY, 0xe009, { KEY_EJECTCD } }, /* These also contain the brightness level at offset 6 */ - {KE_KEY, 0xe006, KEY_BRIGHTNESSUP}, - {KE_KEY, 0xe005, KEY_BRIGHTNESSDOWN}, + { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } }, /* Battery health status button */ - {KE_KEY, 0xe007, KEY_BATTERY}, + { KE_KEY, 0xe007, { KEY_BATTERY } }, /* This is actually for all radios. Although physically a * switch, the notification does not provide an indication of * state and so it should be reported as a key */ - {KE_KEY, 0xe008, KEY_WLAN}, + { KE_KEY, 0xe008, { KEY_WLAN } }, /* The next device is at offset 6, the active devices are at offset 8 and the attached devices at offset 10 */ - {KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE}, + { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } }, - {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE}, + { KE_IGNORE, 0xe00c, { KEY_KBDILLUMTOGGLE } }, /* BIOS error detected */ - {KE_IGNORE, 0xe00d, KEY_RESERVED}, + { KE_IGNORE, 0xe00d, { KEY_RESERVED } }, /* Wifi Catcher */ - {KE_KEY, 0xe011, KEY_PROG2}, + { KE_KEY, 0xe011, {KEY_PROG2 } }, /* Ambient light sensor toggle */ - {KE_IGNORE, 0xe013, KEY_RESERVED}, - - {KE_IGNORE, 0xe020, KEY_MUTE}, - {KE_IGNORE, 0xe02e, KEY_VOLUMEDOWN}, - {KE_IGNORE, 0xe030, KEY_VOLUMEUP}, - {KE_IGNORE, 0xe033, KEY_KBDILLUMUP}, - {KE_IGNORE, 0xe034, KEY_KBDILLUMDOWN}, - {KE_IGNORE, 0xe03a, KEY_CAPSLOCK}, - {KE_IGNORE, 0xe045, KEY_NUMLOCK}, - {KE_IGNORE, 0xe046, KEY_SCROLLLOCK}, - {KE_END, 0} + { KE_IGNORE, 0xe013, { KEY_RESERVED } }, + + { KE_IGNORE, 0xe020, { KEY_MUTE } }, + { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, + { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } }, + { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } }, + { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } }, + { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } }, + { KE_IGNORE, 0xe045, { KEY_NUMLOCK } }, + { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } }, + { KE_END, 0 } }; static bool dell_new_hk_type; -struct dell_new_keymap_entry { +struct dell_bios_keymap_entry { u16 scancode; u16 keycode; }; -struct dell_hotkey_table { +struct dell_bios_hotkey_table { struct dmi_header header; - struct dell_new_keymap_entry keymap[]; + struct dell_bios_keymap_entry keymap[]; }; -static struct key_entry *dell_new_wmi_keymap; +static const struct dell_bios_hotkey_table *dell_bios_hotkey_table; -static u16 bios_to_linux_keycode[256] = { +static const u16 bios_to_linux_keycode[256] __initconst = { KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG, KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, @@ -138,68 +131,11 @@ static u16 bios_to_linux_keycode[256] = { KEY_PROG3 }; - -static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap; - static struct input_dev *dell_wmi_input_dev; -static struct key_entry *dell_wmi_get_entry_by_scancode(unsigned int code) -{ - struct key_entry *key; - - for (key = dell_wmi_keymap; key->type != KE_END; key++) - if (code == key->code) - return key; - - return NULL; -} - -static struct key_entry *dell_wmi_get_entry_by_keycode(unsigned int keycode) -{ - struct key_entry *key; - - for (key = dell_wmi_keymap; key->type != KE_END; key++) - if (key->type == KE_KEY && keycode == key->keycode) - return key; - - return NULL; -} - -static int dell_wmi_getkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) -{ - struct key_entry *key = dell_wmi_get_entry_by_scancode(scancode); - - if (key && key->type == KE_KEY) { - *keycode = key->keycode; - return 0; - } - - return -EINVAL; -} - -static int dell_wmi_setkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode) -{ - struct key_entry *key; - unsigned int old_keycode; - - key = dell_wmi_get_entry_by_scancode(scancode); - if (key && key->type == KE_KEY) { - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!dell_wmi_get_entry_by_keycode(old_keycode)) - clear_bit(old_keycode, dev->keybit); - return 0; - } - return -EINVAL; -} - static void dell_wmi_notify(u32 value, void *context) { struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; - static struct key_entry *key; union acpi_object *obj; acpi_status status; @@ -212,8 +148,10 @@ static void dell_wmi_notify(u32 value, void *context) obj = (union acpi_object *)response.pointer; if (obj && obj->type == ACPI_TYPE_BUFFER) { + const struct key_entry *key; int reported_key; u16 *buffer_entry = (u16 *)obj->buffer.pointer; + if (dell_new_hk_type && (buffer_entry[1] != 0x10)) { printk(KERN_INFO "dell-wmi: Received unknown WMI event" " (0x%x)\n", buffer_entry[1]); @@ -226,8 +164,8 @@ static void dell_wmi_notify(u32 value, void *context) else reported_key = (int)buffer_entry[1] & 0xffff; - key = dell_wmi_get_entry_by_scancode(reported_key); - + key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, + reported_key); if (!key) { printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n", reported_key); @@ -237,92 +175,98 @@ static void dell_wmi_notify(u32 value, void *context) * come via ACPI */ ; } else { - input_report_key(dell_wmi_input_dev, key->keycode, 1); - input_sync(dell_wmi_input_dev); - input_report_key(dell_wmi_input_dev, key->keycode, 0); - input_sync(dell_wmi_input_dev); + sparse_keymap_report_entry(dell_wmi_input_dev, key, + 1, true); } } kfree(obj); } - -static void setup_new_hk_map(const struct dmi_header *dm) +static const struct key_entry * __init dell_wmi_prepare_new_keymap(void) { - + int hotkey_num = (dell_bios_hotkey_table->header.length - 4) / + sizeof(struct dell_bios_keymap_entry); + struct key_entry *keymap; int i; - int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry); - struct dell_hotkey_table *table = - container_of(dm, struct dell_hotkey_table, header); - dell_new_wmi_keymap = kzalloc((hotkey_num+1) * - sizeof(struct key_entry), GFP_KERNEL); + keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL); + if (!keymap) + return NULL; for (i = 0; i < hotkey_num; i++) { - dell_new_wmi_keymap[i].type = KE_KEY; - dell_new_wmi_keymap[i].code = table->keymap[i].scancode; - dell_new_wmi_keymap[i].keycode = - (table->keymap[i].keycode > 255) ? 0 : - bios_to_linux_keycode[table->keymap[i].keycode]; + const struct dell_bios_keymap_entry *bios_entry = + &dell_bios_hotkey_table->keymap[i]; + keymap[i].type = KE_KEY; + keymap[i].code = bios_entry->scancode; + keymap[i].keycode = bios_entry->keycode < 256 ? + bios_to_linux_keycode[bios_entry->keycode] : + KEY_RESERVED; } - dell_new_wmi_keymap[i].type = KE_END; - dell_new_wmi_keymap[i].code = 0; - dell_new_wmi_keymap[i].keycode = 0; - - dell_wmi_keymap = dell_new_wmi_keymap; + keymap[hotkey_num].type = KE_END; + return keymap; } - -static void find_hk_type(const struct dmi_header *dm, void *dummy) -{ - - if ((dm->type == 0xb2) && (dm->length > 6)) { - dell_new_hk_type = true; - setup_new_hk_map(dm); - } - -} - - static int __init dell_wmi_input_setup(void) { - struct key_entry *key; int err; dell_wmi_input_dev = input_allocate_device(); - if (!dell_wmi_input_dev) return -ENOMEM; dell_wmi_input_dev->name = "Dell WMI hotkeys"; dell_wmi_input_dev->phys = "wmi/input0"; dell_wmi_input_dev->id.bustype = BUS_HOST; - dell_wmi_input_dev->getkeycode = dell_wmi_getkeycode; - dell_wmi_input_dev->setkeycode = dell_wmi_setkeycode; - - for (key = dell_wmi_keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, dell_wmi_input_dev->evbit); - set_bit(key->keycode, dell_wmi_input_dev->keybit); - break; - case KE_SW: - set_bit(EV_SW, dell_wmi_input_dev->evbit); - set_bit(key->keycode, dell_wmi_input_dev->swbit); - break; + + if (dell_new_hk_type) { + const struct key_entry *keymap = dell_wmi_prepare_new_keymap(); + if (!keymap) { + err = -ENOMEM; + goto err_free_dev; } - } - err = input_register_device(dell_wmi_input_dev); + err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL); - if (err) { - input_free_device(dell_wmi_input_dev); - return err; + /* + * Sparse keymap library makes a copy of keymap so we + * don't need the original one that was allocated. + */ + kfree(keymap); + } else { + err = sparse_keymap_setup(dell_wmi_input_dev, + dell_wmi_legacy_keymap, NULL); } + if (err) + goto err_free_dev; + + err = input_register_device(dell_wmi_input_dev); + if (err) + goto err_free_keymap; return 0; + + err_free_keymap: + sparse_keymap_free(dell_wmi_input_dev); + err_free_dev: + input_free_device(dell_wmi_input_dev); + return err; +} + +static void dell_wmi_input_destroy(void) +{ + sparse_keymap_free(dell_wmi_input_dev); + input_unregister_device(dell_wmi_input_dev); +} + +static void __init find_hk_type(const struct dmi_header *dm, void *dummy) +{ + if (dm->type == 0xb2 && dm->length > 6) { + dell_new_hk_type = true; + dell_bios_hotkey_table = + container_of(dm, struct dell_bios_hotkey_table, header); + } } static int __init dell_wmi_init(void) @@ -339,18 +283,13 @@ static int __init dell_wmi_init(void) acpi_video = acpi_video_backlight_support(); err = dell_wmi_input_setup(); - if (err) { - if (dell_new_hk_type) - kfree(dell_wmi_keymap); + if (err) return err; - } status = wmi_install_notify_handler(DELL_EVENT_GUID, dell_wmi_notify, NULL); if (ACPI_FAILURE(status)) { - input_unregister_device(dell_wmi_input_dev); - if (dell_new_hk_type) - kfree(dell_wmi_keymap); + dell_wmi_input_destroy(); printk(KERN_ERR "dell-wmi: Unable to register notify handler - %d\n", status); @@ -359,14 +298,11 @@ static int __init dell_wmi_init(void) return 0; } +module_init(dell_wmi_init); static void __exit dell_wmi_exit(void) { wmi_remove_notify_handler(DELL_EVENT_GUID); - input_unregister_device(dell_wmi_input_dev); - if (dell_new_hk_type) - kfree(dell_wmi_keymap); + dell_wmi_input_destroy(); } - -module_init(dell_wmi_init); module_exit(dell_wmi_exit); diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index f15516374987..92a8c1831ca3 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/input.h> +#include <linux/input/sparse-keymap.h> #include <linux/platform_device.h> #include <linux/acpi.h> #include <linux/rfkill.h> @@ -87,24 +88,16 @@ struct bios_return { u32 return_code; }; -struct key_entry { - char type; /* See KE_* below */ - u16 code; - u16 keycode; -}; - -enum { KE_KEY, KE_END }; - -static struct key_entry hp_wmi_keymap[] = { - {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, - {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, - {KE_KEY, 0x20e6, KEY_PROG1}, - {KE_KEY, 0x20e8, KEY_MEDIA}, - {KE_KEY, 0x2142, KEY_MEDIA}, - {KE_KEY, 0x213b, KEY_INFO}, - {KE_KEY, 0x2169, KEY_DIRECTION}, - {KE_KEY, 0x231b, KEY_HELP}, - {KE_END, 0} +static const struct key_entry hp_wmi_keymap[] = { + { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } }, + { KE_KEY, 0x20e6, { KEY_PROG1 } }, + { KE_KEY, 0x20e8, { KEY_MEDIA } }, + { KE_KEY, 0x2142, { KEY_MEDIA } }, + { KE_KEY, 0x213b, { KEY_INFO } }, + { KE_KEY, 0x2169, { KEY_DIRECTION } }, + { KE_KEY, 0x231b, { KEY_HELP } }, + { KE_END, 0 } }; static struct input_dev *hp_wmi_input_dev; @@ -361,64 +354,9 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); -static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code) -{ - struct key_entry *key; - - for (key = hp_wmi_keymap; key->type != KE_END; key++) - if (code == key->code) - return key; - - return NULL; -} - -static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode) -{ - struct key_entry *key; - - for (key = hp_wmi_keymap; key->type != KE_END; key++) - if (key->type == KE_KEY && keycode == key->keycode) - return key; - - return NULL; -} - -static int hp_wmi_getkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) -{ - struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode); - - if (key && key->type == KE_KEY) { - *keycode = key->keycode; - return 0; - } - - return -EINVAL; -} - -static int hp_wmi_setkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode) -{ - struct key_entry *key; - unsigned int old_keycode; - - key = hp_wmi_get_entry_by_scancode(scancode); - if (key && key->type == KE_KEY) { - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!hp_wmi_get_entry_by_keycode(old_keycode)) - clear_bit(old_keycode, dev->keybit); - return 0; - } - - return -EINVAL; -} - static void hp_wmi_notify(u32 value, void *context) { struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; - static struct key_entry *key; union acpi_object *obj; u32 event_id, event_data; int key_code, ret; @@ -479,19 +417,9 @@ static void hp_wmi_notify(u32 value, void *context) sizeof(key_code)); if (ret) break; - key = hp_wmi_get_entry_by_scancode(key_code); - if (key) { - switch (key->type) { - case KE_KEY: - input_report_key(hp_wmi_input_dev, - key->keycode, 1); - input_sync(hp_wmi_input_dev); - input_report_key(hp_wmi_input_dev, - key->keycode, 0); - input_sync(hp_wmi_input_dev); - break; - } - } else + + if (!sparse_keymap_report_event(hp_wmi_input_dev, + key_code, 1, true)) printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n", key_code); break; @@ -524,7 +452,7 @@ static void hp_wmi_notify(u32 value, void *context) static int __init hp_wmi_input_setup(void) { - struct key_entry *key; + acpi_status status; int err; hp_wmi_input_dev = input_allocate_device(); @@ -534,21 +462,14 @@ static int __init hp_wmi_input_setup(void) hp_wmi_input_dev->name = "HP WMI hotkeys"; hp_wmi_input_dev->phys = "wmi/input0"; hp_wmi_input_dev->id.bustype = BUS_HOST; - hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode; - hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode; - - for (key = hp_wmi_keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, hp_wmi_input_dev->evbit); - set_bit(key->keycode, hp_wmi_input_dev->keybit); - break; - } - } - set_bit(EV_SW, hp_wmi_input_dev->evbit); - set_bit(SW_DOCK, hp_wmi_input_dev->swbit); - set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); + __set_bit(EV_SW, hp_wmi_input_dev->evbit); + __set_bit(SW_DOCK, hp_wmi_input_dev->swbit); + __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); + + err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL); + if (err) + goto err_free_dev; /* Set initial hardware state */ input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); @@ -556,14 +477,32 @@ static int __init hp_wmi_input_setup(void) hp_wmi_tablet_state()); input_sync(hp_wmi_input_dev); - err = input_register_device(hp_wmi_input_dev); - - if (err) { - input_free_device(hp_wmi_input_dev); - return err; + status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); + if (ACPI_FAILURE(status)) { + err = -EIO; + goto err_free_keymap; } + err = input_register_device(hp_wmi_input_dev); + if (err) + goto err_uninstall_notifier; + return 0; + + err_uninstall_notifier: + wmi_remove_notify_handler(HPWMI_EVENT_GUID); + err_free_keymap: + sparse_keymap_free(hp_wmi_input_dev); + err_free_dev: + input_free_device(hp_wmi_input_dev); + return err; +} + +static void hp_wmi_input_destroy(void) +{ + wmi_remove_notify_handler(HPWMI_EVENT_GUID); + sparse_keymap_free(hp_wmi_input_dev); + input_unregister_device(hp_wmi_input_dev); } static void cleanup_sysfs(struct platform_device *device) @@ -718,15 +657,9 @@ static int __init hp_wmi_init(void) int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); if (event_capable) { - err = wmi_install_notify_handler(HPWMI_EVENT_GUID, - hp_wmi_notify, NULL); - if (ACPI_FAILURE(err)) - return -EINVAL; err = hp_wmi_input_setup(); - if (err) { - wmi_remove_notify_handler(HPWMI_EVENT_GUID); + if (err) return err; - } } if (bios_capable) { @@ -753,20 +686,17 @@ err_device_add: err_device_alloc: platform_driver_unregister(&hp_wmi_driver); err_driver_reg: - if (wmi_has_guid(HPWMI_EVENT_GUID)) { - input_unregister_device(hp_wmi_input_dev); - wmi_remove_notify_handler(HPWMI_EVENT_GUID); - } + if (event_capable) + hp_wmi_input_destroy(); return err; } static void __exit hp_wmi_exit(void) { - if (wmi_has_guid(HPWMI_EVENT_GUID)) { - wmi_remove_notify_handler(HPWMI_EVENT_GUID); - input_unregister_device(hp_wmi_input_dev); - } + if (wmi_has_guid(HPWMI_EVENT_GUID)) + hp_wmi_input_destroy(); + if (hp_wmi_platform_dev) { platform_device_unregister(hp_wmi_platform_dev); platform_driver_unregister(&hp_wmi_driver); diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index afe82e50dfea..9024480a8228 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -1342,8 +1342,10 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips) limits = &ips_lv_limits; else if (strstr(boot_cpu_data.x86_model_id, "CPU U")) limits = &ips_ulv_limits; - else + else { dev_info(&ips->dev->dev, "No CPUID match found.\n"); + goto out; + } rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_power); tdp = turbo_power & TURBO_TDP_MASK; @@ -1432,6 +1434,12 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) spin_lock_init(&ips->turbo_status_lock); + ret = pci_enable_device(dev); + if (ret) { + dev_err(&dev->dev, "can't enable PCI device, aborting\n"); + goto error_free; + } + if (!pci_resource_start(dev, 0)) { dev_err(&dev->dev, "TBAR not assigned, aborting\n"); ret = -ENXIO; @@ -1444,11 +1452,6 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) goto error_free; } - ret = pci_enable_device(dev); - if (ret) { - dev_err(&dev->dev, "can't enable PCI device, aborting\n"); - goto error_free; - } ips->regmap = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index ec01c3d8fc5a..b3b9e0458ae1 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -128,6 +128,7 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> #include <linux/input.h> +#include <linux/input/sparse-keymap.h> #ifndef ACPI_HOTKEY_COMPONENT @@ -200,30 +201,29 @@ static struct acpi_driver acpi_pcc_driver = { }, }; -#define KEYMAP_SIZE 11 -static const unsigned int initial_keymap[KEYMAP_SIZE] = { - /* 0 */ KEY_RESERVED, - /* 1 */ KEY_BRIGHTNESSDOWN, - /* 2 */ KEY_BRIGHTNESSUP, - /* 3 */ KEY_DISPLAYTOGGLE, - /* 4 */ KEY_MUTE, - /* 5 */ KEY_VOLUMEDOWN, - /* 6 */ KEY_VOLUMEUP, - /* 7 */ KEY_SLEEP, - /* 8 */ KEY_PROG1, /* Change CPU boost */ - /* 9 */ KEY_BATTERY, - /* 10 */ KEY_SUSPEND, +static const struct key_entry panasonic_keymap[] = { + { KE_KEY, 0, { KEY_RESERVED } }, + { KE_KEY, 1, { KEY_BRIGHTNESSDOWN } }, + { KE_KEY, 2, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 3, { KEY_DISPLAYTOGGLE } }, + { KE_KEY, 4, { KEY_MUTE } }, + { KE_KEY, 5, { KEY_VOLUMEDOWN } }, + { KE_KEY, 6, { KEY_VOLUMEUP } }, + { KE_KEY, 7, { KEY_SLEEP } }, + { KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */ + { KE_KEY, 9, { KEY_BATTERY } }, + { KE_KEY, 10, { KEY_SUSPEND } }, + { KE_END, 0 } }; struct pcc_acpi { acpi_handle handle; unsigned long num_sifr; int sticky_mode; - u32 *sinf; + u32 *sinf; struct acpi_device *device; struct input_dev *input_dev; struct backlight_device *backlight; - unsigned int keymap[KEYMAP_SIZE]; }; struct pcc_keyinput { @@ -446,56 +446,10 @@ static struct attribute_group pcc_attr_group = { /* hotkey input device driver */ -static int pcc_getkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) -{ - struct pcc_acpi *pcc = input_get_drvdata(dev); - - if (scancode >= ARRAY_SIZE(pcc->keymap)) - return -EINVAL; - - *keycode = pcc->keymap[scancode]; - - return 0; -} - -static int keymap_get_by_keycode(struct pcc_acpi *pcc, unsigned int keycode) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) { - if (pcc->keymap[i] == keycode) - return i+1; - } - - return 0; -} - -static int pcc_setkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode) -{ - struct pcc_acpi *pcc = input_get_drvdata(dev); - int oldkeycode; - - if (scancode >= ARRAY_SIZE(pcc->keymap)) - return -EINVAL; - - oldkeycode = pcc->keymap[scancode]; - pcc->keymap[scancode] = keycode; - - set_bit(keycode, dev->keybit); - - if (!keymap_get_by_keycode(pcc, oldkeycode)) - clear_bit(oldkeycode, dev->keybit); - - return 0; -} - static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) { struct input_dev *hotk_input_dev = pcc->input_dev; int rc; - int key_code, hkey_num; unsigned long long result; rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, @@ -508,25 +462,10 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result); - hkey_num = result & 0xf; - - if (hkey_num < 0 || hkey_num >= ARRAY_SIZE(pcc->keymap)) { + if (!sparse_keymap_report_event(hotk_input_dev, + result & 0xf, result & 0x80, false)) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "hotkey number out of range: %d\n", - hkey_num)); - return; - } - - key_code = pcc->keymap[hkey_num]; - - if (key_code != KEY_RESERVED) { - int pushed = (result & 0x80) ? TRUE : FALSE; - - input_report_key(hotk_input_dev, key_code, pushed); - input_sync(hotk_input_dev); - } - - return; + "Unknown hotkey event: %d\n", result)); } static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event) @@ -545,40 +484,55 @@ static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event) static int acpi_pcc_init_input(struct pcc_acpi *pcc) { - int i, rc; + struct input_dev *input_dev; + int error; - pcc->input_dev = input_allocate_device(); - if (!pcc->input_dev) { + input_dev = input_allocate_device(); + if (!input_dev) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Couldn't allocate input device for hotkey")); return -ENOMEM; } - pcc->input_dev->evbit[0] = BIT(EV_KEY); - - pcc->input_dev->name = ACPI_PCC_DRIVER_NAME; - pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS; - pcc->input_dev->id.bustype = BUS_HOST; - pcc->input_dev->id.vendor = 0x0001; - pcc->input_dev->id.product = 0x0001; - pcc->input_dev->id.version = 0x0100; - pcc->input_dev->getkeycode = pcc_getkeycode; - pcc->input_dev->setkeycode = pcc_setkeycode; + input_dev->name = ACPI_PCC_DRIVER_NAME; + input_dev->phys = ACPI_PCC_INPUT_PHYS; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; - /* load initial keymap */ - memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap)); + error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL); + if (error) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to setup input device keymap\n")); + goto err_free_dev; + } - for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) - __set_bit(pcc->keymap[i], pcc->input_dev->keybit); - __clear_bit(KEY_RESERVED, pcc->input_dev->keybit); + error = input_register_device(input_dev); + if (error) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to register input device\n")); + goto err_free_keymap; + } - input_set_drvdata(pcc->input_dev, pcc); + pcc->input_dev = input_dev; + return 0; - rc = input_register_device(pcc->input_dev); - if (rc < 0) - input_free_device(pcc->input_dev); + err_free_keymap: + sparse_keymap_free(input_dev); + err_free_dev: + input_free_device(input_dev); + return error; +} - return rc; +static void acpi_pcc_destroy_input(struct pcc_acpi *pcc) +{ + sparse_keymap_free(pcc->input_dev); + input_unregister_device(pcc->input_dev); + /* + * No need to input_free_device() since core input API refcounts + * and free()s the device. + */ } /* kernel module interface */ @@ -636,7 +590,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error installing keyinput handler\n")); - goto out_hotkey; + goto out_sinf; } if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) { @@ -651,7 +605,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) &pcc_backlight_ops, &props); if (IS_ERR(pcc->backlight)) { result = PTR_ERR(pcc->backlight); - goto out_sinf; + goto out_input; } /* read the initial brightness setting from the hardware */ @@ -669,12 +623,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) out_backlight: backlight_device_unregister(pcc->backlight); +out_input: + acpi_pcc_destroy_input(pcc); out_sinf: kfree(pcc->sinf); -out_input: - input_unregister_device(pcc->input_dev); - /* no need to input_free_device() since core input API refcount and - * free()s the device */ out_hotkey: kfree(pcc); @@ -709,9 +661,7 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type) backlight_device_unregister(pcc->backlight); - input_unregister_device(pcc->input_dev); - /* no need to input_free_device() since core input API refcount and - * free()s the device */ + acpi_pcc_destroy_input(pcc); kfree(pcc->sinf); kfree(pcc); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 5d6119bed00c..e35ed128bdef 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1911,6 +1911,17 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, TP_ACPI_HOTKEYSCAN_MUTE, TP_ACPI_HOTKEYSCAN_THINKPAD, + TP_ACPI_HOTKEYSCAN_UNK1, + TP_ACPI_HOTKEYSCAN_UNK2, + TP_ACPI_HOTKEYSCAN_UNK3, + TP_ACPI_HOTKEYSCAN_UNK4, + TP_ACPI_HOTKEYSCAN_UNK5, + TP_ACPI_HOTKEYSCAN_UNK6, + TP_ACPI_HOTKEYSCAN_UNK7, + TP_ACPI_HOTKEYSCAN_UNK8, + + /* Hotkey keymap size */ + TPACPI_HOTKEY_MAP_LEN }; enum { /* Keys/events available through NVRAM polling */ @@ -3082,6 +3093,8 @@ static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = { TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */ }; +typedef u16 tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN]; + static int __init hotkey_init(struct ibm_init_struct *iibm) { /* Requirements for changing the default keymaps: @@ -3113,9 +3126,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * If the above is too much to ask, don't change the keymap. * Ask the thinkpad-acpi maintainer to do it, instead. */ - static u16 ibm_keycode_map[] __initdata = { + + enum keymap_index { + TPACPI_KEYMAP_IBM_GENERIC = 0, + TPACPI_KEYMAP_LENOVO_GENERIC, + }; + + static const tpacpi_keymap_t tpacpi_keymaps[] __initconst = { + /* Generic keymap for IBM ThinkPads */ + [TPACPI_KEYMAP_IBM_GENERIC] = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ - KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, + KEY_FN_F1, KEY_BATTERY, KEY_COFFEE, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, @@ -3146,11 +3167,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, - }; - static u16 lenovo_keycode_map[] __initdata = { + }, + + /* Generic keymap for Lenovo ThinkPads */ + [TPACPI_KEYMAP_LENOVO_GENERIC] = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, - KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, + KEY_WLAN, KEY_CAMERA, KEY_SWITCHVIDEOMODE, KEY_FN_F8, KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ @@ -3189,11 +3212,25 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + }, + }; + + static const struct tpacpi_quirk tpacpi_keymap_qtable[] __initconst = { + /* Generic maps (fallback) */ + { + .vendor = PCI_VENDOR_ID_IBM, + .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY, + .quirks = TPACPI_KEYMAP_IBM_GENERIC, + }, + { + .vendor = PCI_VENDOR_ID_LENOVO, + .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY, + .quirks = TPACPI_KEYMAP_LENOVO_GENERIC, + }, }; -#define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map) -#define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map) -#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0]) +#define TPACPI_HOTKEY_MAP_SIZE sizeof(tpacpi_keymap_t) +#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(tpacpi_keymap_t[0]) int res, i; int status; @@ -3202,6 +3239,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) bool tabletsw_state = false; unsigned long quirks; + unsigned long keymap_id; vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "initializing hotkey subdriver\n"); @@ -3342,7 +3380,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) goto err_exit; /* Set up key map */ - hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, GFP_KERNEL); if (!hotkey_keycode_map) { @@ -3352,17 +3389,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) goto err_exit; } - if (tpacpi_is_lenovo()) { - dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "using Lenovo default hot key map\n"); - memcpy(hotkey_keycode_map, &lenovo_keycode_map, - TPACPI_HOTKEY_MAP_SIZE); - } else { - dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "using IBM default hot key map\n"); - memcpy(hotkey_keycode_map, &ibm_keycode_map, - TPACPI_HOTKEY_MAP_SIZE); - } + keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, + ARRAY_SIZE(tpacpi_keymap_qtable)); + BUG_ON(keymap_id >= ARRAY_SIZE(tpacpi_keymaps)); + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "using keymap number %lu\n", keymap_id); + + memcpy(hotkey_keycode_map, &tpacpi_keymaps[keymap_id], + TPACPI_HOTKEY_MAP_SIZE); input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN); tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; @@ -3469,7 +3503,8 @@ static bool hotkey_notify_hotkey(const u32 hkey, *send_acpi_ev = true; *ignore_acpi_ev = false; - if (scancode > 0 && scancode < 0x21) { + /* HKEY event 0x1001 is scancode 0x00 */ + if (scancode > 0 && scancode <= TPACPI_HOTKEY_MAP_LEN) { scancode--; if (!(hotkey_source_mask & (1 << scancode))) { tpacpi_input_send_key_masked(scancode); @@ -6080,13 +6115,18 @@ static struct backlight_ops ibm_backlight_data = { /* --------------------------------------------------------------------- */ +/* + * Call _BCL method of video device. On some ThinkPads this will + * switch the firmware to the ACPI brightness control mode. + */ + static int __init tpacpi_query_bcl_levels(acpi_handle handle) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; int rc; - if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { + if (ACPI_SUCCESS(acpi_evaluate_object(handle, "_BCL", NULL, &buffer))) { obj = (union acpi_object *)buffer.pointer; if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { printk(TPACPI_ERR "Unknown _BCL data, " @@ -6103,55 +6143,22 @@ static int __init tpacpi_query_bcl_levels(acpi_handle handle) return rc; } -static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, - u32 lvl, void *context, void **rv) -{ - char name[ACPI_PATH_SEGMENT_LENGTH]; - struct acpi_buffer buffer = { sizeof(name), &name }; - - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && - !strncmp("_BCL", name, sizeof(name) - 1)) { - BUG_ON(!rv || !*rv); - **(int **)rv = tpacpi_query_bcl_levels(handle); - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} /* * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map */ static unsigned int __init tpacpi_check_std_acpi_brightness_support(void) { - int status; + acpi_handle video_device; int bcl_levels = 0; - void *bcl_ptr = &bcl_levels; - - if (!vid_handle) - TPACPI_ACPIHANDLE_INIT(vid); - - if (!vid_handle) - return 0; - - /* - * Search for a _BCL method, and execute it. This is safe on all - * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista - * BIOS in ACPI backlight control mode. We do NOT have to care - * about calling the _BCL method in an enabled video device, any - * will do for our purposes. - */ - status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, - tpacpi_acpi_walk_find_bcl, NULL, NULL, - &bcl_ptr); + tpacpi_acpi_handle_locate("video", ACPI_VIDEO_HID, &video_device); + if (video_device) + bcl_levels = tpacpi_query_bcl_levels(video_device); - if (ACPI_SUCCESS(status) && bcl_levels > 2) { - tp_features.bright_acpimode = 1; - return bcl_levels - 2; - } + tp_features.bright_acpimode = (bcl_levels > 0); - return 0; + return (bcl_levels > 2) ? (bcl_levels - 2) : 0; } /* @@ -6244,28 +6251,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (tp_features.bright_unkfw) return 1; - if (tp_features.bright_acpimode) { - if (acpi_video_backlight_support()) { - if (brightness_enable > 1) { - printk(TPACPI_NOTICE - "Standard ACPI backlight interface " - "available, not loading native one.\n"); - return 1; - } else if (brightness_enable == 1) { - printk(TPACPI_NOTICE - "Backlight control force enabled, even if standard " - "ACPI backlight interface is available\n"); - } - } else { - if (brightness_enable > 1) { - printk(TPACPI_NOTICE - "Standard ACPI backlight interface not " - "available, thinkpad_acpi native " - "brightness control enabled\n"); - } - } - } - if (!brightness_enable) { dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, "brightness support disabled by " @@ -6273,6 +6258,26 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return 1; } + if (acpi_video_backlight_support()) { + if (brightness_enable > 1) { + printk(TPACPI_INFO + "Standard ACPI backlight interface " + "available, not loading native one.\n"); + return 1; + } else if (brightness_enable == 1) { + printk(TPACPI_WARN + "Cannot enable backlight brightness support, " + "ACPI is already handling it. Refer to the " + "acpi_backlight kernel parameter\n"); + return 1; + } + } else if (tp_features.bright_acpimode && brightness_enable > 1) { + printk(TPACPI_NOTICE + "Standard ACPI backlight interface not " + "available, thinkpad_acpi native " + "brightness control enabled\n"); + } + /* * Check for module parameter bogosity, note that we * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c index ff4b476f1950..1d07d6d09f27 100644 --- a/drivers/platform/x86/topstar-laptop.c +++ b/drivers/platform/x86/topstar-laptop.c @@ -19,6 +19,7 @@ #include <linux/slab.h> #include <linux/acpi.h> #include <linux/input.h> +#include <linux/input/sparse-keymap.h> #define ACPI_TOPSTAR_CLASS "topstar" @@ -26,52 +27,37 @@ struct topstar_hkey { struct input_dev *inputdev; }; -struct tps_key_entry { - u8 code; - u16 keycode; -}; - -static struct tps_key_entry topstar_keymap[] = { - { 0x80, KEY_BRIGHTNESSUP }, - { 0x81, KEY_BRIGHTNESSDOWN }, - { 0x83, KEY_VOLUMEUP }, - { 0x84, KEY_VOLUMEDOWN }, - { 0x85, KEY_MUTE }, - { 0x86, KEY_SWITCHVIDEOMODE }, - { 0x87, KEY_F13 }, /* touchpad enable/disable key */ - { 0x88, KEY_WLAN }, - { 0x8a, KEY_WWW }, - { 0x8b, KEY_MAIL }, - { 0x8c, KEY_MEDIA }, - { 0x96, KEY_F14 }, /* G key? */ - { } -}; - -static struct tps_key_entry *tps_get_key_by_scancode(unsigned int code) -{ - struct tps_key_entry *key; - - for (key = topstar_keymap; key->code; key++) - if (code == key->code) - return key; +static const struct key_entry topstar_keymap[] = { + { KE_KEY, 0x80, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 0x81, { KEY_BRIGHTNESSDOWN } }, + { KE_KEY, 0x83, { KEY_VOLUMEUP } }, + { KE_KEY, 0x84, { KEY_VOLUMEDOWN } }, + { KE_KEY, 0x85, { KEY_MUTE } }, + { KE_KEY, 0x86, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x87, { KEY_F13 } }, /* touchpad enable/disable key */ + { KE_KEY, 0x88, { KEY_WLAN } }, + { KE_KEY, 0x8a, { KEY_WWW } }, + { KE_KEY, 0x8b, { KEY_MAIL } }, + { KE_KEY, 0x8c, { KEY_MEDIA } }, - return NULL; -} - -static struct tps_key_entry *tps_get_key_by_keycode(unsigned int code) -{ - struct tps_key_entry *key; + /* Known non hotkey events don't handled or that we don't care yet */ + { KE_IGNORE, 0x8e, }, + { KE_IGNORE, 0x8f, }, + { KE_IGNORE, 0x90, }, - for (key = topstar_keymap; key->code; key++) - if (code == key->keycode) - return key; + /* + * 'G key' generate two event codes, convert to only + * one event/key code for now, consider replacing by + * a switch (3G switch - SW_3G?) + */ + { KE_KEY, 0x96, { KEY_F14 } }, + { KE_KEY, 0x97, { KEY_F14 } }, - return NULL; -} + { KE_END, 0 } +}; static void acpi_topstar_notify(struct acpi_device *device, u32 event) { - struct tps_key_entry *key; static bool dup_evnt[2]; bool *dup; struct topstar_hkey *hkey = acpi_driver_data(device); @@ -86,27 +72,8 @@ static void acpi_topstar_notify(struct acpi_device *device, u32 event) *dup = true; } - /* - * 'G key' generate two event codes, convert to only - * one event/key code for now (3G switch?) - */ - if (event == 0x97) - event = 0x96; - - key = tps_get_key_by_scancode(event); - if (key) { - input_report_key(hkey->inputdev, key->keycode, 1); - input_sync(hkey->inputdev); - input_report_key(hkey->inputdev, key->keycode, 0); - input_sync(hkey->inputdev); - return; - } - - /* Known non hotkey events don't handled or that we don't care yet */ - if (event == 0x8e || event == 0x8f || event == 0x90) - return; - - pr_info("unknown event = 0x%02x\n", event); + if (!sparse_keymap_report_event(hkey->inputdev, event, 1, true)) + pr_info("unknown event = 0x%02x\n", event); } static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state) @@ -127,62 +94,41 @@ static int acpi_topstar_fncx_switch(struct acpi_device *device, bool state) return 0; } -static int topstar_getkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) -{ - struct tps_key_entry *key = tps_get_key_by_scancode(scancode); - - if (!key) - return -EINVAL; - - *keycode = key->keycode; - return 0; -} - -static int topstar_setkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode) -{ - struct tps_key_entry *key; - int old_keycode; - - key = tps_get_key_by_scancode(scancode); - - if (!key) - return -EINVAL; - - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!tps_get_key_by_keycode(old_keycode)) - clear_bit(old_keycode, dev->keybit); - return 0; -} - static int acpi_topstar_init_hkey(struct topstar_hkey *hkey) { - struct tps_key_entry *key; + struct input_dev *input; + int error; - hkey->inputdev = input_allocate_device(); - if (!hkey->inputdev) { + input = input_allocate_device(); + if (!input) { pr_err("Unable to allocate input device\n"); - return -ENODEV; + return -ENOMEM; } - hkey->inputdev->name = "Topstar Laptop extra buttons"; - hkey->inputdev->phys = "topstar/input0"; - hkey->inputdev->id.bustype = BUS_HOST; - hkey->inputdev->getkeycode = topstar_getkeycode; - hkey->inputdev->setkeycode = topstar_setkeycode; - for (key = topstar_keymap; key->code; key++) { - set_bit(EV_KEY, hkey->inputdev->evbit); - set_bit(key->keycode, hkey->inputdev->keybit); + + input->name = "Topstar Laptop extra buttons"; + input->phys = "topstar/input0"; + input->id.bustype = BUS_HOST; + + error = sparse_keymap_setup(input, topstar_keymap, NULL); + if (error) { + pr_err("Unable to setup input device keymap\n"); + goto err_free_dev; } - if (input_register_device(hkey->inputdev)) { + + error = input_register_device(input); + if (error) { pr_err("Unable to register input device\n"); - input_free_device(hkey->inputdev); - return -ENODEV; + goto err_free_keymap; } + hkey->inputdev = input; return 0; + + err_free_keymap: + sparse_keymap_free(input); + err_free_dev: + input_free_device(input); + return error; } static int acpi_topstar_add(struct acpi_device *device) @@ -216,6 +162,7 @@ static int acpi_topstar_remove(struct acpi_device *device, int type) acpi_topstar_fncx_switch(device, false); + sparse_keymap_free(tps_hkey->inputdev); input_unregister_device(tps_hkey->inputdev); kfree(tps_hkey); diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 7d67a45bb2b0..06f304f46e02 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -48,6 +48,7 @@ #include <linux/platform_device.h> #include <linux/rfkill.h> #include <linux/input.h> +#include <linux/input/sparse-keymap.h> #include <linux/leds.h> #include <linux/slab.h> @@ -121,36 +122,28 @@ static const struct acpi_device_id toshiba_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); -struct key_entry { - char type; - u16 code; - u16 keycode; -}; - -enum {KE_KEY, KE_END}; - -static struct key_entry toshiba_acpi_keymap[] = { - {KE_KEY, 0x101, KEY_MUTE}, - {KE_KEY, 0x102, KEY_ZOOMOUT}, - {KE_KEY, 0x103, KEY_ZOOMIN}, - {KE_KEY, 0x13b, KEY_COFFEE}, - {KE_KEY, 0x13c, KEY_BATTERY}, - {KE_KEY, 0x13d, KEY_SLEEP}, - {KE_KEY, 0x13e, KEY_SUSPEND}, - {KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE}, - {KE_KEY, 0x140, KEY_BRIGHTNESSDOWN}, - {KE_KEY, 0x141, KEY_BRIGHTNESSUP}, - {KE_KEY, 0x142, KEY_WLAN}, - {KE_KEY, 0x143, KEY_PROG1}, - {KE_KEY, 0xb05, KEY_PROG2}, - {KE_KEY, 0xb06, KEY_WWW}, - {KE_KEY, 0xb07, KEY_MAIL}, - {KE_KEY, 0xb30, KEY_STOP}, - {KE_KEY, 0xb31, KEY_PREVIOUSSONG}, - {KE_KEY, 0xb32, KEY_NEXTSONG}, - {KE_KEY, 0xb33, KEY_PLAYPAUSE}, - {KE_KEY, 0xb5a, KEY_MEDIA}, - {KE_END, 0, 0}, +static const struct key_entry toshiba_acpi_keymap[] __initconst = { + { KE_KEY, 0x101, { KEY_MUTE } }, + { KE_KEY, 0x102, { KEY_ZOOMOUT } }, + { KE_KEY, 0x103, { KEY_ZOOMIN } }, + { KE_KEY, 0x13b, { KEY_COFFEE } }, + { KE_KEY, 0x13c, { KEY_BATTERY } }, + { KE_KEY, 0x13d, { KEY_SLEEP } }, + { KE_KEY, 0x13e, { KEY_SUSPEND } }, + { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, + { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 0x142, { KEY_WLAN } }, + { KE_KEY, 0x143, { KEY_PROG1 } }, + { KE_KEY, 0xb05, { KEY_PROG2 } }, + { KE_KEY, 0xb06, { KEY_WWW } }, + { KE_KEY, 0xb07, { KEY_MAIL } }, + { KE_KEY, 0xb30, { KEY_STOP } }, + { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, + { KE_KEY, 0xb32, { KEY_NEXTSONG } }, + { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, + { KE_KEY, 0xb5a, { KEY_MEDIA } }, + { KE_END, 0 }, }; /* utility @@ -852,64 +845,9 @@ static struct backlight_ops toshiba_backlight_data = { .update_status = set_lcd_status, }; -static struct key_entry *toshiba_acpi_get_entry_by_scancode(unsigned int code) -{ - struct key_entry *key; - - for (key = toshiba_acpi_keymap; key->type != KE_END; key++) - if (code == key->code) - return key; - - return NULL; -} - -static struct key_entry *toshiba_acpi_get_entry_by_keycode(unsigned int code) -{ - struct key_entry *key; - - for (key = toshiba_acpi_keymap; key->type != KE_END; key++) - if (code == key->keycode && key->type == KE_KEY) - return key; - - return NULL; -} - -static int toshiba_acpi_getkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) -{ - struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode); - - if (key && key->type == KE_KEY) { - *keycode = key->keycode; - return 0; - } - - return -EINVAL; -} - -static int toshiba_acpi_setkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode) -{ - struct key_entry *key; - unsigned int old_keycode; - - key = toshiba_acpi_get_entry_by_scancode(scancode); - if (key && key->type == KE_KEY) { - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!toshiba_acpi_get_entry_by_keycode(old_keycode)) - clear_bit(old_keycode, dev->keybit); - return 0; - } - - return -EINVAL; -} - static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context) { u32 hci_result, value; - struct key_entry *key; if (event != 0x80) return; @@ -922,19 +860,11 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context) if (value & 0x80) continue; - key = toshiba_acpi_get_entry_by_scancode - (value); - if (!key) { + if (!sparse_keymap_report_event(toshiba_acpi.hotkey_dev, + value, 1, true)) { printk(MY_INFO "Unknown key %x\n", value); - continue; } - input_report_key(toshiba_acpi.hotkey_dev, - key->keycode, 1); - input_sync(toshiba_acpi.hotkey_dev); - input_report_key(toshiba_acpi.hotkey_dev, - key->keycode, 0); - input_sync(toshiba_acpi.hotkey_dev); } else if (hci_result == HCI_NOT_SUPPORTED) { /* This is a workaround for an unresolved issue on * some machines where system events sporadically @@ -945,34 +875,17 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context) } while (hci_result != HCI_EMPTY); } -static int toshiba_acpi_setup_keyboard(char *device) +static int __init toshiba_acpi_setup_keyboard(char *device) { acpi_status status; - acpi_handle handle; - int result; - const struct key_entry *key; + int error; - status = acpi_get_handle(NULL, device, &handle); + status = acpi_get_handle(NULL, device, &toshiba_acpi.handle); if (ACPI_FAILURE(status)) { printk(MY_INFO "Unable to get notification device\n"); return -ENODEV; } - toshiba_acpi.handle = handle; - - status = acpi_evaluate_object(handle, "ENAB", NULL, NULL); - if (ACPI_FAILURE(status)) { - printk(MY_INFO "Unable to enable hotkeys\n"); - return -ENODEV; - } - - status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY, - toshiba_acpi_notify, NULL); - if (ACPI_FAILURE(status)) { - printk(MY_INFO "Unable to install hotkey notification\n"); - return -ENODEV; - } - toshiba_acpi.hotkey_dev = input_allocate_device(); if (!toshiba_acpi.hotkey_dev) { printk(MY_INFO "Unable to register input device\n"); @@ -982,27 +895,54 @@ static int toshiba_acpi_setup_keyboard(char *device) toshiba_acpi.hotkey_dev->name = "Toshiba input device"; toshiba_acpi.hotkey_dev->phys = device; toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST; - toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode; - toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode; - for (key = toshiba_acpi_keymap; key->type != KE_END; key++) { - set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit); - set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit); + error = sparse_keymap_setup(toshiba_acpi.hotkey_dev, + toshiba_acpi_keymap, NULL); + if (error) + goto err_free_dev; + + status = acpi_install_notify_handler(toshiba_acpi.handle, + ACPI_DEVICE_NOTIFY, toshiba_acpi_notify, NULL); + if (ACPI_FAILURE(status)) { + printk(MY_INFO "Unable to install hotkey notification\n"); + error = -ENODEV; + goto err_free_keymap; + } + + status = acpi_evaluate_object(toshiba_acpi.handle, "ENAB", NULL, NULL); + if (ACPI_FAILURE(status)) { + printk(MY_INFO "Unable to enable hotkeys\n"); + error = -ENODEV; + goto err_remove_notify; } - result = input_register_device(toshiba_acpi.hotkey_dev); - if (result) { + error = input_register_device(toshiba_acpi.hotkey_dev); + if (error) { printk(MY_INFO "Unable to register input device\n"); - return result; + goto err_remove_notify; } return 0; + + err_remove_notify: + acpi_remove_notify_handler(toshiba_acpi.handle, + ACPI_DEVICE_NOTIFY, toshiba_acpi_notify); + err_free_keymap: + sparse_keymap_free(toshiba_acpi.hotkey_dev); + err_free_dev: + input_free_device(toshiba_acpi.hotkey_dev); + toshiba_acpi.hotkey_dev = NULL; + return error; } static void toshiba_acpi_exit(void) { - if (toshiba_acpi.hotkey_dev) + if (toshiba_acpi.hotkey_dev) { + acpi_remove_notify_handler(toshiba_acpi.handle, + ACPI_DEVICE_NOTIFY, toshiba_acpi_notify); + sparse_keymap_free(toshiba_acpi.hotkey_dev); input_unregister_device(toshiba_acpi.hotkey_dev); + } if (toshiba_acpi.bt_rfk) { rfkill_unregister(toshiba_acpi.bt_rfk); @@ -1017,9 +957,6 @@ static void toshiba_acpi_exit(void) if (toshiba_proc_dir) remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); - acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY, - toshiba_acpi_notify); - if (toshiba_acpi.illumination_installed) led_classdev_unregister(&toshiba_led); |