Pull thinkpad into release branch
This commit is contained in:
commit
bf0a40b77a
3 changed files with 210 additions and 59 deletions
|
@ -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.
|
||||||
|
|
|
@ -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,19 +1034,36 @@ 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);
|
||||||
if (!res && tp_features.hotkey_mask) {
|
if (!res && tp_features.hotkey_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,22 +1274,19 @@ 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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hotkey_resume(void)
|
static void hotkey_resume(void)
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Reference in a new issue