Loading Documentation/thinkpad-acpi.txt +19 −6 Original line number Diff line number Diff line Loading @@ -105,10 +105,15 @@ The version of thinkpad-acpi's sysfs interface is exported by the driver as a driver attribute (see below). Sysfs driver attributes are on the driver's sysfs attribute space, for 2.6.20 this is /sys/bus/platform/drivers/thinkpad_acpi/. for 2.6.23 this is /sys/bus/platform/drivers/thinkpad_acpi/ and /sys/bus/platform/drivers/thinkpad_hwmon/ Sysfs device attributes are on the driver's sysfs attribute space, for 2.6.20 this is /sys/devices/platform/thinkpad_acpi/. Sysfs device attributes are on the thinkpad_acpi device sysfs attribute space, for 2.6.23 this is /sys/devices/platform/thinkpad_acpi/. Sysfs device attributes for the sensors and fan are on the thinkpad_hwmon device's sysfs attribute space, but you should locate it looking for a hwmon device with the name attribute of "thinkpad". Driver version -------------- Loading Loading @@ -766,7 +771,7 @@ Temperature sensors ------------------- procfs: /proc/acpi/ibm/thermal sysfs device attributes: (hwmon) temp*_input sysfs device attributes: (hwmon "thinkpad") temp*_input Most ThinkPads include six or more separate temperature sensors but only expose the CPU temperature through the standard ACPI methods. This Loading Loading @@ -989,7 +994,9 @@ Fan control and monitoring: fan speed, fan enable/disable --------------------------------------------------------- procfs: /proc/acpi/ibm/fan sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1, pwm1_enable sysfs hwmon driver attributes: fan_watchdog NOTE NOTE NOTE: fan control operations are disabled by default for safety reasons. To enable them, the module parameter "fan_control=1" Loading Loading @@ -1131,7 +1138,7 @@ hwmon device attribute fan1_input: which can take up to two minutes. May return rubbish on older ThinkPads. driver attribute fan_watchdog: hwmon driver attribute fan_watchdog: Fan safety watchdog timer interval, in seconds. Minimum is 1 second, maximum is 120 seconds. 0 disables the watchdog. Loading Loading @@ -1233,3 +1240,9 @@ Sysfs interface changelog: layer, the radio switch generates input event EV_RADIO, and the driver enables hot key handling by default in the firmware. 0x020000: ABI fix: added a separate hwmon platform device and driver, which must be located by name (thinkpad) and the hwmon class for libsensors4 (lm-sensors 3) compatibility. Moved all hwmon attributes to this new platform device. drivers/misc/thinkpad_acpi.c +170 −37 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ */ #define IBM_VERSION "0.16" #define TPACPI_SYSFS_VERSION 0x010000 #define TPACPI_SYSFS_VERSION 0x020000 /* * Changelog: Loading Loading @@ -117,6 +117,12 @@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); #define __unused __attribute__ ((unused)) static enum { TPACPI_LIFE_INIT = 0, TPACPI_LIFE_RUNNING, TPACPI_LIFE_EXITING, } tpacpi_lifecycle; /**************************************************************************** **************************************************************************** * Loading Loading @@ -342,6 +348,9 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) { struct ibm_struct *ibm = data; if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) return; if (!ibm || !ibm->acpi || !ibm->acpi->notify) return; Loading Loading @@ -517,8 +526,10 @@ static char *next_cmd(char **cmds) ****************************************************************************/ static struct platform_device *tpacpi_pdev; static struct platform_device *tpacpi_sensors_pdev; static struct class_device *tpacpi_hwmon; static struct input_dev *tpacpi_inputdev; static struct mutex tpacpi_inputdev_send_mutex; static int tpacpi_resume_handler(struct platform_device *pdev) Loading @@ -543,6 +554,12 @@ static struct platform_driver tpacpi_pdriver = { .resume = tpacpi_resume_handler, }; static struct platform_driver tpacpi_hwmon_pdriver = { .driver = { .name = IBM_HWMON_DRVR_NAME, .owner = THIS_MODULE, }, }; /************************************************************************* * thinkpad-acpi driver attributes Loading Loading @@ -692,6 +709,8 @@ static int parse_strtoul(const char *buf, { char *endp; while (*buf && isspace(*buf)) buf++; *value = simple_strtoul(buf, &endp, 0); while (*endp && isspace(*endp)) endp++; Loading Loading @@ -989,6 +1008,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) int res, i; int status; int hkeyv; vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); Loading @@ -1014,19 +1034,36 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) return res; /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, A30, R30, R31, T20-22, X20-21, X22-24 */ tp_features.hotkey_mask = acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking for HKEY interface version 0x100 */ if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { if ((hkeyv >> 8) != 1) { printk(IBM_ERR "unknown version of the " "HKEY interface: 0x%x\n", hkeyv); printk(IBM_ERR "please report this to %s\n", IBM_MAIL); } else { /* * MHKV 0x100 in A31, R40, R40e, * T4x, X31, and later * */ tp_features.hotkey_mask = 1; } } 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")) "MHKA", "qd")) { printk(IBM_ERR "missing MHKA handler, " "please report this to %s\n", IBM_MAIL); 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) { Loading Loading @@ -1131,6 +1168,8 @@ static void tpacpi_input_send_key(unsigned int scancode, unsigned int keycode) { if (keycode != KEY_RESERVED) { mutex_lock(&tpacpi_inputdev_send_mutex); input_report_key(tpacpi_inputdev, keycode, 1); if (keycode == KEY_UNKNOWN) input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, Loading @@ -1142,6 +1181,8 @@ static void tpacpi_input_send_key(unsigned int scancode, input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); } } Loading @@ -1149,18 +1190,47 @@ static void tpacpi_input_send_radiosw(void) { int wlsw; if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) mutex_lock(&tpacpi_inputdev_send_mutex); if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { input_report_switch(tpacpi_inputdev, SW_RADIO, !!wlsw); input_sync(tpacpi_inputdev); } mutex_unlock(&tpacpi_inputdev_send_mutex); } static void hotkey_notify(struct ibm_struct *ibm, u32 event) { u32 hkey; unsigned int keycode, scancode; int send_acpi_ev = 0; int send_acpi_ev; int ignore_acpi_ev; if (event != 0x80) { printk(IBM_ERR "unknown HKEY notification event %d\n", event); /* forward it to userspace, maybe it knows how to handle it */ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, ibm->acpi->device->dev.bus_id, event, 0); return; } while (1) { if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { printk(IBM_ERR "failed to retrieve HKEY event\n"); return; } if (hkey == 0) { /* queue empty */ return; } send_acpi_ev = 0; ignore_acpi_ev = 0; if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { switch (hkey >> 12) { case 1: /* 0x1000-0x1FFF: key presses */ Loading @@ -1182,9 +1252,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) * eat up known LID events */ if (hkey != 0x5001 && hkey != 0x5002) { printk(IBM_ERR "unknown LID-related hotkey event: 0x%04x\n", "unknown LID-related HKEY event: 0x%04x\n", hkey); send_acpi_ev = 1; } else { ignore_acpi_ev = 1; } break; case 7: Loading @@ -1202,23 +1274,20 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); send_acpi_ev = 1; } } else { printk(IBM_ERR "unknown hotkey notification event %d\n", event); hkey = 0; send_acpi_ev = 1; } /* Legacy events */ if (send_acpi_ev || hotkey_report_mode < 2) if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); } /* netlink events */ if (send_acpi_ev) { if (!ignore_acpi_ev && send_acpi_ev) { acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, ibm->acpi->device->dev.bus_id, event, hkey); } } } static void hotkey_resume(void) { Loading Loading @@ -2812,7 +2881,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) switch(thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: res = sysfs_create_group(&tpacpi_pdev->dev.kobj, res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); if (res) return res; Loading @@ -2820,7 +2889,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_UPDT: res = sysfs_create_group(&tpacpi_pdev->dev.kobj, res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input8_group); if (res) return res; Loading @@ -2837,13 +2906,13 @@ static void thermal_exit(void) { switch(thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: sysfs_remove_group(&tpacpi_pdev->dev.kobj, sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); break; case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_UPDT: sysfs_remove_group(&tpacpi_pdev->dev.kobj, sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); break; case TPACPI_THERMAL_NONE: Loading Loading @@ -3626,7 +3695,7 @@ static struct device_attribute dev_attr_fan_fan1_input = __ATTR(fan1_input, S_IRUGO, fan_fan1_input_show, NULL); /* sysfs fan fan_watchdog (driver) ------------------------------------- */ /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ static ssize_t fan_fan_watchdog_show(struct device_driver *drv, char *buf) { Loading Loading @@ -3768,10 +3837,10 @@ static int __init fan_init(struct ibm_init_struct *iibm) if (fan_status_access_mode != TPACPI_FAN_NONE || fan_control_access_mode != TPACPI_FAN_WR_NONE) { rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); if (!(rc < 0)) rc = driver_create_file(&tpacpi_pdriver.driver, rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); if (rc < 0) return rc; Loading Loading @@ -3854,8 +3923,8 @@ static void fan_exit(void) vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); /* FIXME: can we really do this unconditionally? */ sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); cancel_delayed_work(&fan_watchdog_task); flush_scheduled_work(); Loading Loading @@ -3888,6 +3957,9 @@ static void fan_watchdog_fire(struct work_struct *ignored) { int rc; if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) return; printk(IBM_NOTICE "fan watchdog: enabling fan\n"); rc = fan_set_enable(); if (rc < 0) { Loading @@ -3908,7 +3980,8 @@ static void fan_watchdog_reset(void) if (fan_watchdog_active) cancel_delayed_work(&fan_watchdog_task); if (fan_watchdog_maxinterval > 0) { if (fan_watchdog_maxinterval > 0 && tpacpi_lifecycle != TPACPI_LIFE_EXITING) { fan_watchdog_active = 1; if (!schedule_delayed_work(&fan_watchdog_task, msecs_to_jiffies(fan_watchdog_maxinterval Loading Loading @@ -4302,6 +4375,19 @@ static struct ibm_struct fan_driver_data = { **************************************************************************** ****************************************************************************/ /* sysfs name ---------------------------------------------------------- */ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME); } static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); /* --------------------------------------------------------------------- */ /* /proc support */ static struct proc_dir_entry *proc_dir; Loading Loading @@ -4674,6 +4760,8 @@ static int __init thinkpad_acpi_module_init(void) { int ret, i; tpacpi_lifecycle = TPACPI_LIFE_INIT; /* Parameter checking */ if (hotkey_report_mode > 2) return -EINVAL; Loading Loading @@ -4702,19 +4790,31 @@ static int __init thinkpad_acpi_module_init(void) ret = platform_driver_register(&tpacpi_pdriver); if (ret) { printk(IBM_ERR "unable to register platform driver\n"); printk(IBM_ERR "unable to register main platform driver\n"); thinkpad_acpi_module_exit(); return ret; } tp_features.platform_drv_registered = 1; ret = platform_driver_register(&tpacpi_hwmon_pdriver); if (ret) { printk(IBM_ERR "unable to register hwmon platform driver\n"); thinkpad_acpi_module_exit(); return ret; } tp_features.sensors_pdrv_registered = 1; ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); if (!ret) { tp_features.platform_drv_attrs_registered = 1; ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_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; tp_features.sensors_pdrv_attrs_registered = 1; /* Device initialization */ Loading @@ -4727,7 +4827,26 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev); tpacpi_sensors_pdev = platform_device_register_simple( IBM_HWMON_DRVR_NAME, -1, NULL, 0); if (IS_ERR(tpacpi_sensors_pdev)) { ret = PTR_ERR(tpacpi_sensors_pdev); tpacpi_sensors_pdev = NULL; printk(IBM_ERR "unable to register hwmon platform device\n"); thinkpad_acpi_module_exit(); return ret; } ret = device_create_file(&tpacpi_sensors_pdev->dev, &dev_attr_thinkpad_acpi_pdev_name); if (ret) { printk(IBM_ERR "unable to create sysfs hwmon device attributes\n"); thinkpad_acpi_module_exit(); return ret; } tp_features.sensors_pdev_attrs_registered = 1; tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev); if (IS_ERR(tpacpi_hwmon)) { ret = PTR_ERR(tpacpi_hwmon); tpacpi_hwmon = NULL; Loading @@ -4735,6 +4854,7 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } mutex_init(&tpacpi_inputdev_send_mutex); tpacpi_inputdev = input_allocate_device(); if (!tpacpi_inputdev) { printk(IBM_ERR "unable to allocate input device\n"); Loading Loading @@ -4769,6 +4889,7 @@ static int __init thinkpad_acpi_module_init(void) tp_features.input_device_registered = 1; } tpacpi_lifecycle = TPACPI_LIFE_RUNNING; return 0; } Loading @@ -4776,6 +4897,8 @@ static void thinkpad_acpi_module_exit(void) { struct ibm_struct *ibm, *itmp; tpacpi_lifecycle = TPACPI_LIFE_EXITING; list_for_each_entry_safe_reverse(ibm, itmp, &tpacpi_all_drivers, all_drivers) { Loading @@ -4794,12 +4917,22 @@ static void thinkpad_acpi_module_exit(void) if (tpacpi_hwmon) hwmon_device_unregister(tpacpi_hwmon); if (tp_features.sensors_pdev_attrs_registered) device_remove_file(&tpacpi_sensors_pdev->dev, &dev_attr_thinkpad_acpi_pdev_name); if (tpacpi_sensors_pdev) platform_device_unregister(tpacpi_sensors_pdev); if (tpacpi_pdev) platform_device_unregister(tpacpi_pdev); if (tp_features.sensors_pdrv_attrs_registered) tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); if (tp_features.platform_drv_attrs_registered) tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); if (tp_features.sensors_pdrv_registered) platform_driver_unregister(&tpacpi_hwmon_pdriver); if (tp_features.platform_drv_registered) platform_driver_unregister(&tpacpi_pdriver); Loading drivers/misc/thinkpad_acpi.h +21 −16 Original line number Diff line number Diff line Loading @@ -58,13 +58,14 @@ #define IBM_NAME "thinkpad" #define IBM_DESC "ThinkPad ACPI Extras" #define IBM_FILE "thinkpad_acpi" #define IBM_FILE IBM_NAME "_acpi" #define IBM_URL "http://ibm-acpi.sf.net/" #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" #define IBM_PROC_DIR "ibm" #define IBM_ACPI_EVENT_PREFIX "ibm" #define IBM_DRVR_NAME IBM_FILE #define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" #define IBM_LOG IBM_FILE ": " #define IBM_ERR KERN_ERR IBM_LOG Loading Loading @@ -171,6 +172,7 @@ static int parse_strtoul(const char *buf, unsigned long max, /* Device model */ static struct platform_device *tpacpi_pdev; static struct platform_device *tpacpi_sensors_pdev; static struct class_device *tpacpi_hwmon; static struct platform_driver tpacpi_pdriver; static struct input_dev *tpacpi_inputdev; Loading Loading @@ -233,22 +235,25 @@ struct ibm_init_struct { static struct { #ifdef CONFIG_THINKPAD_ACPI_BAY u16 bay_status:1; u16 bay_eject:1; u16 bay_status2:1; u16 bay_eject2:1; u32 bay_status:1; u32 bay_eject:1; u32 bay_status2:1; u32 bay_eject2:1; #endif u16 bluetooth:1; u16 hotkey:1; u16 hotkey_mask:1; u16 hotkey_wlsw:1; u16 light:1; u16 light_status:1; u16 wan:1; u16 fan_ctrl_status_undef:1; u16 input_device_registered:1; u16 platform_drv_registered:1; u16 platform_drv_attrs_registered:1; u32 bluetooth:1; u32 hotkey:1; u32 hotkey_mask:1; u32 hotkey_wlsw:1; u32 light:1; u32 light_status:1; u32 wan:1; u32 fan_ctrl_status_undef:1; u32 input_device_registered:1; u32 platform_drv_registered:1; u32 platform_drv_attrs_registered:1; u32 sensors_pdrv_registered:1; u32 sensors_pdrv_attrs_registered:1; u32 sensors_pdev_attrs_registered:1; } tp_features; struct thinkpad_id_data { Loading Loading
Documentation/thinkpad-acpi.txt +19 −6 Original line number Diff line number Diff line Loading @@ -105,10 +105,15 @@ The version of thinkpad-acpi's sysfs interface is exported by the driver as a driver attribute (see below). Sysfs driver attributes are on the driver's sysfs attribute space, for 2.6.20 this is /sys/bus/platform/drivers/thinkpad_acpi/. for 2.6.23 this is /sys/bus/platform/drivers/thinkpad_acpi/ and /sys/bus/platform/drivers/thinkpad_hwmon/ Sysfs device attributes are on the driver's sysfs attribute space, for 2.6.20 this is /sys/devices/platform/thinkpad_acpi/. Sysfs device attributes are on the thinkpad_acpi device sysfs attribute space, for 2.6.23 this is /sys/devices/platform/thinkpad_acpi/. Sysfs device attributes for the sensors and fan are on the thinkpad_hwmon device's sysfs attribute space, but you should locate it looking for a hwmon device with the name attribute of "thinkpad". Driver version -------------- Loading Loading @@ -766,7 +771,7 @@ Temperature sensors ------------------- procfs: /proc/acpi/ibm/thermal sysfs device attributes: (hwmon) temp*_input sysfs device attributes: (hwmon "thinkpad") temp*_input Most ThinkPads include six or more separate temperature sensors but only expose the CPU temperature through the standard ACPI methods. This Loading Loading @@ -989,7 +994,9 @@ Fan control and monitoring: fan speed, fan enable/disable --------------------------------------------------------- procfs: /proc/acpi/ibm/fan sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable sysfs device attributes: (hwmon "thinkpad") fan1_input, pwm1, pwm1_enable sysfs hwmon driver attributes: fan_watchdog NOTE NOTE NOTE: fan control operations are disabled by default for safety reasons. To enable them, the module parameter "fan_control=1" Loading Loading @@ -1131,7 +1138,7 @@ hwmon device attribute fan1_input: which can take up to two minutes. May return rubbish on older ThinkPads. driver attribute fan_watchdog: hwmon driver attribute fan_watchdog: Fan safety watchdog timer interval, in seconds. Minimum is 1 second, maximum is 120 seconds. 0 disables the watchdog. Loading Loading @@ -1233,3 +1240,9 @@ Sysfs interface changelog: layer, the radio switch generates input event EV_RADIO, and the driver enables hot key handling by default in the firmware. 0x020000: ABI fix: added a separate hwmon platform device and driver, which must be located by name (thinkpad) and the hwmon class for libsensors4 (lm-sensors 3) compatibility. Moved all hwmon attributes to this new platform device.
drivers/misc/thinkpad_acpi.c +170 −37 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ */ #define IBM_VERSION "0.16" #define TPACPI_SYSFS_VERSION 0x010000 #define TPACPI_SYSFS_VERSION 0x020000 /* * Changelog: Loading Loading @@ -117,6 +117,12 @@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); #define __unused __attribute__ ((unused)) static enum { TPACPI_LIFE_INIT = 0, TPACPI_LIFE_RUNNING, TPACPI_LIFE_EXITING, } tpacpi_lifecycle; /**************************************************************************** **************************************************************************** * Loading Loading @@ -342,6 +348,9 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) { struct ibm_struct *ibm = data; if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) return; if (!ibm || !ibm->acpi || !ibm->acpi->notify) return; Loading Loading @@ -517,8 +526,10 @@ static char *next_cmd(char **cmds) ****************************************************************************/ static struct platform_device *tpacpi_pdev; static struct platform_device *tpacpi_sensors_pdev; static struct class_device *tpacpi_hwmon; static struct input_dev *tpacpi_inputdev; static struct mutex tpacpi_inputdev_send_mutex; static int tpacpi_resume_handler(struct platform_device *pdev) Loading @@ -543,6 +554,12 @@ static struct platform_driver tpacpi_pdriver = { .resume = tpacpi_resume_handler, }; static struct platform_driver tpacpi_hwmon_pdriver = { .driver = { .name = IBM_HWMON_DRVR_NAME, .owner = THIS_MODULE, }, }; /************************************************************************* * thinkpad-acpi driver attributes Loading Loading @@ -692,6 +709,8 @@ static int parse_strtoul(const char *buf, { char *endp; while (*buf && isspace(*buf)) buf++; *value = simple_strtoul(buf, &endp, 0); while (*endp && isspace(*endp)) endp++; Loading Loading @@ -989,6 +1008,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) int res, i; int status; int hkeyv; vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); Loading @@ -1014,19 +1034,36 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) return res; /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, A30, R30, R31, T20-22, X20-21, X22-24 */ tp_features.hotkey_mask = acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking for HKEY interface version 0x100 */ if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { if ((hkeyv >> 8) != 1) { printk(IBM_ERR "unknown version of the " "HKEY interface: 0x%x\n", hkeyv); printk(IBM_ERR "please report this to %s\n", IBM_MAIL); } else { /* * MHKV 0x100 in A31, R40, R40e, * T4x, X31, and later * */ tp_features.hotkey_mask = 1; } } 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")) "MHKA", "qd")) { printk(IBM_ERR "missing MHKA handler, " "please report this to %s\n", IBM_MAIL); 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) { Loading Loading @@ -1131,6 +1168,8 @@ static void tpacpi_input_send_key(unsigned int scancode, unsigned int keycode) { if (keycode != KEY_RESERVED) { mutex_lock(&tpacpi_inputdev_send_mutex); input_report_key(tpacpi_inputdev, keycode, 1); if (keycode == KEY_UNKNOWN) input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, Loading @@ -1142,6 +1181,8 @@ static void tpacpi_input_send_key(unsigned int scancode, input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); } } Loading @@ -1149,18 +1190,47 @@ static void tpacpi_input_send_radiosw(void) { int wlsw; if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) mutex_lock(&tpacpi_inputdev_send_mutex); if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { input_report_switch(tpacpi_inputdev, SW_RADIO, !!wlsw); input_sync(tpacpi_inputdev); } mutex_unlock(&tpacpi_inputdev_send_mutex); } static void hotkey_notify(struct ibm_struct *ibm, u32 event) { u32 hkey; unsigned int keycode, scancode; int send_acpi_ev = 0; int send_acpi_ev; int ignore_acpi_ev; if (event != 0x80) { printk(IBM_ERR "unknown HKEY notification event %d\n", event); /* forward it to userspace, maybe it knows how to handle it */ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, ibm->acpi->device->dev.bus_id, event, 0); return; } while (1) { if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { printk(IBM_ERR "failed to retrieve HKEY event\n"); return; } if (hkey == 0) { /* queue empty */ return; } send_acpi_ev = 0; ignore_acpi_ev = 0; if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { switch (hkey >> 12) { case 1: /* 0x1000-0x1FFF: key presses */ Loading @@ -1182,9 +1252,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) * eat up known LID events */ if (hkey != 0x5001 && hkey != 0x5002) { printk(IBM_ERR "unknown LID-related hotkey event: 0x%04x\n", "unknown LID-related HKEY event: 0x%04x\n", hkey); send_acpi_ev = 1; } else { ignore_acpi_ev = 1; } break; case 7: Loading @@ -1202,23 +1274,20 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); send_acpi_ev = 1; } } else { printk(IBM_ERR "unknown hotkey notification event %d\n", event); hkey = 0; send_acpi_ev = 1; } /* Legacy events */ if (send_acpi_ev || hotkey_report_mode < 2) if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); } /* netlink events */ if (send_acpi_ev) { if (!ignore_acpi_ev && send_acpi_ev) { acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, ibm->acpi->device->dev.bus_id, event, hkey); } } } static void hotkey_resume(void) { Loading Loading @@ -2812,7 +2881,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) switch(thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: res = sysfs_create_group(&tpacpi_pdev->dev.kobj, res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); if (res) return res; Loading @@ -2820,7 +2889,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_UPDT: res = sysfs_create_group(&tpacpi_pdev->dev.kobj, res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input8_group); if (res) return res; Loading @@ -2837,13 +2906,13 @@ static void thermal_exit(void) { switch(thermal_read_mode) { case TPACPI_THERMAL_TPEC_16: sysfs_remove_group(&tpacpi_pdev->dev.kobj, sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); break; case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_UPDT: sysfs_remove_group(&tpacpi_pdev->dev.kobj, sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &thermal_temp_input16_group); break; case TPACPI_THERMAL_NONE: Loading Loading @@ -3626,7 +3695,7 @@ static struct device_attribute dev_attr_fan_fan1_input = __ATTR(fan1_input, S_IRUGO, fan_fan1_input_show, NULL); /* sysfs fan fan_watchdog (driver) ------------------------------------- */ /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ static ssize_t fan_fan_watchdog_show(struct device_driver *drv, char *buf) { Loading Loading @@ -3768,10 +3837,10 @@ static int __init fan_init(struct ibm_init_struct *iibm) if (fan_status_access_mode != TPACPI_FAN_NONE || fan_control_access_mode != TPACPI_FAN_WR_NONE) { rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); if (!(rc < 0)) rc = driver_create_file(&tpacpi_pdriver.driver, rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); if (rc < 0) return rc; Loading Loading @@ -3854,8 +3923,8 @@ static void fan_exit(void) vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); /* FIXME: can we really do this unconditionally? */ sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); cancel_delayed_work(&fan_watchdog_task); flush_scheduled_work(); Loading Loading @@ -3888,6 +3957,9 @@ static void fan_watchdog_fire(struct work_struct *ignored) { int rc; if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) return; printk(IBM_NOTICE "fan watchdog: enabling fan\n"); rc = fan_set_enable(); if (rc < 0) { Loading @@ -3908,7 +3980,8 @@ static void fan_watchdog_reset(void) if (fan_watchdog_active) cancel_delayed_work(&fan_watchdog_task); if (fan_watchdog_maxinterval > 0) { if (fan_watchdog_maxinterval > 0 && tpacpi_lifecycle != TPACPI_LIFE_EXITING) { fan_watchdog_active = 1; if (!schedule_delayed_work(&fan_watchdog_task, msecs_to_jiffies(fan_watchdog_maxinterval Loading Loading @@ -4302,6 +4375,19 @@ static struct ibm_struct fan_driver_data = { **************************************************************************** ****************************************************************************/ /* sysfs name ---------------------------------------------------------- */ static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME); } static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); /* --------------------------------------------------------------------- */ /* /proc support */ static struct proc_dir_entry *proc_dir; Loading Loading @@ -4674,6 +4760,8 @@ static int __init thinkpad_acpi_module_init(void) { int ret, i; tpacpi_lifecycle = TPACPI_LIFE_INIT; /* Parameter checking */ if (hotkey_report_mode > 2) return -EINVAL; Loading Loading @@ -4702,19 +4790,31 @@ static int __init thinkpad_acpi_module_init(void) ret = platform_driver_register(&tpacpi_pdriver); if (ret) { printk(IBM_ERR "unable to register platform driver\n"); printk(IBM_ERR "unable to register main platform driver\n"); thinkpad_acpi_module_exit(); return ret; } tp_features.platform_drv_registered = 1; ret = platform_driver_register(&tpacpi_hwmon_pdriver); if (ret) { printk(IBM_ERR "unable to register hwmon platform driver\n"); thinkpad_acpi_module_exit(); return ret; } tp_features.sensors_pdrv_registered = 1; ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); if (!ret) { tp_features.platform_drv_attrs_registered = 1; ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_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; tp_features.sensors_pdrv_attrs_registered = 1; /* Device initialization */ Loading @@ -4727,7 +4827,26 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev); tpacpi_sensors_pdev = platform_device_register_simple( IBM_HWMON_DRVR_NAME, -1, NULL, 0); if (IS_ERR(tpacpi_sensors_pdev)) { ret = PTR_ERR(tpacpi_sensors_pdev); tpacpi_sensors_pdev = NULL; printk(IBM_ERR "unable to register hwmon platform device\n"); thinkpad_acpi_module_exit(); return ret; } ret = device_create_file(&tpacpi_sensors_pdev->dev, &dev_attr_thinkpad_acpi_pdev_name); if (ret) { printk(IBM_ERR "unable to create sysfs hwmon device attributes\n"); thinkpad_acpi_module_exit(); return ret; } tp_features.sensors_pdev_attrs_registered = 1; tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev); if (IS_ERR(tpacpi_hwmon)) { ret = PTR_ERR(tpacpi_hwmon); tpacpi_hwmon = NULL; Loading @@ -4735,6 +4854,7 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } mutex_init(&tpacpi_inputdev_send_mutex); tpacpi_inputdev = input_allocate_device(); if (!tpacpi_inputdev) { printk(IBM_ERR "unable to allocate input device\n"); Loading Loading @@ -4769,6 +4889,7 @@ static int __init thinkpad_acpi_module_init(void) tp_features.input_device_registered = 1; } tpacpi_lifecycle = TPACPI_LIFE_RUNNING; return 0; } Loading @@ -4776,6 +4897,8 @@ static void thinkpad_acpi_module_exit(void) { struct ibm_struct *ibm, *itmp; tpacpi_lifecycle = TPACPI_LIFE_EXITING; list_for_each_entry_safe_reverse(ibm, itmp, &tpacpi_all_drivers, all_drivers) { Loading @@ -4794,12 +4917,22 @@ static void thinkpad_acpi_module_exit(void) if (tpacpi_hwmon) hwmon_device_unregister(tpacpi_hwmon); if (tp_features.sensors_pdev_attrs_registered) device_remove_file(&tpacpi_sensors_pdev->dev, &dev_attr_thinkpad_acpi_pdev_name); if (tpacpi_sensors_pdev) platform_device_unregister(tpacpi_sensors_pdev); if (tpacpi_pdev) platform_device_unregister(tpacpi_pdev); if (tp_features.sensors_pdrv_attrs_registered) tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); if (tp_features.platform_drv_attrs_registered) tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); if (tp_features.sensors_pdrv_registered) platform_driver_unregister(&tpacpi_hwmon_pdriver); if (tp_features.platform_drv_registered) platform_driver_unregister(&tpacpi_pdriver); Loading
drivers/misc/thinkpad_acpi.h +21 −16 Original line number Diff line number Diff line Loading @@ -58,13 +58,14 @@ #define IBM_NAME "thinkpad" #define IBM_DESC "ThinkPad ACPI Extras" #define IBM_FILE "thinkpad_acpi" #define IBM_FILE IBM_NAME "_acpi" #define IBM_URL "http://ibm-acpi.sf.net/" #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" #define IBM_PROC_DIR "ibm" #define IBM_ACPI_EVENT_PREFIX "ibm" #define IBM_DRVR_NAME IBM_FILE #define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" #define IBM_LOG IBM_FILE ": " #define IBM_ERR KERN_ERR IBM_LOG Loading Loading @@ -171,6 +172,7 @@ static int parse_strtoul(const char *buf, unsigned long max, /* Device model */ static struct platform_device *tpacpi_pdev; static struct platform_device *tpacpi_sensors_pdev; static struct class_device *tpacpi_hwmon; static struct platform_driver tpacpi_pdriver; static struct input_dev *tpacpi_inputdev; Loading Loading @@ -233,22 +235,25 @@ struct ibm_init_struct { static struct { #ifdef CONFIG_THINKPAD_ACPI_BAY u16 bay_status:1; u16 bay_eject:1; u16 bay_status2:1; u16 bay_eject2:1; u32 bay_status:1; u32 bay_eject:1; u32 bay_status2:1; u32 bay_eject2:1; #endif u16 bluetooth:1; u16 hotkey:1; u16 hotkey_mask:1; u16 hotkey_wlsw:1; u16 light:1; u16 light_status:1; u16 wan:1; u16 fan_ctrl_status_undef:1; u16 input_device_registered:1; u16 platform_drv_registered:1; u16 platform_drv_attrs_registered:1; u32 bluetooth:1; u32 hotkey:1; u32 hotkey_mask:1; u32 hotkey_wlsw:1; u32 light:1; u32 light_status:1; u32 wan:1; u32 fan_ctrl_status_undef:1; u32 input_device_registered:1; u32 platform_drv_registered:1; u32 platform_drv_attrs_registered:1; u32 sensors_pdrv_registered:1; u32 sensors_pdrv_attrs_registered:1; u32 sensors_pdev_attrs_registered:1; } tp_features; struct thinkpad_id_data { Loading