* 02110-1301, USA.
*/
-#define IBM_VERSION "0.16"
-#define TPACPI_SYSFS_VERSION 0x010000
+#define IBM_VERSION "0.17"
+#define TPACPI_SYSFS_VERSION 0x020000
/*
* Changelog:
#define __unused __attribute__ ((unused))
+static enum {
+ TPACPI_LIFE_INIT = 0,
+ TPACPI_LIFE_RUNNING,
+ TPACPI_LIFE_EXITING,
+} tpacpi_lifecycle;
+
/****************************************************************************
****************************************************************************
*
{
struct ibm_struct *ibm = data;
+ if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+ return;
+
if (!ibm || !ibm->acpi || !ibm->acpi->notify)
return;
****************************************************************************/
static struct platform_device *tpacpi_pdev;
-static struct class_device *tpacpi_hwmon;
+static struct platform_device *tpacpi_sensors_pdev;
+static struct 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)
.resume = tpacpi_resume_handler,
};
+static struct platform_driver tpacpi_hwmon_pdriver = {
+ .driver = {
+ .name = IBM_HWMON_DRVR_NAME,
+ .owner = THIS_MODULE,
+ },
+};
/*************************************************************************
* thinkpad-acpi driver attributes
{
char *endp;
+ while (*buf && isspace(*buf))
+ buf++;
*value = simple_strtoul(buf, &endp, 0);
while (*endp && isspace(*endp))
endp++;
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
- KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
+ KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
- KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
+ 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) */
int res, i;
int status;
+ int hkeyv;
vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
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);
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,
input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
scancode);
input_sync(tpacpi_inputdev);
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
}
}
{
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 */
* eat up known LID events */
if (hkey != 0x5001 && hkey != 0x5002) {
printk(IBM_ERR
- "unknown LID-related hotkey event: 0x%04x\n",
- hkey);
+ "unknown LID-related HKEY event: 0x%04x\n",
+ hkey);
send_acpi_ev = 1;
+ } else {
+ ignore_acpi_ev = 1;
}
break;
case 7:
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)
- acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+ /* Legacy events */
+ 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) {
- acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- ibm->acpi->device->dev.bus_id,
- event, hkey);
+ /* netlink events */
+ 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);
+ }
}
}
return len;
}
- res = mutex_lock_interruptible(&hotkey_mutex);
- if (res < 0)
- return res;
+ if (mutex_lock_interruptible(&hotkey_mutex))
+ return -ERESTARTSYS;
res = hotkey_get(&status, &mask);
mutex_unlock(&hotkey_mutex);
if (res)
if (!tp_features.hotkey)
return -ENODEV;
- res = mutex_lock_interruptible(&hotkey_mutex);
- if (res < 0)
- return res;
+ if (mutex_lock_interruptible(&hotkey_mutex))
+ return -ERESTARTSYS;
res = hotkey_get(&status, &mask);
if (res)
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;
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;
{
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:
static struct mutex brightness_mutex;
+static int __init tpacpi_query_bcll_levels(acpi_handle handle)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ int rc;
+
+ if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
+ obj = (union acpi_object *)buffer.pointer;
+ if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+ printk(IBM_ERR "Unknown BCLL data, "
+ "please report this to %s\n", IBM_MAIL);
+ rc = 0;
+ } else {
+ rc = obj->package.count;
+ }
+ } else {
+ return 0;
+ }
+
+ kfree(buffer.pointer);
+ return rc;
+}
+
+static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ char name[ACPI_PATH_SEGMENT_LENGTH];
+ struct acpi_buffer buffer = { sizeof(name), &name };
+
+ if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+ !strncmp("BCLL", name, sizeof(name) - 1)) {
+ if (tpacpi_query_bcll_levels(handle) == 16) {
+ *rv = handle;
+ return AE_CTRL_TERMINATE;
+ } else {
+ return AE_OK;
+ }
+ } else {
+ return AE_OK;
+ }
+}
+
+static int __init brightness_check_levels(void)
+{
+ int status;
+ void *found_node = NULL;
+
+ if (!vid_handle) {
+ IBM_ACPIHANDLE_INIT(vid);
+ }
+ if (!vid_handle)
+ return 0;
+
+ /* Search for a BCLL package with 16 levels */
+ status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
+ brightness_find_bcll, NULL, &found_node);
+
+ return (ACPI_SUCCESS(status) && found_node != NULL);
+}
+
+static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ char name[ACPI_PATH_SEGMENT_LENGTH];
+ struct acpi_buffer buffer = { sizeof(name), &name };
+
+ if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+ !strncmp("_BCL", name, sizeof(name) - 1)) {
+ *rv = handle;
+ return AE_CTRL_TERMINATE;
+ } else {
+ return AE_OK;
+ }
+}
+
+static int __init brightness_check_std_acpi_support(void)
+{
+ int status;
+ void *found_node = NULL;
+
+ if (!vid_handle) {
+ IBM_ACPIHANDLE_INIT(vid);
+ }
+ if (!vid_handle)
+ return 0;
+
+ /* Search for a _BCL method, but don't execute it */
+ status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
+ brightness_find_bcl, NULL, &found_node);
+
+ return (ACPI_SUCCESS(status) && found_node != NULL);
+}
+
static int __init brightness_init(struct ibm_init_struct *iibm)
{
int b;
mutex_init(&brightness_mutex);
+ if (!brightness_enable) {
+ dbg_printk(TPACPI_DBG_INIT,
+ "brightness support disabled by module parameter\n");
+ return 1;
+ } else if (brightness_enable > 1) {
+ if (brightness_check_std_acpi_support()) {
+ printk(IBM_NOTICE
+ "standard ACPI backlight interface available, not loading native one...\n");
+ return 1;
+ }
+ }
+
if (!brightness_mode) {
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
brightness_mode = 2;
if (brightness_mode > 3)
return -EINVAL;
+ tp_features.bright_16levels =
+ thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
+ brightness_check_levels();
+
b = brightness_get(NULL);
if (b < 0)
return 1;
+ if (tp_features.bright_16levels)
+ printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n");
+
ibm_backlight_device = backlight_device_register(
TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
&ibm_backlight_data);
}
vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
- ibm_backlight_device->props.max_brightness = 7;
+ ibm_backlight_device->props.max_brightness =
+ (tp_features.bright_16levels)? 15 : 7;
ibm_backlight_device->props.brightness = b;
backlight_update_status(ibm_backlight_device);
static int brightness_update_status(struct backlight_device *bd)
{
+ /* it is the backlight class's job (caller) to handle
+ * EINTR and other errors properly */
return brightness_set(
(bd->props.fb_blank == FB_BLANK_UNBLANK &&
bd->props.power == FB_BLANK_UNBLANK) ?
if (brightness_mode & 1) {
if (!acpi_ec_read(brightness_offset, &lec))
return -EIO;
- lec &= 7;
+ lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
level = lec;
};
if (brightness_mode & 2) {
lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
& TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+ lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
level = lcmos;
}
return level;
}
+/* May return EINTR which can always be mapped to ERESTARTSYS */
static int brightness_set(int value)
{
int cmos_cmd, inc, i, res;
int current_value;
- if (value > 7)
+ if (value > ((tp_features.bright_16levels)? 15 : 7))
return -EINVAL;
res = mutex_lock_interruptible(&brightness_mutex);
cmos_cmd = value > current_value ?
TP_CMOS_BRIGHTNESS_UP :
TP_CMOS_BRIGHTNESS_DOWN;
- inc = value > current_value ? 1 : -1;
+ inc = (value > current_value)? 1 : -1;
res = 0;
for (i = current_value; i != value; i += inc) {
if ((level = brightness_get(NULL)) < 0) {
len += sprintf(p + len, "level:\t\tunreadable\n");
} else {
- len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
+ len += sprintf(p + len, "level:\t\t%d\n", level);
len += sprintf(p + len, "commands:\tup, down\n");
len += sprintf(p + len, "commands:\tlevel <level>"
- " (<level> is 0-7)\n");
+ " (<level> is 0-%d)\n",
+ (tp_features.bright_16levels) ? 15 : 7);
}
return len;
static int brightness_write(char *buf)
{
int level;
- int new_level;
+ int rc;
char *cmd;
+ int max_level = (tp_features.bright_16levels) ? 15 : 7;
- while ((cmd = next_cmd(&buf))) {
- if ((level = brightness_get(NULL)) < 0)
- return level;
- level &= 7;
+ level = brightness_get(NULL);
+ if (level < 0)
+ return level;
+ while ((cmd = next_cmd(&buf))) {
if (strlencmp(cmd, "up") == 0) {
- new_level = level == 7 ? 7 : level + 1;
+ if (level < max_level)
+ level++;
} else if (strlencmp(cmd, "down") == 0) {
- new_level = level == 0 ? 0 : level - 1;
- } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
- new_level >= 0 && new_level <= 7) {
- /* new_level set */
+ if (level > 0)
+ level--;
+ } else if (sscanf(cmd, "level %d", &level) == 1 &&
+ level >= 0 && level <= max_level) {
+ /* new level set */
} else
return -EINVAL;
-
- brightness_set(new_level);
}
- return 0;
+ /*
+ * Now we know what the final level should be, so we try to set it.
+ * Doing it this way makes the syscall restartable in case of EINTR
+ */
+ rc = brightness_set(level);
+ return (rc == -EINTR)? ERESTARTSYS : rc;
}
static struct ibm_struct brightness_driver_data = {
/* scale down from 0-255 to 0-7 */
newlevel = (s >> 5) & 0x07;
- rc = mutex_lock_interruptible(&fan_mutex);
- if (rc < 0)
- return rc;
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
rc = fan_get_status(&status);
if (!rc && (status &
__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)
{
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;
int rc;
u8 s;
- rc = mutex_lock_interruptible(&fan_mutex);
- if (rc < 0)
- return rc;
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
rc = fan_get_status(&s);
if (!rc)
fan_update_desired_level(s);
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();
{
int rc;
+ if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+ return;
+
printk(IBM_NOTICE "fan watchdog: enabling fan\n");
rc = fan_set_enable();
if (rc < 0) {
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
if (!fan_control_allowed)
return -EPERM;
- rc = mutex_lock_interruptible(&fan_mutex);
- if (rc < 0)
- return rc;
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
if (level == TPACPI_FAN_LAST_LEVEL)
level = fan_control_desired_level;
if (!fan_control_allowed)
return -EPERM;
- rc = mutex_lock_interruptible(&fan_mutex);
- if (rc < 0)
- return rc;
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
switch (fan_control_access_mode) {
case TPACPI_FAN_WR_ACPI_FANS:
if (!fan_control_allowed)
return -EPERM;
- rc = mutex_lock_interruptible(&fan_mutex);
- if (rc < 0)
- return rc;
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
rc = 0;
switch (fan_control_access_mode) {
if (!fan_control_allowed)
return -EPERM;
- rc = mutex_lock_interruptible(&fan_mutex);
- if (rc < 0)
- return rc;
+ if (mutex_lock_interruptible(&fan_mutex))
+ return -ERESTARTSYS;
rc = 0;
switch (fan_control_access_mode) {
****************************************************************************
****************************************************************************/
+/* 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;
unsigned int i;
struct ibm_struct *ibm;
+ if (!kp || !kp->name || !val)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
ibm = ibms_init[i].data;
- BUG_ON(ibm == NULL);
+ WARN_ON(ibm == NULL);
+
+ if (!ibm || !ibm->name)
+ continue;
if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
if (strlen(val) > sizeof(ibms_init[i].param) - 2)
static int brightness_mode;
module_param_named(brightness_mode, brightness_mode, int, 0);
+static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
+module_param(brightness_enable, uint, 0);
+
static unsigned int hotkey_report_mode;
module_param(hotkey_report_mode, uint, 0);
{
int ret, i;
+ tpacpi_lifecycle = TPACPI_LIFE_INIT;
+
/* Parameter checking */
if (hotkey_report_mode > 2)
return -EINVAL;
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 */
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;
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");
tp_features.input_device_registered = 1;
}
+ tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
return 0;
}
{
struct ibm_struct *ibm, *itmp;
+ tpacpi_lifecycle = TPACPI_LIFE_EXITING;
+
list_for_each_entry_safe_reverse(ibm, itmp,
&tpacpi_all_drivers,
all_drivers) {
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);