Pull thinkpad into release branch

This commit is contained in:
Len Brown 2007-10-10 00:28:04 -04:00
commit bf0a40b77a
3 changed files with 210 additions and 59 deletions

View file

@ -105,10 +105,15 @@ The version of thinkpad-acpi's sysfs interface is exported by the driver
as a driver attribute (see below). as a driver attribute (see below).
Sysfs driver attributes are on the driver's sysfs attribute space, 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, Sysfs device attributes are on the thinkpad_acpi device sysfs attribute
for 2.6.20 this is /sys/devices/platform/thinkpad_acpi/. 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 Driver version
-------------- --------------
@ -766,7 +771,7 @@ Temperature sensors
------------------- -------------------
procfs: /proc/acpi/ibm/thermal 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 Most ThinkPads include six or more separate temperature sensors but only
expose the CPU temperature through the standard ACPI methods. This expose the CPU temperature through the standard ACPI methods. This
@ -989,7 +994,9 @@ Fan control and monitoring: fan speed, fan enable/disable
--------------------------------------------------------- ---------------------------------------------------------
procfs: /proc/acpi/ibm/fan 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 NOTE NOTE NOTE: fan control operations are disabled by default for
safety reasons. To enable them, the module parameter "fan_control=1" safety reasons. To enable them, the module parameter "fan_control=1"
@ -1131,7 +1138,7 @@ hwmon device attribute fan1_input:
which can take up to two minutes. May return rubbish on older which can take up to two minutes. May return rubbish on older
ThinkPads. ThinkPads.
driver attribute fan_watchdog: hwmon driver attribute fan_watchdog:
Fan safety watchdog timer interval, in seconds. Minimum is Fan safety watchdog timer interval, in seconds. Minimum is
1 second, maximum is 120 seconds. 0 disables the watchdog. 1 second, maximum is 120 seconds. 0 disables the watchdog.
@ -1233,3 +1240,9 @@ Sysfs interface changelog:
layer, the radio switch generates input event EV_RADIO, layer, the radio switch generates input event EV_RADIO,
and the driver enables hot key handling by default in and the driver enables hot key handling by default in
the firmware. 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.

View file

@ -22,7 +22,7 @@
*/ */
#define IBM_VERSION "0.16" #define IBM_VERSION "0.16"
#define TPACPI_SYSFS_VERSION 0x010000 #define TPACPI_SYSFS_VERSION 0x020000
/* /*
* Changelog: * Changelog:
@ -117,6 +117,12 @@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
#define __unused __attribute__ ((unused)) #define __unused __attribute__ ((unused))
static enum {
TPACPI_LIFE_INIT = 0,
TPACPI_LIFE_RUNNING,
TPACPI_LIFE_EXITING,
} tpacpi_lifecycle;
/**************************************************************************** /****************************************************************************
**************************************************************************** ****************************************************************************
* *
@ -342,6 +348,9 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
{ {
struct ibm_struct *ibm = data; struct ibm_struct *ibm = data;
if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
return;
if (!ibm || !ibm->acpi || !ibm->acpi->notify) if (!ibm || !ibm->acpi || !ibm->acpi->notify)
return; return;
@ -517,8 +526,10 @@ static char *next_cmd(char **cmds)
****************************************************************************/ ****************************************************************************/
static struct platform_device *tpacpi_pdev; static struct platform_device *tpacpi_pdev;
static struct platform_device *tpacpi_sensors_pdev;
static struct class_device *tpacpi_hwmon; static struct class_device *tpacpi_hwmon;
static struct input_dev *tpacpi_inputdev; static struct input_dev *tpacpi_inputdev;
static struct mutex tpacpi_inputdev_send_mutex;
static int tpacpi_resume_handler(struct platform_device *pdev) static int tpacpi_resume_handler(struct platform_device *pdev)
@ -543,6 +554,12 @@ static struct platform_driver tpacpi_pdriver = {
.resume = tpacpi_resume_handler, .resume = tpacpi_resume_handler,
}; };
static struct platform_driver tpacpi_hwmon_pdriver = {
.driver = {
.name = IBM_HWMON_DRVR_NAME,
.owner = THIS_MODULE,
},
};
/************************************************************************* /*************************************************************************
* thinkpad-acpi driver attributes * thinkpad-acpi driver attributes
@ -692,6 +709,8 @@ static int parse_strtoul(const char *buf,
{ {
char *endp; char *endp;
while (*buf && isspace(*buf))
buf++;
*value = simple_strtoul(buf, &endp, 0); *value = simple_strtoul(buf, &endp, 0);
while (*endp && isspace(*endp)) while (*endp && isspace(*endp))
endp++; endp++;
@ -989,6 +1008,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
int res, i; int res, i;
int status; int status;
int hkeyv;
vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
@ -1014,18 +1034,35 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
return res; return res;
/* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
A30, R30, R31, T20-22, X20-21, X22-24 */ A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking
tp_features.hotkey_mask = for HKEY interface version 0x100 */
acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); 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", vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
str_supported(tp_features.hotkey_mask)); str_supported(tp_features.hotkey_mask));
if (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, 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 */ hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
}
} }
res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
@ -1131,6 +1168,8 @@ static void tpacpi_input_send_key(unsigned int scancode,
unsigned int keycode) unsigned int keycode)
{ {
if (keycode != KEY_RESERVED) { if (keycode != KEY_RESERVED) {
mutex_lock(&tpacpi_inputdev_send_mutex);
input_report_key(tpacpi_inputdev, keycode, 1); input_report_key(tpacpi_inputdev, keycode, 1);
if (keycode == KEY_UNKNOWN) if (keycode == KEY_UNKNOWN)
input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
@ -1142,6 +1181,8 @@ static void tpacpi_input_send_key(unsigned int scancode,
input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
scancode); scancode);
input_sync(tpacpi_inputdev); input_sync(tpacpi_inputdev);
mutex_unlock(&tpacpi_inputdev_send_mutex);
} }
} }
@ -1149,18 +1190,47 @@ static void tpacpi_input_send_radiosw(void)
{ {
int wlsw; 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, input_report_switch(tpacpi_inputdev,
SW_RADIO, !!wlsw); SW_RADIO, !!wlsw);
input_sync(tpacpi_inputdev);
}
mutex_unlock(&tpacpi_inputdev_send_mutex);
} }
static void hotkey_notify(struct ibm_struct *ibm, u32 event) static void hotkey_notify(struct ibm_struct *ibm, u32 event)
{ {
u32 hkey; u32 hkey;
unsigned int keycode, scancode; 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) { switch (hkey >> 12) {
case 1: case 1:
/* 0x1000-0x1FFF: key presses */ /* 0x1000-0x1FFF: key presses */
@ -1182,9 +1252,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
* eat up known LID events */ * eat up known LID events */
if (hkey != 0x5001 && hkey != 0x5002) { if (hkey != 0x5001 && hkey != 0x5002) {
printk(IBM_ERR printk(IBM_ERR
"unknown LID-related hotkey event: 0x%04x\n", "unknown LID-related HKEY event: 0x%04x\n",
hkey); hkey);
send_acpi_ev = 1; send_acpi_ev = 1;
} else {
ignore_acpi_ev = 1;
} }
break; break;
case 7: case 7:
@ -1202,21 +1274,18 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
send_acpi_ev = 1; send_acpi_ev = 1;
} }
} else {
printk(IBM_ERR "unknown hotkey notification event %d\n", event);
hkey = 0;
send_acpi_ev = 1;
}
/* Legacy events */ /* 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); acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
}
/* netlink events */ /* netlink events */
if (send_acpi_ev) { if (!ignore_acpi_ev && send_acpi_ev) {
acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
ibm->acpi->device->dev.bus_id, ibm->acpi->device->dev.bus_id,
event, hkey); event, hkey);
}
} }
} }
@ -2812,7 +2881,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
switch(thermal_read_mode) { switch(thermal_read_mode) {
case TPACPI_THERMAL_TPEC_16: 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); &thermal_temp_input16_group);
if (res) if (res)
return res; return res;
@ -2820,7 +2889,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_TPEC_8:
case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_TMP07:
case TPACPI_THERMAL_ACPI_UPDT: 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); &thermal_temp_input8_group);
if (res) if (res)
return res; return res;
@ -2837,13 +2906,13 @@ static void thermal_exit(void)
{ {
switch(thermal_read_mode) { switch(thermal_read_mode) {
case TPACPI_THERMAL_TPEC_16: case TPACPI_THERMAL_TPEC_16:
sysfs_remove_group(&tpacpi_pdev->dev.kobj, sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input16_group); &thermal_temp_input16_group);
break; break;
case TPACPI_THERMAL_TPEC_8: case TPACPI_THERMAL_TPEC_8:
case TPACPI_THERMAL_ACPI_TMP07: case TPACPI_THERMAL_ACPI_TMP07:
case TPACPI_THERMAL_ACPI_UPDT: case TPACPI_THERMAL_ACPI_UPDT:
sysfs_remove_group(&tpacpi_pdev->dev.kobj, sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input16_group); &thermal_temp_input16_group);
break; break;
case TPACPI_THERMAL_NONE: case TPACPI_THERMAL_NONE:
@ -3626,7 +3695,7 @@ static struct device_attribute dev_attr_fan_fan1_input =
__ATTR(fan1_input, S_IRUGO, __ATTR(fan1_input, S_IRUGO,
fan_fan1_input_show, NULL); 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, static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
char *buf) char *buf)
{ {
@ -3768,10 +3837,10 @@ static int __init fan_init(struct ibm_init_struct *iibm)
if (fan_status_access_mode != TPACPI_FAN_NONE || if (fan_status_access_mode != TPACPI_FAN_NONE ||
fan_control_access_mode != TPACPI_FAN_WR_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); &fan_attr_group);
if (!(rc < 0)) if (!(rc < 0))
rc = driver_create_file(&tpacpi_pdriver.driver, rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
&driver_attr_fan_watchdog); &driver_attr_fan_watchdog);
if (rc < 0) if (rc < 0)
return rc; return rc;
@ -3854,8 +3923,8 @@ static void fan_exit(void)
vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
/* FIXME: can we really do this unconditionally? */ /* FIXME: can we really do this unconditionally? */
sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog);
cancel_delayed_work(&fan_watchdog_task); cancel_delayed_work(&fan_watchdog_task);
flush_scheduled_work(); flush_scheduled_work();
@ -3888,6 +3957,9 @@ static void fan_watchdog_fire(struct work_struct *ignored)
{ {
int rc; int rc;
if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
return;
printk(IBM_NOTICE "fan watchdog: enabling fan\n"); printk(IBM_NOTICE "fan watchdog: enabling fan\n");
rc = fan_set_enable(); rc = fan_set_enable();
if (rc < 0) { if (rc < 0) {
@ -3908,7 +3980,8 @@ static void fan_watchdog_reset(void)
if (fan_watchdog_active) if (fan_watchdog_active)
cancel_delayed_work(&fan_watchdog_task); 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; fan_watchdog_active = 1;
if (!schedule_delayed_work(&fan_watchdog_task, if (!schedule_delayed_work(&fan_watchdog_task,
msecs_to_jiffies(fan_watchdog_maxinterval msecs_to_jiffies(fan_watchdog_maxinterval
@ -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 */ /* /proc support */
static struct proc_dir_entry *proc_dir; static struct proc_dir_entry *proc_dir;
@ -4674,6 +4760,8 @@ static int __init thinkpad_acpi_module_init(void)
{ {
int ret, i; int ret, i;
tpacpi_lifecycle = TPACPI_LIFE_INIT;
/* Parameter checking */ /* Parameter checking */
if (hotkey_report_mode > 2) if (hotkey_report_mode > 2)
return -EINVAL; return -EINVAL;
@ -4702,19 +4790,31 @@ static int __init thinkpad_acpi_module_init(void)
ret = platform_driver_register(&tpacpi_pdriver); ret = platform_driver_register(&tpacpi_pdriver);
if (ret) { 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(); thinkpad_acpi_module_exit();
return ret; return ret;
} }
tp_features.platform_drv_registered = 1; 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); 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) { if (ret) {
printk(IBM_ERR "unable to create sysfs driver attributes\n"); printk(IBM_ERR "unable to create sysfs driver attributes\n");
thinkpad_acpi_module_exit(); thinkpad_acpi_module_exit();
return ret; return ret;
} }
tp_features.platform_drv_attrs_registered = 1; tp_features.sensors_pdrv_attrs_registered = 1;
/* Device initialization */ /* Device initialization */
@ -4727,7 +4827,26 @@ static int __init thinkpad_acpi_module_init(void)
thinkpad_acpi_module_exit(); thinkpad_acpi_module_exit();
return ret; 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)) { if (IS_ERR(tpacpi_hwmon)) {
ret = PTR_ERR(tpacpi_hwmon); ret = PTR_ERR(tpacpi_hwmon);
tpacpi_hwmon = NULL; tpacpi_hwmon = NULL;
@ -4735,6 +4854,7 @@ static int __init thinkpad_acpi_module_init(void)
thinkpad_acpi_module_exit(); thinkpad_acpi_module_exit();
return ret; return ret;
} }
mutex_init(&tpacpi_inputdev_send_mutex);
tpacpi_inputdev = input_allocate_device(); tpacpi_inputdev = input_allocate_device();
if (!tpacpi_inputdev) { if (!tpacpi_inputdev) {
printk(IBM_ERR "unable to allocate input device\n"); printk(IBM_ERR "unable to allocate input device\n");
@ -4769,6 +4889,7 @@ static int __init thinkpad_acpi_module_init(void)
tp_features.input_device_registered = 1; tp_features.input_device_registered = 1;
} }
tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
return 0; return 0;
} }
@ -4776,6 +4897,8 @@ static void thinkpad_acpi_module_exit(void)
{ {
struct ibm_struct *ibm, *itmp; struct ibm_struct *ibm, *itmp;
tpacpi_lifecycle = TPACPI_LIFE_EXITING;
list_for_each_entry_safe_reverse(ibm, itmp, list_for_each_entry_safe_reverse(ibm, itmp,
&tpacpi_all_drivers, &tpacpi_all_drivers,
all_drivers) { all_drivers) {
@ -4794,12 +4917,22 @@ static void thinkpad_acpi_module_exit(void)
if (tpacpi_hwmon) if (tpacpi_hwmon)
hwmon_device_unregister(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) if (tpacpi_pdev)
platform_device_unregister(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) if (tp_features.platform_drv_attrs_registered)
tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); 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) if (tp_features.platform_drv_registered)
platform_driver_unregister(&tpacpi_pdriver); platform_driver_unregister(&tpacpi_pdriver);

View file

@ -58,13 +58,14 @@
#define IBM_NAME "thinkpad" #define IBM_NAME "thinkpad"
#define IBM_DESC "ThinkPad ACPI Extras" #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_URL "http://ibm-acpi.sf.net/"
#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
#define IBM_PROC_DIR "ibm" #define IBM_PROC_DIR "ibm"
#define IBM_ACPI_EVENT_PREFIX "ibm" #define IBM_ACPI_EVENT_PREFIX "ibm"
#define IBM_DRVR_NAME IBM_FILE #define IBM_DRVR_NAME IBM_FILE
#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon"
#define IBM_LOG IBM_FILE ": " #define IBM_LOG IBM_FILE ": "
#define IBM_ERR KERN_ERR IBM_LOG #define IBM_ERR KERN_ERR IBM_LOG
@ -171,6 +172,7 @@ static int parse_strtoul(const char *buf, unsigned long max,
/* Device model */ /* Device model */
static struct platform_device *tpacpi_pdev; static struct platform_device *tpacpi_pdev;
static struct platform_device *tpacpi_sensors_pdev;
static struct class_device *tpacpi_hwmon; static struct class_device *tpacpi_hwmon;
static struct platform_driver tpacpi_pdriver; static struct platform_driver tpacpi_pdriver;
static struct input_dev *tpacpi_inputdev; static struct input_dev *tpacpi_inputdev;
@ -233,22 +235,25 @@ struct ibm_init_struct {
static struct { static struct {
#ifdef CONFIG_THINKPAD_ACPI_BAY #ifdef CONFIG_THINKPAD_ACPI_BAY
u16 bay_status:1; u32 bay_status:1;
u16 bay_eject:1; u32 bay_eject:1;
u16 bay_status2:1; u32 bay_status2:1;
u16 bay_eject2:1; u32 bay_eject2:1;
#endif #endif
u16 bluetooth:1; u32 bluetooth:1;
u16 hotkey:1; u32 hotkey:1;
u16 hotkey_mask:1; u32 hotkey_mask:1;
u16 hotkey_wlsw:1; u32 hotkey_wlsw:1;
u16 light:1; u32 light:1;
u16 light_status:1; u32 light_status:1;
u16 wan:1; u32 wan:1;
u16 fan_ctrl_status_undef:1; u32 fan_ctrl_status_undef:1;
u16 input_device_registered:1; u32 input_device_registered:1;
u16 platform_drv_registered:1; u32 platform_drv_registered:1;
u16 platform_drv_attrs_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; } tp_features;
struct thinkpad_id_data { struct thinkpad_id_data {