From b964b437601a0e7d09896d5d9a85c83643e94f41 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:26 -0300 Subject: ACPI: thinkpad-acpi: add DMI-based modalias Add DMI-based aliases to allow module autoloading on select thinkpads. The aliases will do nothing unless the dmi-based-module-autoloading.patch patch from Lennart Poettering is applied. Lennart's patch has been accepted by greghk and will be merged eventually. Signed-off-by: Henrique de Moraes Holschuh Cc: Lennart Poettering Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 95c0b96e83f2..22a5f228b55a 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -92,6 +92,29 @@ MODULE_LICENSE("GPL"); /* Please remove this in year 2009 */ MODULE_ALIAS("ibm_acpi"); +/* + * DMI matching for module autoloading + * + * See http://thinkwiki.org/wiki/List_of_DMI_IDs + * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads + * + * Only models listed in thinkwiki will be supported, so add yours + * if it is not there yet. + */ +#define IBM_BIOS_MODULE_ALIAS(__type) \ + MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") + +/* Non-ancient thinkpads */ +MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); +MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); + +/* Ancient thinkpad BIOSes have to be identified by + * BIOS type or model number, and there are far less + * BIOS types than model numbers... */ +IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); +IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); +IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); + #define __unused __attribute__ ((unused)) /**************************************************************************** -- cgit v1.2.3 From 94954cc60194796fb257802f6f65d79553c9a8ca Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:27 -0300 Subject: ACPI: thinkpad-acpi: remove all uneeded initializers Remove all initializers to NULL or zero. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 22a5f228b55a..9f10b4694eda 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -129,7 +129,7 @@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); * ACPI basic handles */ -static acpi_handle root_handle = NULL; +static acpi_handle root_handle; #define IBM_HANDLE(object, parent, paths...) \ static acpi_handle object##_handle; \ @@ -515,8 +515,8 @@ static char *next_cmd(char **cmds) **************************************************************************** ****************************************************************************/ -static struct platform_device *tpacpi_pdev = NULL; -static struct class_device *tpacpi_hwmon = NULL; +static struct platform_device *tpacpi_pdev; +static struct class_device *tpacpi_hwmon; static struct platform_driver tpacpi_pdriver = { .driver = { @@ -729,7 +729,7 @@ static struct ibm_struct thinkpad_acpi_driver_data = { static int hotkey_orig_status; static int hotkey_orig_mask; -static struct attribute_set *hotkey_dev_attributes = NULL; +static struct attribute_set *hotkey_dev_attributes; /* sysfs hotkey enable ------------------------------------------------- */ static ssize_t hotkey_enable_show(struct device *dev, @@ -2694,7 +2694,7 @@ static struct ibm_struct ecdump_driver_data = { * Backlight/brightness subdriver */ -static struct backlight_device *ibm_backlight_device = NULL; +static struct backlight_device *ibm_backlight_device; static struct backlight_ops ibm_backlight_data = { .get_brightness = brightness_get, @@ -3497,7 +3497,7 @@ static void fan_watchdog_fire(struct work_struct *ignored) static void fan_watchdog_reset(void) { - static int fan_watchdog_active = 0; + static int fan_watchdog_active; if (fan_control_access_mode == TPACPI_FAN_WR_NONE) return; @@ -3900,7 +3900,7 @@ static struct ibm_struct fan_driver_data = { ****************************************************************************/ /* /proc support */ -static struct proc_dir_entry *proc_dir = NULL; +static struct proc_dir_entry *proc_dir; /* Subdriver registry */ static LIST_HEAD(tpacpi_all_drivers); @@ -4043,7 +4043,7 @@ static void ibm_exit(struct ibm_struct *ibm) /* Probing */ -static char *ibm_thinkpad_ec_found = NULL; +static char *ibm_thinkpad_ec_found; static char* __init check_dmi_for_ec(void) { -- cgit v1.2.3 From ae92bd17ff703b3703562148c73b4d6833e6a326 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:29 -0300 Subject: ACPI: thinkpad-acpi: enable more hotkeys Revise ACPI HKEY functionality to better interface with the firmware, and enable up to 32 regular hotkeys, instead of just 16 of them. Ouch. This takes care of most keys one used to have to do CMOS NVRAM polling on, and should drop the need for tpb, thinkpad-keys, and other such 5Hz NVRAM polling power vampires on most modern ThinkPads ;-) And, just to add insult to injury, this was sort of working since forever through the procfs interface, but nobody noticed or tried an echo 0xffffffff > /proc/acpi/ibm/hotkey and told me it would generate weird events. ARGH! Thanks to Richard Hughes for kicking off the work that ended up with this discovery, and to Matthew Garret for calling my attention to the fact that newer ThinkPads were indeed generating ACPI GPEs when such hot keys were pressed. Signed-off-by: Henrique de Moraes Holschuh Cc: Richard Hughes Cc: Matthew Garrett Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 9f10b4694eda..450b1e5cd681 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -727,7 +727,7 @@ static struct ibm_struct thinkpad_acpi_driver_data = { */ static int hotkey_orig_status; -static int hotkey_orig_mask; +static u32 hotkey_orig_mask; static struct attribute_set *hotkey_dev_attributes; @@ -736,7 +736,8 @@ static ssize_t hotkey_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { - int res, status, mask; + int res, status; + u32 mask; res = hotkey_get(&status, &mask); if (res) @@ -750,7 +751,8 @@ static ssize_t hotkey_enable_store(struct device *dev, const char *buf, size_t count) { unsigned long t; - int res, status, mask; + int res, status; + u32 mask; if (parse_strtoul(buf, 1, &t)) return -EINVAL; @@ -771,13 +773,14 @@ static ssize_t hotkey_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - int res, status, mask; + int res, status; + u32 mask; res = hotkey_get(&status, &mask); if (res) return res; - return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask); + return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask); } static ssize_t hotkey_mask_store(struct device *dev, @@ -785,9 +788,10 @@ static ssize_t hotkey_mask_store(struct device *dev, const char *buf, size_t count) { unsigned long t; - int res, status, mask; + int res, status; + u32 mask; - if (parse_strtoul(buf, 0xffff, &t)) + if (parse_strtoul(buf, 0xffffffffUL, &t)) return -EINVAL; res = hotkey_get(&status, &mask); @@ -817,7 +821,7 @@ static ssize_t hotkey_bios_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask); + return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); } static struct device_attribute dev_attr_hotkey_bios_mask = @@ -902,10 +906,10 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) { int hkey; - if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) + if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { acpi_bus_generate_event(ibm->acpi->device, event, hkey); - else { - printk(IBM_ERR "unknown hotkey event %d\n", event); + } else { + printk(IBM_ERR "unknown hotkey notification event %d\n", event); acpi_bus_generate_event(ibm->acpi->device, event, 0); } } @@ -913,7 +917,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) /* * Call with hotkey_mutex held */ -static int hotkey_get(int *status, int *mask) +static int hotkey_get(int *status, u32 *mask) { if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) return -EIO; @@ -928,7 +932,7 @@ static int hotkey_get(int *status, int *mask) /* * Call with hotkey_mutex held */ -static int hotkey_set(int status, int mask) +static int hotkey_set(int status, u32 mask) { int i; @@ -949,7 +953,8 @@ static int hotkey_set(int status, int mask) /* procfs -------------------------------------------------------------- */ static int hotkey_read(char *p) { - int res, status, mask; + int res, status; + u32 mask; int len = 0; if (!tp_features.hotkey) { @@ -967,7 +972,7 @@ static int hotkey_read(char *p) len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); if (tp_features.hotkey_mask) { - len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); + len += sprintf(p + len, "mask:\t\t0x%08x\n", mask); len += sprintf(p + len, "commands:\tenable, disable, reset, \n"); } else { @@ -980,7 +985,8 @@ static int hotkey_read(char *p) static int hotkey_write(char *buf) { - int res, status, mask; + int res, status; + u32 mask; char *cmd; int do_cmd = 0; -- cgit v1.2.3 From 9b010de59cb6dcab7e167dd2a0fa5d3b31447fea Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:30 -0300 Subject: ACPI: thinkpad-acpi: export hotkey maximum masks The firmware knows how many hot keys it supports, so export this information in a sysfs attribute. And the driver knows which keys are always handled by the firmware in all known ThinkPad models too, so export this information as well in a sysfs attribute. Unless you know which events need to be handled in a passive way, do *not* enable hotkeys that are always handled by the firmware. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 450b1e5cd681..8c088687e954 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -728,6 +728,8 @@ static struct ibm_struct thinkpad_acpi_driver_data = { static int hotkey_orig_status; static u32 hotkey_orig_mask; +static u32 hotkey_all_mask; +static u32 hotkey_reserved_mask = 0x00778000; static struct attribute_set *hotkey_dev_attributes; @@ -827,12 +829,38 @@ static ssize_t hotkey_bios_mask_show(struct device *dev, static struct device_attribute dev_attr_hotkey_bios_mask = __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); +/* sysfs hotkey all_mask ----------------------------------------------- */ +static ssize_t hotkey_all_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask); +} + +static struct device_attribute dev_attr_hotkey_all_mask = + __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL); + +/* sysfs hotkey recommended_mask --------------------------------------- */ +static ssize_t hotkey_recommended_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%08x\n", + hotkey_all_mask & ~hotkey_reserved_mask); +} + +static struct device_attribute dev_attr_hotkey_recommended_mask = + __ATTR(hotkey_recommended_mask, S_IRUGO, + hotkey_recommended_mask_show, NULL); + /* --------------------------------------------------------------------- */ static struct attribute *hotkey_mask_attributes[] = { &dev_attr_hotkey_mask.attr, &dev_attr_hotkey_bios_enabled.attr, &dev_attr_hotkey_bios_mask.attr, + &dev_attr_hotkey_all_mask.attr, + &dev_attr_hotkey_recommended_mask.attr, }; static int __init hotkey_init(struct ibm_init_struct *iibm) @@ -851,7 +879,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) str_supported(tp_features.hotkey)); if (tp_features.hotkey) { - hotkey_dev_attributes = create_attr_set(4, NULL); + hotkey_dev_attributes = create_attr_set(6, NULL); if (!hotkey_dev_attributes) return -ENOMEM; res = add_to_attr_set(hotkey_dev_attributes, @@ -867,6 +895,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", str_supported(tp_features.hotkey_mask)); + if (tp_features.hotkey_mask) { + /* MHKA available in A31, R40, R40e, T4x, X31, and later */ + if (!acpi_evalf(hkey_handle, &hotkey_all_mask, + "MHKA", "qd")) + hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ + } + res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); if (!res && tp_features.hotkey_mask) { res = add_many_to_attr_set(hotkey_dev_attributes, -- cgit v1.2.3 From 74941a69afcc06722685d492784414ec042ab492 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:31 -0300 Subject: ACPI: thinkpad-acpi: export to sysfs the state of the radio slider switch Some ThinkPad models, notably the T60 and X60, have a slider switch to enable and disable the radios. The switch has the capability of force-disabling the radios in hardware on most models, and it is supposed to affect all radios (WLAN, WWAN, BlueTooth). Export the switch state as a sysfs attribute, on ThinkPads where it is available. Thanks to Henning Schild for asking for this feature, and for tracking down the EC register that holds the radio switch state. Signed-off-by: Henrique de Moraes Holschuh Cc: Henning Schild Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 8c088687e954..3cf37bb55e9a 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -733,6 +733,13 @@ static u32 hotkey_reserved_mask = 0x00778000; static struct attribute_set *hotkey_dev_attributes; +static int hotkey_get_wlsw(int *status) +{ + if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) + return -EIO; + return 0; +} + /* sysfs hotkey enable ------------------------------------------------- */ static ssize_t hotkey_enable_show(struct device *dev, struct device_attribute *attr, @@ -853,6 +860,22 @@ static struct device_attribute dev_attr_hotkey_recommended_mask = __ATTR(hotkey_recommended_mask, S_IRUGO, hotkey_recommended_mask_show, NULL); +/* sysfs hotkey radio_sw ----------------------------------------------- */ +static ssize_t hotkey_radio_sw_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int res, s; + res = hotkey_get_wlsw(&s); + if (res < 0) + return res; + + return snprintf(buf, PAGE_SIZE, "%d\n", !!s); +} + +static struct device_attribute dev_attr_hotkey_radio_sw = + __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); + /* --------------------------------------------------------------------- */ static struct attribute *hotkey_mask_attributes[] = { @@ -866,6 +889,7 @@ static struct attribute *hotkey_mask_attributes[] = { static int __init hotkey_init(struct ibm_init_struct *iibm) { int res; + int status; vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); @@ -879,7 +903,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) str_supported(tp_features.hotkey)); if (tp_features.hotkey) { - hotkey_dev_attributes = create_attr_set(6, NULL); + hotkey_dev_attributes = create_attr_set(7, NULL); if (!hotkey_dev_attributes) return -ENOMEM; res = add_to_attr_set(hotkey_dev_attributes, @@ -908,11 +932,21 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) hotkey_mask_attributes, ARRAY_SIZE(hotkey_mask_attributes)); } + + /* Not all thinkpads have a hardware radio switch */ + if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { + tp_features.hotkey_wlsw = 1; + printk(IBM_INFO + "radio switch found; radios are %s\n", + enabled(status, 0)); + res = add_to_attr_set(hotkey_dev_attributes, + &dev_attr_hotkey_radio_sw.attr); + } + if (!res) res = register_attr_set_with_sysfs( hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); - if (res) return res; } -- cgit v1.2.3 From 94b08713186cc47a5c367a866cc0a0a762721455 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:32 -0300 Subject: ACPI: thinkpad-acpi: checkpoint sysfs interface version due to hotkey The change in the size of the hotkey mask, the hability to report the keys that use the higher bits, and the addition of the hotkey_radio_sw attribute are important enough features to warrant increasing the minor field of the sysfs interface version. Also, document a bit better how and when the thinkpad-acpi sysfs interface version will be updated. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 3cf37bb55e9a..4d7189330ec1 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -22,7 +22,7 @@ */ #define IBM_VERSION "0.14" -#define TPACPI_SYSFS_VERSION 0x000100 +#define TPACPI_SYSFS_VERSION 0x000200 /* * Changelog: -- cgit v1.2.3 From 7f5d1cd6287b7b29d210f85e2343207ac4310da2 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:34 -0300 Subject: ACPI: thinkpad-acpi: register input device Register an input device to send input events to userspace. This patch is based on a patch by Richard Hughes . Signed-off-by: Henrique de Moraes Holschuh Cc: Richard Hughes Cc: Dmitry Torokhov Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 4d7189330ec1..4427c994bc7d 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -510,13 +510,14 @@ static char *next_cmd(char **cmds) /**************************************************************************** **************************************************************************** * - * Device model: hwmon and platform + * Device model: input, hwmon and platform * **************************************************************************** ****************************************************************************/ static struct platform_device *tpacpi_pdev; static struct class_device *tpacpi_hwmon; +static struct input_dev *tpacpi_inputdev; static struct platform_driver tpacpi_pdriver = { .driver = { @@ -4363,6 +4364,20 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } + tpacpi_inputdev = input_allocate_device(); + if (!tpacpi_inputdev) { + printk(IBM_ERR "unable to allocate input device\n"); + thinkpad_acpi_module_exit(); + return -ENOMEM; + } else { + /* Prepare input device, but don't register */ + tpacpi_inputdev->name = "ThinkPad Extra Buttons"; + tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0"; + tpacpi_inputdev->id.bustype = BUS_HOST; + tpacpi_inputdev->id.vendor = TPACPI_HKEY_INPUT_VENDOR; + tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; + tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; + } for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { ret = ibm_init(&ibms_init[i]); if (ret >= 0 && *ibms_init[i].param) @@ -4372,6 +4387,14 @@ static int __init thinkpad_acpi_module_init(void) return ret; } } + ret = input_register_device(tpacpi_inputdev); + if (ret < 0) { + printk(IBM_ERR "unable to register input device\n"); + thinkpad_acpi_module_exit(); + return ret; + } else { + tp_features.input_device_registered = 1; + } return 0; } @@ -4388,6 +4411,13 @@ static void thinkpad_acpi_module_exit(void) dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); + if (tpacpi_inputdev) { + if (tp_features.input_device_registered) + input_unregister_device(tpacpi_inputdev); + else + input_free_device(tpacpi_inputdev); + } + if (tpacpi_hwmon) hwmon_device_unregister(tpacpi_hwmon); -- cgit v1.2.3 From 6a38abbf2b68e37493f2d5e8702b895a6c23ba0f Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:35 -0300 Subject: ACPI: thinkpad-acpi: add input device support to hotkey subdriver Add input device support to the hotkey subdriver. Hot keys that have a valid keycode mapping are reported through the input layer if the input device is open. Otherwise, they will be reported as ACPI events, as they were before. Scan codes are reported (using EV_MSC MSC_SCAN events) along with EV_KEY KEY_UNKNOWN events. For backwards compatibility purposes, hot keys that used to be reported through ACPI events are not mapped to anything meaningful by default. Userspace is supposed to remap them if it wants to use the input device for hot key reporting. This patch is based on a patch by Richard Hughes . Signed-off-by: Henrique de Moraes Holschuh Cc: Richard Hughes Cc: Dmitry Torokhov Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 108 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 4 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 4427c994bc7d..5c1bea1a6c37 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -730,7 +730,31 @@ static struct ibm_struct thinkpad_acpi_driver_data = { static int hotkey_orig_status; static u32 hotkey_orig_mask; static u32 hotkey_all_mask; -static u32 hotkey_reserved_mask = 0x00778000; +static u32 hotkey_reserved_mask; + +static u16 hotkey_keycode_map[] = { + /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ + KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ + KEY_UNKNOWN, /* 0x0D: FN+INSERT */ + KEY_UNKNOWN, /* 0x0E: FN+DELETE */ + KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ + /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ + KEY_RESERVED, /* 0x10: FN+END (brightness down) */ + KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ + KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ + KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ + KEY_RESERVED, /* 0x14: VOLUME UP */ + KEY_RESERVED, /* 0x15: VOLUME DOWN */ + KEY_RESERVED, /* 0x16: MUTE */ + KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ + /* (assignments unknown, please report if found) */ + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, +}; static struct attribute_set *hotkey_dev_attributes; @@ -889,11 +913,13 @@ static struct attribute *hotkey_mask_attributes[] = { static int __init hotkey_init(struct ibm_init_struct *iibm) { - int res; + int res, i; int status; vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); + BUG_ON(!tpacpi_inputdev); + IBM_ACPIHANDLE_INIT(hkey); mutex_init(&hotkey_mutex); @@ -950,6 +976,23 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) &tpacpi_pdev->dev.kobj); if (res) return res; + + set_bit(EV_KEY, tpacpi_inputdev->evbit); + set_bit(EV_MSC, tpacpi_inputdev->evbit); + set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); + tpacpi_inputdev->keycodesize = sizeof(hotkey_keycode_map[0]); + tpacpi_inputdev->keycodemax = ARRAY_SIZE(hotkey_keycode_map); + tpacpi_inputdev->keycode = &hotkey_keycode_map; + for (i = 0; i < ARRAY_SIZE(hotkey_keycode_map); i++) { + if (hotkey_keycode_map[i] != KEY_RESERVED) { + set_bit(hotkey_keycode_map[i], + tpacpi_inputdev->keybit); + } else { + if (i < sizeof(hotkey_reserved_mask)*8) + hotkey_reserved_mask |= 1 << i; + } + } + } return (tp_features.hotkey)? 0 : 1; @@ -972,12 +1015,69 @@ static void hotkey_exit(void) } } +static void tpacpi_input_send_key(unsigned int scancode, + unsigned int keycode) +{ + if (keycode != KEY_RESERVED) { + input_report_key(tpacpi_inputdev, keycode, 1); + if (keycode == KEY_UNKNOWN) + input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, + scancode); + input_sync(tpacpi_inputdev); + + input_report_key(tpacpi_inputdev, keycode, 0); + if (keycode == KEY_UNKNOWN) + input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, + scancode); + input_sync(tpacpi_inputdev); + } +} + static void hotkey_notify(struct ibm_struct *ibm, u32 event) { - int hkey; + u32 hkey; + unsigned int keycode, scancode; + int sendacpi = 1; if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { - acpi_bus_generate_event(ibm->acpi->device, event, hkey); + if (tpacpi_inputdev->users > 0) { + switch (hkey >> 12) { + case 1: + /* 0x1000-0x1FFF: key presses */ + scancode = hkey & 0xfff; + if (scancode > 0 && scancode < 0x21) { + scancode--; + keycode = hotkey_keycode_map[scancode]; + tpacpi_input_send_key(scancode, keycode); + sendacpi = (keycode == KEY_RESERVED + || keycode == KEY_UNKNOWN); + } else { + printk(IBM_ERR + "hotkey 0x%04x out of range for keyboard map\n", + hkey); + } + break; + case 5: + /* 0x5000-0x5FFF: LID */ + /* we don't handle it through this path, just + * eat up known LID events */ + if (hkey != 0x5001 && hkey != 0x5002) { + printk(IBM_ERR + "unknown LID-related hotkey event: 0x%04x\n", + hkey); + } + break; + default: + /* case 2: dock-related */ + /* 0x2305 - T43 waking up due to bay lever eject while aslept */ + /* case 3: ultra-bay related. maybe bay in dock? */ + /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ + printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey); + } + } + + if (sendacpi) + acpi_bus_generate_event(ibm->acpi->device, event, hkey); } else { printk(IBM_ERR "unknown hotkey notification event %d\n", event); acpi_bus_generate_event(ibm->acpi->device, event, 0); -- cgit v1.2.3 From 1a343760b516ca5466d201bec32b1794858b18a5 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:36 -0300 Subject: ACPI: thinkpad-acpi: make the input event mode the default Make the input layer the default way to deal with thinkpad-acpi hot keys, but add a kernel config option to retain the old way of doing things. This means we map a lot more keys to useful stuff by default, and also that we enable hot key handling by default on driver load (like Windows does). The documentation for proper use of this resource is also updated. Signed-off-by: Henrique de Moraes Holschuh Cc: Richard Hughes Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 5c1bea1a6c37..c86b228375cc 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -734,9 +734,9 @@ static u32 hotkey_reserved_mask; static u16 hotkey_keycode_map[] = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_FN_F1, KEY_FN_F2, KEY_FN_F3, KEY_SLEEP, + KEY_FN_F5, KEY_FN_F6, KEY_FN_F7, KEY_FN_F8, + KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ KEY_UNKNOWN, /* 0x0D: FN+INSERT */ @@ -977,6 +977,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (res) return res; +#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED + for (i = 0; i < 12; i++) + hotkey_keycode_map[i] = KEY_UNKNOWN; +#endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ + set_bit(EV_KEY, tpacpi_inputdev->evbit); set_bit(EV_MSC, tpacpi_inputdev->evbit); set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); @@ -993,6 +998,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } } +#ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED + dbg_printk(TPACPI_DBG_INIT, + "enabling hot key handling\n"); + res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) + | hotkey_orig_mask); + if (res) + return res; +#endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ } return (tp_features.hotkey)? 0 : 1; -- cgit v1.2.3 From e295e8508c1dd56e06c73e78a2f67f2eb563e74f Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:37 -0300 Subject: ACPI: thinkpad-acpi: add power-management handler capability Some subdrivers could benefit from resume handling, so add the infrastructure for simple resume handling. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index c86b228375cc..78914bf2166d 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -519,11 +519,27 @@ static struct platform_device *tpacpi_pdev; static struct class_device *tpacpi_hwmon; static struct input_dev *tpacpi_inputdev; + +static int tpacpi_resume_handler(struct platform_device *pdev) +{ + struct ibm_struct *ibm, *itmp; + + list_for_each_entry_safe(ibm, itmp, + &tpacpi_all_drivers, + all_drivers) { + if (ibm->resume) + (ibm->resume)(); + } + + return 0; +} + static struct platform_driver tpacpi_pdriver = { .driver = { .name = IBM_DRVR_NAME, .owner = THIS_MODULE, }, + .resume = tpacpi_resume_handler, }; -- cgit v1.2.3 From 5c29d58f471099401513e2e567f6c28001bb0f13 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:38 -0300 Subject: ACPI: thinkpad-acpi: export EV_SW SW_RADIO events The expected user case for the radio slider switch on a ThinkPad includes interfacing to applications, so that the user gets an offer to find and associate with a wireless network when the switch is changed from disabled to enabled (ThinkVantage suite). Export the information about the switch state, and switch change events as an EV_SW SW_RADIO event over the input layer. Signed-off-by: Henrique de Moraes Holschuh Cc: Dmitry Torokhov Cc: Ivo van Doorn Cc: Richard Hughes Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 78914bf2166d..cfef218c4513 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1014,6 +1014,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) } } + if (tp_features.hotkey_wlsw) { + set_bit(EV_SW, tpacpi_inputdev->evbit); + set_bit(SW_RADIO, tpacpi_inputdev->swbit); + } + #ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); @@ -1062,6 +1067,15 @@ static void tpacpi_input_send_key(unsigned int scancode, } } +static void tpacpi_input_send_radiosw(void) +{ + int wlsw; + + if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) + input_report_switch(tpacpi_inputdev, + SW_RADIO, !!wlsw); +} + static void hotkey_notify(struct ibm_struct *ibm, u32 event) { u32 hkey; @@ -1096,6 +1110,14 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) hkey); } break; + case 7: + /* 0x7000-0x7FFF: misc */ + if (tp_features.hotkey_wlsw && hkey == 0x7000) { + tpacpi_input_send_radiosw(); + sendacpi = 0; + break; + } + /* fallthrough to default */ default: /* case 2: dock-related */ /* 0x2305 - T43 waking up due to bay lever eject while aslept */ @@ -1113,6 +1135,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) } } +static void hotkey_resume(void) +{ + tpacpi_input_send_radiosw(); +} + /* * Call with hotkey_mutex held */ @@ -1240,6 +1267,7 @@ static struct ibm_struct hotkey_driver_data = { .read = hotkey_read, .write = hotkey_write, .exit = hotkey_exit, + .resume = hotkey_resume, .acpi = &ibm_hotkey_acpidriver, }; -- cgit v1.2.3 From 741553c2d29b4075d636a38792c05cd2fc62bd8a Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:39 -0300 Subject: ACPI: thinkpad-acpi: checkpoint sysfs interface version due to input layer The change in the way hotkey events are handled by default, and the use of the input layer for the hotkey events are important enough features to warrant increasing the major field of the sysfs interface version. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index cfef218c4513..c1e6a01d0857 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -22,7 +22,7 @@ */ #define IBM_VERSION "0.14" -#define TPACPI_SYSFS_VERSION 0x000200 +#define TPACPI_SYSFS_VERSION 0x010000 /* * Changelog: -- cgit v1.2.3 From 996fba08db7faf46b1a674957f60cd772ecd29ec Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:40 -0300 Subject: ACPI: thinkpad-acpi: rename pci HID constant Rename an internal driver constant, on request by Len Brown. Also, document exactly what it is for. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index c1e6a01d0857..78e41102a95c 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2026,7 +2026,10 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { .type = ACPI_SYSTEM_NOTIFY, }, { - .hid = IBM_PCI_HID, + /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING. + * We just use it to get notifications of dock hotplug + * in very old thinkpads */ + .hid = PCI_ROOT_HID_STRING, .notify = dock_notify, .handle = &pci_handle, .type = ACPI_SYSTEM_NOTIFY, @@ -2085,7 +2088,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm) static void dock_notify(struct ibm_struct *ibm, u32 event) { int docked = dock_docked(); - int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID); + int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, PCI_ROOT_HID_STRING); if (event == 1 && !pci) /* 570 */ acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ -- cgit v1.2.3 From 86cc9445e86bef9da44f933e3849e6eb43cbf626 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:41 -0300 Subject: ACPI: thinkpad_acpi: use bool for boolean parameters Some of the module parameters are boolean in nature. Make it so in fact. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 78e41102a95c..44aa8c92f91f 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -4444,10 +4444,10 @@ static u32 dbg_level; module_param_named(debug, dbg_level, uint, 0); static int force_load; -module_param(force_load, int, 0); +module_param(force_load, bool, 0); static int fan_control_allowed; -module_param_named(fan_control, fan_control_allowed, int, 0); +module_param_named(fan_control, fan_control_allowed, bool, 0); #define IBM_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0) -- cgit v1.2.3 From d5a2f2f1d68e2da538ac28540cddd9ccc733b001 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:42 -0300 Subject: ACPI: thinkpad-acpi: store ThinkPad model information Keep note of ThinkPad model, BIOS and EC firmware information, and log it on startup. Makes for far more readable code in places, too. This patch also adds Lenovo's PCI ID to the pci ids table. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 98 +++++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 28 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 44aa8c92f91f..99500af651c1 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -717,9 +717,19 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); printk(IBM_INFO "%s\n", IBM_URL); - if (ibm_thinkpad_ec_found) - printk(IBM_INFO "ThinkPad EC firmware %s\n", - ibm_thinkpad_ec_found); + printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n", + (thinkpad_id.bios_version_str) ? + thinkpad_id.bios_version_str : "unknown", + (thinkpad_id.ec_version_str) ? + thinkpad_id.ec_version_str : "unknown"); + + if (thinkpad_id.vendor && thinkpad_id.model_str) + printk(IBM_INFO "%s %s\n", + (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? + "IBM" : ((thinkpad_id.vendor == + PCI_VENDOR_ID_LENOVO) ? + "Lenovo" : "Unknown vendor"), + thinkpad_id.model_str); return 0; } @@ -2648,7 +2658,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); - if (ibm_thinkpad_ec_found && experimental) { + if (thinkpad_id.ec_model && experimental) { /* * Direct EC access mode: sensors at registers * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for @@ -3532,20 +3542,19 @@ static int __init fan_init(struct ibm_init_struct *iibm) * Enable for TP-1Y (T43), TP-78 (R51e), * TP-76 (R52), TP-70 (T43, R52), which are known * to be buggy. */ - if (fan_control_initial_status == 0x07 && - ibm_thinkpad_ec_found && - ((ibm_thinkpad_ec_found[0] == '1' && - ibm_thinkpad_ec_found[1] == 'Y') || - (ibm_thinkpad_ec_found[0] == '7' && - (ibm_thinkpad_ec_found[1] == '6' || - ibm_thinkpad_ec_found[1] == '8' || - ibm_thinkpad_ec_found[1] == '0')) - )) { - printk(IBM_NOTICE - "fan_init: initial fan status is " - "unknown, assuming it is in auto " - "mode\n"); - tp_features.fan_ctrl_status_undef = 1; + if (fan_control_initial_status == 0x07) { + switch (thinkpad_id.ec_model) { + case 0x5931: /* TP-1Y */ + case 0x3837: /* TP-78 */ + case 0x3637: /* TP-76 */ + case 0x3037: /* TP-70 */ + printk(IBM_NOTICE + "fan_init: initial fan status is " + "unknown, assuming it is in auto " + "mode\n"); + tp_features.fan_ctrl_status_undef = 1; + ;; + } } } else { printk(IBM_ERR @@ -4279,13 +4288,30 @@ static void ibm_exit(struct ibm_struct *ibm) /* Probing */ -static char *ibm_thinkpad_ec_found; - -static char* __init check_dmi_for_ec(void) +static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) { struct dmi_device *dev = NULL; char ec_fw_string[18]; + if (!tp) + return; + + memset(tp, 0, sizeof(*tp)); + + if (dmi_name_in_vendors("IBM")) + tp->vendor = PCI_VENDOR_ID_IBM; + else if (dmi_name_in_vendors("LENOVO")) + tp->vendor = PCI_VENDOR_ID_LENOVO; + else + return; + + tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION), + GFP_KERNEL); + if (!tp->bios_version_str) + return; + tp->bios_model = tp->bios_version_str[0] + | (tp->bios_version_str[1] << 8); + /* * ThinkPad T23 or newer, A31 or newer, R50e or newer, * X32 or newer, all Z series; Some models must have an @@ -4299,10 +4325,20 @@ static char* __init check_dmi_for_ec(void) ec_fw_string) == 1) { ec_fw_string[sizeof(ec_fw_string) - 1] = 0; ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; - return kstrdup(ec_fw_string, GFP_KERNEL); + + tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); + tp->ec_model = ec_fw_string[0] + | (ec_fw_string[1] << 8); + break; } } - return NULL; + + tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION), + GFP_KERNEL); + if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) { + kfree(tp->model_str); + tp->model_str = NULL; + } } static int __init probe_for_thinkpad(void) @@ -4316,7 +4352,7 @@ static int __init probe_for_thinkpad(void) * Non-ancient models have better DMI tagging, but very old models * don't. */ - is_thinkpad = dmi_name_in_vendors("ThinkPad"); + is_thinkpad = (thinkpad_id.model_str != NULL); /* ec is required because many other handles are relative to it */ IBM_ACPIHANDLE_INIT(ec); @@ -4332,7 +4368,7 @@ static int __init probe_for_thinkpad(void) * false positives a damn great deal */ if (!is_thinkpad) - is_thinkpad = dmi_name_in_vendors("IBM"); + is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM); if (!is_thinkpad && !force_load) return -ENODEV; @@ -4475,12 +4511,16 @@ static int __init thinkpad_acpi_module_init(void) int ret, i; /* Driver-level probe */ + + get_thinkpad_model_data(&thinkpad_id); ret = probe_for_thinkpad(); - if (ret) + if (ret) { + thinkpad_acpi_module_exit(); return ret; + } /* Driver initialization */ - ibm_thinkpad_ec_found = check_dmi_for_ec(); + IBM_ACPIHANDLE_INIT(ecrd); IBM_ACPIHANDLE_INIT(ecwr); @@ -4590,7 +4630,9 @@ static void thinkpad_acpi_module_exit(void) if (proc_dir) remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); - kfree(ibm_thinkpad_ec_found); + kfree(thinkpad_id.bios_version_str); + kfree(thinkpad_id.ec_version_str); + kfree(thinkpad_id.model_str); } module_init(thinkpad_acpi_module_init); -- cgit v1.2.3 From 24d3b77467b6aaf59e38dce4aa86d05541858195 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:43 -0300 Subject: ACPI: thinkpad-acpi: allow use of CMOS NVRAM for brightness control It appears that Lenovo decided to break the EC brightness control interface in a weird way in their latest BIOSes. Fortunately, the old CMOS NVRAM interface works just fine in such BIOSes. Add a module parameter that allows the user to select which strategy to use for brightness control: EC, NVRAM, or both. By default, do both (which is the way thinkpad-acpi used to work until now) on IBM ThinkPads, and use NVRAM only on Lenovo ThinkPads. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 62 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 9 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 99500af651c1..5318eb272c61 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2953,9 +2953,22 @@ static int __init brightness_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); + if (!brightness_mode) { + if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) + brightness_mode = 2; + else + brightness_mode = 3; + + dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n", + brightness_mode); + } + + if (brightness_mode > 3) + return -EINVAL; + b = brightness_get(NULL); if (b < 0) - return b; + return 1; ibm_backlight_device = backlight_device_register( TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, @@ -2991,13 +3004,35 @@ static int brightness_update_status(struct backlight_device *bd) bd->props.brightness : 0); } +/* + * ThinkPads can read brightness from two places: EC 0x31, or + * CMOS NVRAM byte 0x5E, bits 0-3. + */ static int brightness_get(struct backlight_device *bd) { - u8 level; - if (!acpi_ec_read(brightness_offset, &level)) - return -EIO; + u8 lec = 0, lcmos = 0, level = 0; - level &= 0x7; + if (brightness_mode & 1) { + if (!acpi_ec_read(brightness_offset, &lec)) + return -EIO; + lec &= 7; + level = lec; + }; + if (brightness_mode & 2) { + lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) + & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) + >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; + level = lcmos; + } + + if (brightness_mode == 3 && lec != lcmos) { + printk(IBM_ERR + "CMOS NVRAM (%u) and EC (%u) do not agree " + "on display brightness level\n", + (unsigned int) lcmos, + (unsigned int) lec); + return -EIO; + } return level; } @@ -3007,14 +3042,20 @@ static int brightness_set(int value) int cmos_cmd, inc, i; int current_value = brightness_get(NULL); - value &= 7; + if (value > 7) + return -EINVAL; - cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN; + cmos_cmd = value > current_value ? + TP_CMOS_BRIGHTNESS_UP : + TP_CMOS_BRIGHTNESS_DOWN; inc = value > current_value ? 1 : -1; + for (i = current_value; i != value; i += inc) { - if (issue_thinkpad_cmos_command(cmos_cmd)) + if ((brightness_mode & 2) && + issue_thinkpad_cmos_command(cmos_cmd)) return -EIO; - if (!acpi_ec_write(brightness_offset, i + inc)) + if ((brightness_mode & 1) && + !acpi_ec_write(brightness_offset, i + inc)) return -EIO; } @@ -4485,6 +4526,9 @@ module_param(force_load, bool, 0); static int fan_control_allowed; module_param_named(fan_control, fan_control_allowed, bool, 0); +static int brightness_mode; +module_param_named(brightness_mode, brightness_mode, int, 0); + #define IBM_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0) -- cgit v1.2.3 From edf0e0e56904f794c97ca6c4562d8256e3d8d8e3 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:44 -0300 Subject: ACPI: thinkpad-acpi: react to Lenovo ThinkPad differences in hot key Lenovo ThinkPads have a slightly different key map layout from IBM ThinkPads (fn+f2 and fn+f3 are swapped). Knowing which one we are dealing with, we can properly set a few more hot keys up by default. Also, export the correct vendor in the input device, as that information might be useful to userspace. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 109 ++++++++++++++++++++++++++++++++----------- 1 file changed, 81 insertions(+), 28 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 5318eb272c61..623d36fd8dbe 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -758,29 +758,7 @@ static u32 hotkey_orig_mask; static u32 hotkey_all_mask; static u32 hotkey_reserved_mask; -static u16 hotkey_keycode_map[] = { - /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ - KEY_FN_F1, KEY_FN_F2, KEY_FN_F3, KEY_SLEEP, - KEY_FN_F5, KEY_FN_F6, KEY_FN_F7, KEY_FN_F8, - KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, - /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ - KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ - KEY_UNKNOWN, /* 0x0D: FN+INSERT */ - KEY_UNKNOWN, /* 0x0E: FN+DELETE */ - KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ - /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ - KEY_RESERVED, /* 0x10: FN+END (brightness down) */ - KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ - KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ - KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ - KEY_RESERVED, /* 0x14: VOLUME UP */ - KEY_RESERVED, /* 0x15: VOLUME DOWN */ - KEY_RESERVED, /* 0x16: MUTE */ - KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ - /* (assignments unknown, please report if found) */ - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, -}; +static u16 *hotkey_keycode_map; static struct attribute_set *hotkey_dev_attributes; @@ -939,6 +917,58 @@ static struct attribute *hotkey_mask_attributes[] = { static int __init hotkey_init(struct ibm_init_struct *iibm) { + + static u16 ibm_keycode_map[] __initdata = { + /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ + KEY_FN_F1, KEY_FN_F2, 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, + /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ + KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ + KEY_UNKNOWN, /* 0x0D: FN+INSERT */ + KEY_UNKNOWN, /* 0x0E: FN+DELETE */ + KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ + /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ + KEY_RESERVED, /* 0x10: FN+END (brightness down) */ + KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ + KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ + KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ + KEY_RESERVED, /* 0x14: VOLUME UP */ + KEY_RESERVED, /* 0x15: VOLUME DOWN */ + KEY_RESERVED, /* 0x16: MUTE */ + KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ + /* (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 = { + /* 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_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, + /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ + KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ + KEY_UNKNOWN, /* 0x0D: FN+INSERT */ + KEY_UNKNOWN, /* 0x0E: FN+DELETE */ + KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ + /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ + KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ + KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ + KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ + KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ + KEY_RESERVED, /* 0x14: VOLUME UP */ + KEY_RESERVED, /* 0x15: VOLUME DOWN */ + KEY_RESERVED, /* 0x16: MUTE */ + KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ + /* (assignments unknown, please report if found) */ + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + }; + +#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]) + int res, i; int status; @@ -1003,6 +1033,27 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (res) return res; + /* Set up key map */ + + hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, + GFP_KERNEL); + if (!hotkey_keycode_map) { + printk(IBM_ERR "failed to allocate memory for key map\n"); + return -ENOMEM; + } + + if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { + dbg_printk(TPACPI_DBG_INIT, + "using Lenovo default hot key map\n"); + memcpy(hotkey_keycode_map, &lenovo_keycode_map, + TPACPI_HOTKEY_MAP_SIZE); + } else { + dbg_printk(TPACPI_DBG_INIT, + "using IBM default hot key map\n"); + memcpy(hotkey_keycode_map, &ibm_keycode_map, + TPACPI_HOTKEY_MAP_SIZE); + } + #ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED for (i = 0; i < 12; i++) hotkey_keycode_map[i] = KEY_UNKNOWN; @@ -1011,10 +1062,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) set_bit(EV_KEY, tpacpi_inputdev->evbit); set_bit(EV_MSC, tpacpi_inputdev->evbit); set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); - tpacpi_inputdev->keycodesize = sizeof(hotkey_keycode_map[0]); - tpacpi_inputdev->keycodemax = ARRAY_SIZE(hotkey_keycode_map); - tpacpi_inputdev->keycode = &hotkey_keycode_map; - for (i = 0; i < ARRAY_SIZE(hotkey_keycode_map); i++) { + tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; + tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; + tpacpi_inputdev->keycode = hotkey_keycode_map; + for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { if (hotkey_keycode_map[i] != KEY_RESERVED) { set_bit(hotkey_keycode_map[i], tpacpi_inputdev->keybit); @@ -4618,7 +4669,9 @@ static int __init thinkpad_acpi_module_init(void) tpacpi_inputdev->name = "ThinkPad Extra Buttons"; tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0"; tpacpi_inputdev->id.bustype = BUS_HOST; - tpacpi_inputdev->id.vendor = TPACPI_HKEY_INPUT_VENDOR; + tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? + thinkpad_id.vendor : + PCI_VENDOR_ID_IBM; tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; } -- cgit v1.2.3 From a8fba3da3d11d808137be7ebeb3b6938a42f011f Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:45 -0300 Subject: ACPI: thinkpad-acpi: make sure DSDT TMPx readings don't return +128 We get +128 instead of -128 from the DSDT TMPx methods, due to errors when converting a EC byte return that is a s8 to an ACPI handler return that is an int. Fix it once and for all, by clamping acceptable temperature readings from DSDT TMPx so that anything outside the [-127,+127] range is converted to TP_EC_THERMAL_TMP_NA (-128). Signed-off-by: Henrique de Moraes Holschuh Cc: Michael Olbrich Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 623d36fd8dbe..f74d7d600d83 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2853,6 +2853,8 @@ static int thermal_get_sensor(int idx, s32 *value) snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); if (!acpi_evalf(ec_handle, &t, tmpi, "d")) return -EIO; + if (t > 127 || t < -127) + t = TP_EC_THERMAL_TMP_NA; *value = t * 1000; return 0; } -- cgit v1.2.3 From 3d6f99ca00ccf861305fd8630a21f2e696886708 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:46 -0300 Subject: ACPI: thinkpad-acpi: make EC-based thermal readings non-experimental Reading the 16 thermal sensors directly from the EC has been stable for about one year, in all supported ThinkPad models. Remove its "experimental" label. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index f74d7d600d83..84a1000e4cec 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2709,7 +2709,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); - if (thinkpad_id.ec_model && experimental) { + if (thinkpad_id.ec_model) { /* * Direct EC access mode: sensors at registers * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for -- cgit v1.2.3 From c78d5c96bb65b71a54b7551b404fbaf4763ed6e4 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:47 -0300 Subject: ACPI: thinkpad-acpi: bump up version to 0.15 Name it thinkpad-acpi version 0.15. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 84a1000e4cec..01bed937d387 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -#define IBM_VERSION "0.14" +#define IBM_VERSION "0.15" #define TPACPI_SYSFS_VERSION 0x010000 /* -- cgit v1.2.3 From f432255e936a892a6896e5032e2b4897423076f2 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Wed, 18 Jul 2007 23:45:48 -0300 Subject: ACPI: thinkpad-acpi: add locking to brightness subdriver The backlight class does all the locking needed for sysfs access, but offers no API to interface to that locking without an layer violation. Since we need to mutex-lock procfs access, implement in-driver locking for brightness. It will go away the day thinkpad-acpi procfs goes away, or the backlight class gives us a way to use its locks without a layer violation. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 01bed937d387..f15a58f7403f 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -3000,12 +3000,16 @@ static struct backlight_ops ibm_backlight_data = { .update_status = brightness_update_status, }; +static struct mutex brightness_mutex; + static int __init brightness_init(struct ibm_init_struct *iibm) { int b; vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); + mutex_init(&brightness_mutex); + if (!brightness_mode) { if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) brightness_mode = 2; @@ -3092,27 +3096,44 @@ static int brightness_get(struct backlight_device *bd) static int brightness_set(int value) { - int cmos_cmd, inc, i; - int current_value = brightness_get(NULL); + int cmos_cmd, inc, i, res; + int current_value; if (value > 7) return -EINVAL; + res = mutex_lock_interruptible(&brightness_mutex); + if (res < 0) + return res; + + current_value = brightness_get(NULL); + if (current_value < 0) { + res = current_value; + goto errout; + } + cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN; inc = value > current_value ? 1 : -1; + res = 0; for (i = current_value; i != value; i += inc) { if ((brightness_mode & 2) && - issue_thinkpad_cmos_command(cmos_cmd)) - return -EIO; + issue_thinkpad_cmos_command(cmos_cmd)) { + res = -EIO; + goto errout; + } if ((brightness_mode & 1) && - !acpi_ec_write(brightness_offset, i + inc)) - return -EIO; + !acpi_ec_write(brightness_offset, i + inc)) { + res = -EIO; + goto errout;; + } } - return 0; +errout: + mutex_unlock(&brightness_mutex); + return res; } static int brightness_read(char *p) -- cgit v1.2.3 From 1ba90e3a87c46500623afdc3898573e4a5ebb21b Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 23 Jul 2007 14:44:41 +0200 Subject: ACPI: autoload modules - Create __mod_acpi_device_table symbol for all ACPI drivers modpost is going to use these to create e.g. acpi:ACPI0001 in modules.alias. Signed-off-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index f15a58f7403f..fa80f355e522 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -411,12 +411,13 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); ibm->acpi->driver->ids = ibm->acpi->hid; + ibm->acpi->driver->ops.add = &tpacpi_device_add; rc = acpi_bus_register_driver(ibm->acpi->driver); if (rc < 0) { printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", - ibm->acpi->hid, rc); + ibm->name, rc); kfree(ibm->acpi->driver); ibm->acpi->driver = NULL; } else if (!rc) @@ -1316,8 +1317,13 @@ errexit: return res; } +static const struct acpi_device_id ibm_htk_device_ids[] = { + {IBM_HKEY_HID, 0}, + {"", 0}, +}; + static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { - .hid = IBM_HKEY_HID, + .hid = ibm_htk_device_ids, .notify = hotkey_notify, .handle = &hkey_handle, .type = ACPI_DEVICE_NOTIFY, @@ -2080,6 +2086,11 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ /* don't list other alternatives as we install a notify handler on the 570 */ IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ +static const struct acpi_device_id ibm_pci_device_ids[] = { + {PCI_ROOT_HID_STRING, 0}, + {"", 0}, +}; + static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { { .notify = dock_notify, @@ -2090,7 +2101,7 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING. * We just use it to get notifications of dock hotplug * in very old thinkpads */ - .hid = PCI_ROOT_HID_STRING, + .hid = ibm_pci_device_ids, .notify = dock_notify, .handle = &pci_handle, .type = ACPI_SYSTEM_NOTIFY, @@ -2149,7 +2160,8 @@ static int __init dock_init2(struct ibm_init_struct *iibm) static void dock_notify(struct ibm_struct *ibm, u32 event) { int docked = dock_docked(); - int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, PCI_ROOT_HID_STRING); + int pci = ibm->acpi->hid && ibm->acpi->device && + acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids); if (event == 1 && !pci) /* 570 */ acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ -- cgit v1.2.3 From ac36393de6034be7266264a435360e7628849005 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Fri, 27 Jul 2007 17:04:40 -0300 Subject: ACPI: thinkpad-acpi: fix the module init failure path Thomas Renninger reports that if one tries to load thinkpad-acpi in a non-thinkpad, one gets: Call Trace: [] kref_get+0x2f/0x36 [] kobject_get+0x12/0x17 [] get_driver+0x14/0x1a [] driver_remove_file+0x11/0x32 [] :thinkpad_acpi:thinkpad_acpi_module_exit+0xa8/0xfc [] :thinkpad_acpi:thinkpad_acpi_module_init+0x74a/0x776 [] __link_module+0x0/0x25 [] sys_init_module+0x162c/0x178f [] system_call+0x7e/0x83 So, track if the platform driver and its driver attributes were registered, and only deallocate them in that case. This patch is based on Thomas Renninger's patch for the issue. Signed-off-by: Henrique de Moraes Holschuh Acked-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index fa80f355e522..f6cd34a3dbac 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -4668,12 +4668,15 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } + tp_features.platform_drv_registered = 1; + ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); if (ret) { printk(IBM_ERR "unable to create sysfs driver attributes\n"); thinkpad_acpi_module_exit(); return ret; } + tp_features.platform_drv_attrs_registered = 1; /* Device initialization */ @@ -4756,8 +4759,11 @@ static void thinkpad_acpi_module_exit(void) if (tpacpi_pdev) platform_device_unregister(tpacpi_pdev); - tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); - platform_driver_unregister(&tpacpi_pdriver); + if (tp_features.platform_drv_attrs_registered) + tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); + + if (tp_features.platform_drv_registered) + platform_driver_unregister(&tpacpi_pdriver); if (proc_dir) remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); -- cgit v1.2.3 From 962ce8ca0604af0c3c5609f7613d4ec5fcfac623 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 23 Aug 2007 01:24:31 +0800 Subject: ACPI: don't duplicate input events on netlink The previous events patch added a netlink event for every user of the legacy /proc/acpi/event interface. However, some users of /proc/acpi/event are really input events, and they already report their events via the input layer. Introduce a new interface, acpi_bus_generate_netlink_event(), which is explicitly called by devices that want to repoprt events via netlink. This allows the input-like events to opt-out of generating netlink events. In summary: events that are sent via netlink: ac/battery/sbs thermal processor thinkpad_acpi dock/bay events that are sent via input layer: button video hotkey thinkpad_acpi hotkey asus_acpi/asus-laptop hotkey sonypi/sonylaptop Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index f6cd34a3dbac..d0825a34a7b0 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2162,22 +2162,27 @@ static void dock_notify(struct ibm_struct *ibm, u32 event) int docked = dock_docked(); int pci = ibm->acpi->hid && ibm->acpi->device && acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids); + int data; if (event == 1 && !pci) /* 570 */ - acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ + data = 1; /* button */ else if (event == 1 && pci) /* 570 */ - acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ + data = 3; /* dock */ else if (event == 3 && docked) - acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ + data = 1; /* button */ else if (event == 3 && !docked) - acpi_bus_generate_event(ibm->acpi->device, event, 2); /* undock */ + data = 2; /* undock */ else if (event == 0 && docked) - acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ + data = 3; /* dock */ else { printk(IBM_ERR "unknown dock event %d, status %d\n", event, _sta(dock_handle)); - acpi_bus_generate_event(ibm->acpi->device, event, 0); /* unknown */ + data = 0; /* unknown */ } + acpi_bus_generate_event(ibm->acpi->device, event, data); + acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, + ibm->acpi->device->dev.bus_id, + event, data); } static int dock_read(char *p) @@ -2276,6 +2281,9 @@ static int __init bay_init(struct ibm_init_struct *iibm) static void bay_notify(struct ibm_struct *ibm, u32 event) { acpi_bus_generate_event(ibm->acpi->device, event, 0); + acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, + ibm->acpi->device->dev.bus_id, + event, 0); } #define bay_occupied(b) (_sta(b##_handle) & 1) -- cgit v1.2.3 From 14e04fb34ffa82ee61ae69f98d8fca12d2e8e31c Mon Sep 17 00:00:00 2001 From: Len Brown Date: Thu, 23 Aug 2007 15:20:26 -0400 Subject: ACPI: Schedule /proc/acpi/event for removal Schedule /proc/acpi/event for removal in 6 months. Re-name acpi_bus_generate_event() to acpi_bus_generate_proc_event() to make sure there is no confusion that it is for /proc/acpi/event only. Add CONFIG_ACPI_PROC_EVENT to allow removal of /proc/acpi/event. There is no functional change if CONFIG_ACPI_PROC_EVENT=y Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index d0825a34a7b0..bb8956d0c104 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1190,10 +1190,10 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) } if (sendacpi) - acpi_bus_generate_event(ibm->acpi->device, event, hkey); + acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); } else { printk(IBM_ERR "unknown hotkey notification event %d\n", event); - acpi_bus_generate_event(ibm->acpi->device, event, 0); + acpi_bus_generate_proc_event(ibm->acpi->device, event, 0); } } @@ -2179,7 +2179,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event) event, _sta(dock_handle)); data = 0; /* unknown */ } - acpi_bus_generate_event(ibm->acpi->device, event, data); + acpi_bus_generate_proc_event(ibm->acpi->device, event, data); acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, ibm->acpi->device->dev.bus_id, event, data); @@ -2280,7 +2280,7 @@ static int __init bay_init(struct ibm_init_struct *iibm) static void bay_notify(struct ibm_struct *ibm, u32 event) { - acpi_bus_generate_event(ibm->acpi->device, event, 0); + acpi_bus_generate_proc_event(ibm->acpi->device, event, 0); acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, ibm->acpi->device->dev.bus_id, event, 0); -- cgit v1.2.3 From ff80f1370f2eff7dd7a828cf2416bf7be697247e Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 4 Sep 2007 11:13:15 -0300 Subject: ACPI: thinkpad-acpi: revert new 2.6.23 CONFIG_THINKPAD_ACPI_INPUT_ENABLED option Revert new 2.6.23 CONFIG_THINKPAD_ACPI_INPUT_ENABLED Kconfig option because it would create a legacy we don't want to support. CONFIG_THINKPAD_ACPI_INPUT_ENABLED was added to try to fix an issue that is now moot with the addition of the netlink ACPI event report interface to the ACPI core. Now that ACPI core can send events over netlink, we can use a different strategy to keep backwards compatibility with older userspace, without the need for the CONFIG_THINKPAD_ACPI_INPUT_ENABLED games. And it arrived before CONFIG_THINKPAD_ACPI_INPUT_ENABLED made it to a stable mainline kernel, even, which is Good. This patch is in sync with some changes to thinkpad-acpi backports, that will keep things sane for userspace across different combinations of kernel versions, thinkpad-acpi backports (or the lack thereof), and userspace capabilities: Unless a module parameter is used, thinkpad-acpi will now behave in such a way that it will work well (by default) with userspace that still uses only the old ACPI procfs event interface and doesn't care for thinkpad-acpi input devices. It will also always work well with userspace that has been updated to use both the thinkpad-acpi input devices, and ACPI core netlink event interface, regardless of any module parameter. The module parameter was added to allow thinkpad-acpi to work with userspace that has been partially updated to use thinkpad-acpi input devices, but not the new ACPI core netlink event interface. To use this mode of hot key reporting, one has to specify the hotkey_report_mode=2 module parameter. The thinkpad-acpi driver exports the value of hotkey_report_mode through sysfs, as well. thinkpad-acpi backports to older kernels, that do not support the new ACPI core netlink interface, have code to allow userspace to switch hotkey_report_mode at runtime through sysfs. This capability will not be provided in mainline thinkpad-acpi as it is not needed there. Signed-off-by: Henrique de Moraes Holschuh Cc: Michael S. Tsirkin Cc: Hugh Dickins Cc: Richard Hughes Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 142 ++++++++++++++++++++++++++----------------- 1 file changed, 86 insertions(+), 56 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index bb8956d0c104..3d849d13657d 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -906,9 +906,26 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, static struct device_attribute dev_attr_hotkey_radio_sw = __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); +/* sysfs hotkey report_mode -------------------------------------------- */ +static ssize_t hotkey_report_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + (hotkey_report_mode != 0) ? hotkey_report_mode : 1); +} + +static struct device_attribute dev_attr_hotkey_report_mode = + __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); + /* --------------------------------------------------------------------- */ -static struct attribute *hotkey_mask_attributes[] = { +static struct attribute *hotkey_attributes[] __initdata = { + &dev_attr_hotkey_enable.attr, + &dev_attr_hotkey_report_mode.attr, +}; + +static struct attribute *hotkey_mask_attributes[] __initdata = { &dev_attr_hotkey_mask.attr, &dev_attr_hotkey_bios_enabled.attr, &dev_attr_hotkey_bios_mask.attr, @@ -987,11 +1004,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) str_supported(tp_features.hotkey)); if (tp_features.hotkey) { - hotkey_dev_attributes = create_attr_set(7, NULL); + hotkey_dev_attributes = create_attr_set(8, NULL); if (!hotkey_dev_attributes) return -ENOMEM; - res = add_to_attr_set(hotkey_dev_attributes, - &dev_attr_hotkey_enable.attr); + res = add_many_to_attr_set(hotkey_dev_attributes, + hotkey_attributes, + ARRAY_SIZE(hotkey_attributes)); if (res) return res; @@ -1055,11 +1073,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) TPACPI_HOTKEY_MAP_SIZE); } -#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED - for (i = 0; i < 12; i++) - hotkey_keycode_map[i] = KEY_UNKNOWN; -#endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ - set_bit(EV_KEY, tpacpi_inputdev->evbit); set_bit(EV_MSC, tpacpi_inputdev->evbit); set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); @@ -1081,14 +1094,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) set_bit(SW_RADIO, tpacpi_inputdev->swbit); } -#ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) | hotkey_orig_mask); if (res) return res; -#endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ + + dbg_printk(TPACPI_DBG_INIT, + "legacy hot key reporting over procfs %s\n", + (hotkey_report_mode < 2) ? + "enabled" : "disabled"); } return (tp_features.hotkey)? 0 : 1; @@ -1142,58 +1158,65 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) { u32 hkey; unsigned int keycode, scancode; - int sendacpi = 1; + int send_acpi_ev = 0; if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { - if (tpacpi_inputdev->users > 0) { - switch (hkey >> 12) { - case 1: - /* 0x1000-0x1FFF: key presses */ - scancode = hkey & 0xfff; - if (scancode > 0 && scancode < 0x21) { - scancode--; - keycode = hotkey_keycode_map[scancode]; - tpacpi_input_send_key(scancode, keycode); - sendacpi = (keycode == KEY_RESERVED - || keycode == KEY_UNKNOWN); - } else { - printk(IBM_ERR - "hotkey 0x%04x out of range for keyboard map\n", - hkey); - } - break; - case 5: - /* 0x5000-0x5FFF: LID */ - /* we don't handle it through this path, just - * eat up known LID events */ - if (hkey != 0x5001 && hkey != 0x5002) { - printk(IBM_ERR - "unknown LID-related hotkey event: 0x%04x\n", - hkey); - } + switch (hkey >> 12) { + case 1: + /* 0x1000-0x1FFF: key presses */ + scancode = hkey & 0xfff; + if (scancode > 0 && scancode < 0x21) { + scancode--; + keycode = hotkey_keycode_map[scancode]; + tpacpi_input_send_key(scancode, keycode); + } else { + printk(IBM_ERR + "hotkey 0x%04x out of range for keyboard map\n", + hkey); + send_acpi_ev = 1; + } + break; + case 5: + /* 0x5000-0x5FFF: LID */ + /* we don't handle it through this path, just + * eat up known LID events */ + if (hkey != 0x5001 && hkey != 0x5002) { + printk(IBM_ERR + "unknown LID-related hotkey event: 0x%04x\n", + hkey); + send_acpi_ev = 1; + } + break; + case 7: + /* 0x7000-0x7FFF: misc */ + if (tp_features.hotkey_wlsw && hkey == 0x7000) { + tpacpi_input_send_radiosw(); break; - case 7: - /* 0x7000-0x7FFF: misc */ - if (tp_features.hotkey_wlsw && hkey == 0x7000) { - tpacpi_input_send_radiosw(); - sendacpi = 0; - break; - } - /* fallthrough to default */ - default: - /* case 2: dock-related */ - /* 0x2305 - T43 waking up due to bay lever eject while aslept */ - /* case 3: ultra-bay related. maybe bay in dock? */ - /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ - printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey); } + /* fallthrough to default */ + default: + /* case 2: dock-related */ + /* 0x2305 - T43 waking up due to bay lever eject while aslept */ + /* case 3: ultra-bay related. maybe bay in dock? */ + /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ + printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); + send_acpi_ev = 1; } - - if (sendacpi) - acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); } else { printk(IBM_ERR "unknown hotkey notification event %d\n", event); - acpi_bus_generate_proc_event(ibm->acpi->device, event, 0); + hkey = 0; + send_acpi_ev = 1; + } + + /* Legacy events */ + if (send_acpi_ev || hotkey_report_mode < 2) + acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); + + /* netlink events */ + if (send_acpi_ev) { + acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, + ibm->acpi->device->dev.bus_id, + event, hkey); } } @@ -4623,6 +4646,9 @@ module_param_named(fan_control, fan_control_allowed, bool, 0); static int brightness_mode; module_param_named(brightness_mode, brightness_mode, int, 0); +static unsigned int hotkey_report_mode; +module_param(hotkey_report_mode, uint, 0); + #define IBM_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0) @@ -4648,6 +4674,10 @@ static int __init thinkpad_acpi_module_init(void) { int ret, i; + /* Parameter checking */ + if (hotkey_report_mode > 2) + return -EINVAL; + /* Driver-level probe */ get_thinkpad_model_data(&thinkpad_id); -- cgit v1.2.3 From 3b0c6485a733f5f0f5c362fb094df1466b18ab93 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 4 Sep 2007 11:13:16 -0300 Subject: ACPI: thinkpad-acpi: bump up version to 0.16 Name it thinkpad-acpi version 0.16 to avoid any confusion with some 0.15 thinkpad-acpi development snapshots and backports that had input layer support, but no hotkey_report_mode support. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 3d849d13657d..0222bbaf7b76 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -21,7 +21,7 @@ * 02110-1301, USA. */ -#define IBM_VERSION "0.15" +#define IBM_VERSION "0.16" #define TPACPI_SYSFS_VERSION 0x010000 /* -- cgit v1.2.3 From 1855256c497ecfefc730df6032243f26855ce52c Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 3 Oct 2007 15:15:40 -0400 Subject: drivers/firmware: const-ify DMI API and internals Three main sets of changes: 1) dmi_get_system_info() return value should have been marked const, since callers should not be changing that data. 2) const-ify DMI internals, since DMI firmware tables should, whenever possible, be marked const to ensure we never ever write to that data area. 3) const-ify DMI API, to enable marking tables const where possible in low-level drivers. And if we're really lucky, this might enable some additional optimizations on the part of the compiler. The bulk of the changes are #2 and #3, which are interrelated. #1 could have been a separate patch, but it was so small compared to the others, it was easier to roll it into this changeset. Signed-off-by: Jeff Garzik --- drivers/misc/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc/thinkpad_acpi.c') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 0222bbaf7b76..6c0b2f0a51ab 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -4448,7 +4448,7 @@ static void ibm_exit(struct ibm_struct *ibm) static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) { - struct dmi_device *dev = NULL; + const struct dmi_device *dev = NULL; char ec_fw_string[18]; if (!tp) -- cgit v1.2.3