From f21f85de4b3b9ad4a671fb19a889c16db2ea38b2 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 29 Mar 2007 01:58:40 -0300 Subject: ACPI: ibm-acpi: rename driver to thinkpad-acpi Rename the ibm-acpi driver to thinkpad-acpi. ThinkPads are not even made by IBM anymore, so it is high time to rename the driver... The name thinkpad-acpi was used sometime ago by a thinkpad-specific hotkey driver by Erik Rigtorp, around the 2.6.8-2.6.10 time frame. The driver apparently never got merged into mainline (it did make some trips through -mm). ibm-acpi was merged soon after, making its debut in 2.6.10. The reuse of the thinkpad-acpi name shouldn't be a problem as far as user confusion goes, as Erik's thinkpad-acpi apparently didn't get widespread use in the Linux ThinkPad community and most hits for thinkpad-acpi in google point to ibm-acpi anyway. Erik, if you read this, please consider the reuse of the thinkpad-acpi name as a compliment to your effort to make ThinkPads more useful to all of us. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.h | 437 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 drivers/misc/thinkpad_acpi.h (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h new file mode 100644 index 000000000000..7ebaaa40e183 --- /dev/null +++ b/drivers/misc/thinkpad_acpi.h @@ -0,0 +1,437 @@ +/* + * ibm_acpi.h - IBM ThinkPad ACPI Extras + * + * + * Copyright (C) 2004-2005 Borislav Deianov + * Copyright (C) 2006-2007 Henrique de Moraes Holschuh + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __IBM_ACPI_H__ +#define __IBM_ACPI_H__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +/**************************************************************************** + * Main driver + */ + +#define IBM_NAME "ibm" +#define IBM_DESC "IBM ThinkPad ACPI Extras" +#define IBM_FILE "ibm_acpi" +#define IBM_URL "http://ibm-acpi.sf.net/" + +#define IBM_DIR IBM_NAME + +#define IBM_LOG IBM_FILE ": " +#define IBM_ERR KERN_ERR IBM_LOG +#define IBM_NOTICE KERN_NOTICE IBM_LOG +#define IBM_INFO KERN_INFO IBM_LOG +#define IBM_DEBUG KERN_DEBUG IBM_LOG + +#define IBM_MAX_ACPI_ARGS 3 + +/* ThinkPad CMOS commands */ +#define TP_CMOS_VOLUME_DOWN 0 +#define TP_CMOS_VOLUME_UP 1 +#define TP_CMOS_VOLUME_MUTE 2 +#define TP_CMOS_BRIGHTNESS_UP 4 +#define TP_CMOS_BRIGHTNESS_DOWN 5 + +#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") +#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") +#define strlencmp(a,b) (strncmp((a), (b), strlen(b))) + +/* ACPI HIDs */ +#define IBM_HKEY_HID "IBM0068" +#define IBM_PCI_HID "PNP0A03" + +/* ACPI helpers */ +static int acpi_evalf(acpi_handle handle, + void *res, char *method, char *fmt, ...); +static int acpi_ec_read(int i, u8 * p); +static int acpi_ec_write(int i, u8 v); +static int _sta(acpi_handle handle); + +/* ACPI handles */ +static acpi_handle root_handle; /* root namespace */ +static acpi_handle ec_handle; /* EC */ +static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */ +static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */ + +static void ibm_handle_init(char *name, + acpi_handle * handle, acpi_handle parent, + char **paths, int num_paths, char **path); +#define IBM_HANDLE_INIT(object) \ + ibm_handle_init(#object, &object##_handle, *object##_parent, \ + object##_paths, ARRAY_SIZE(object##_paths), &object##_path) + +/* procfs support */ +static struct proc_dir_entry *proc_dir; +static int ibm_acpi_driver_init(void); +static int ibm_acpi_driver_read(char *p); + +/* procfs helpers */ +static int dispatch_read(char *page, char **start, off_t off, int count, + int *eof, void *data); +static int dispatch_write(struct file *file, const char __user * userbuf, + unsigned long count, void *data); +static char *next_cmd(char **cmds); + +/* Module */ +static int experimental; +static char *ibm_thinkpad_ec_found; + +static char* check_dmi_for_ec(void); +static int acpi_ibm_init(void); +static void acpi_ibm_exit(void); + + +/**************************************************************************** + * Subdrivers + */ + +struct ibm_struct { + char *name; + char param[32]; + + char *hid; + struct acpi_driver *driver; + + int (*init) (void); + int (*read) (char *); + int (*write) (char *); + void (*exit) (void); + + void (*notify) (struct ibm_struct *, u32); + acpi_handle *handle; + int type; + struct acpi_device *device; + + int driver_registered; + int proc_created; + int init_called; + int notify_installed; + + int experimental; +}; + +static struct ibm_struct ibms[]; +static int set_ibm_param(const char *val, struct kernel_param *kp); +static int ibm_init(struct ibm_struct *ibm); +static void ibm_exit(struct ibm_struct *ibm); + +/* ACPI devices */ +static void dispatch_notify(acpi_handle handle, u32 event, void *data); +static int setup_notify(struct ibm_struct *ibm); +static int ibm_device_add(struct acpi_device *device); +static int register_ibmacpi_subdriver(struct ibm_struct *ibm); + + +/* + * Bay subdriver + */ + +#ifdef CONFIG_ACPI_IBM_BAY +static int bay_status_supported, bay_eject_supported; +static int bay_status2_supported, bay_eject2_supported; + +static acpi_handle bay_handle, bay_ej_handle; +static acpi_handle bay2_handle, bay2_ej_handle; + +static int bay_init(void); +static void bay_notify(struct ibm_struct *ibm, u32 event); +static int bay_read(char *p); +static int bay_write(char *buf); +#endif /* CONFIG_ACPI_IBM_BAY */ + + +/* + * Beep subdriver + */ + +static acpi_handle beep_handle; + +static int beep_read(char *p); +static int beep_write(char *buf); + + +/* + * Bluetooth subdriver + */ + +static int bluetooth_supported; + +static int bluetooth_init(void); +static int bluetooth_status(void); +static int bluetooth_read(char *p); +static int bluetooth_write(char *buf); + + +/* + * Brightness (backlight) subdriver + */ + +static struct backlight_device *ibm_backlight_device; +static int brightness_offset = 0x31; + +static int brightness_init(void); +static void brightness_exit(void); +static int brightness_get(struct backlight_device *bd); +static int brightness_set(int value); +static int brightness_update_status(struct backlight_device *bd); +static int brightness_read(char *p); +static int brightness_write(char *buf); + + +/* + * CMOS subdriver + */ + +static int cmos_eval(int cmos_cmd); +static int cmos_read(char *p); +static int cmos_write(char *buf); + + +/* + * Dock subdriver + */ + +static acpi_handle pci_handle; +#ifdef CONFIG_ACPI_IBM_DOCK +static acpi_handle dock_handle; + +static void dock_notify(struct ibm_struct *ibm, u32 event); +static int dock_read(char *p); +static int dock_write(char *buf); +#endif /* CONFIG_ACPI_IBM_DOCK */ + + +/* + * EC dump subdriver + */ + +static int ecdump_read(char *p) ; +static int ecdump_write(char *buf); + + +/* + * Fan subdriver + */ + +enum { /* Fan control constants */ + fan_status_offset = 0x2f, /* EC register 0x2f */ + fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) + * 0x84 must be read before 0x85 */ + + IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer + * disengaged */ + IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan + * control */ +}; + +enum fan_status_access_mode { + IBMACPI_FAN_NONE = 0, /* No fan status or control */ + IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ + IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ +}; + +enum fan_control_access_mode { + IBMACPI_FAN_WR_NONE = 0, /* No fan control */ + IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ + IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ + IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ +}; + +enum fan_control_commands { + IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ + IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ + IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, + * and also watchdog cmd */ +}; + +static enum fan_status_access_mode fan_status_access_mode; +static enum fan_control_access_mode fan_control_access_mode; +static enum fan_control_commands fan_control_commands; +static int fan_control_status_known; +static u8 fan_control_initial_status; +static int fan_watchdog_maxinterval; + +static acpi_handle fans_handle, gfan_handle, sfan_handle; + +static int fan_init(void); +static void fan_exit(void); +static int fan_get_status(u8 *status); +static int fan_get_speed(unsigned int *speed); +static void fan_watchdog_fire(struct work_struct *ignored); +static void fan_watchdog_reset(void); +static int fan_set_level(int level); +static int fan_set_enable(void); +static int fan_set_disable(void); +static int fan_set_speed(int speed); +static int fan_read(char *p); +static int fan_write(char *buf); +static int fan_write_cmd_level(const char *cmd, int *rc); +static int fan_write_cmd_enable(const char *cmd, int *rc); +static int fan_write_cmd_disable(const char *cmd, int *rc); +static int fan_write_cmd_speed(const char *cmd, int *rc); +static int fan_write_cmd_watchdog(const char *cmd, int *rc); + + +/* + * Hotkey subdriver + */ + +static int hotkey_supported; +static int hotkey_mask_supported; +static int hotkey_orig_status; +static int hotkey_orig_mask; + +static int hotkey_init(void); +static void hotkey_exit(void); +static int hotkey_get(int *status, int *mask); +static int hotkey_set(int status, int mask); +static void hotkey_notify(struct ibm_struct *ibm, u32 event); +static int hotkey_read(char *p); +static int hotkey_write(char *buf); + + +/* + * LED subdriver + */ + +enum led_access_mode { + IBMACPI_LED_NONE = 0, + IBMACPI_LED_570, /* 570 */ + IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + IBMACPI_LED_NEW, /* all others */ +}; + +enum { /* For IBMACPI_LED_OLD */ + IBMACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ + IBMACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ + IBMACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ +}; + +static enum led_access_mode led_supported; +static acpi_handle led_handle; + +static int led_init(void); +static int led_read(char *p); +static int led_write(char *buf); + +/* + * Light (thinklight) subdriver + */ + +static int light_supported; +static int light_status_supported; +static acpi_handle lght_handle, ledb_handle; + +static int light_init(void); +static int light_read(char *p); +static int light_write(char *buf); + + +/* + * Thermal subdriver + */ + +enum thermal_access_mode { + IBMACPI_THERMAL_NONE = 0, /* No thermal support */ + IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ + IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ + IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ + IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ +}; + +#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ +struct ibm_thermal_sensors_struct { + s32 temp[IBMACPI_MAX_THERMAL_SENSORS]; +}; + +static int thermal_init(void); +static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); +static int thermal_read(char *p); + + +/* + * Video subdriver + */ + +enum video_access_mode { + IBMACPI_VIDEO_NONE = 0, + IBMACPI_VIDEO_570, /* 570 */ + IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */ + IBMACPI_VIDEO_NEW, /* all others */ +}; + +static enum video_access_mode video_supported; +static int video_orig_autosw; +static acpi_handle vid_handle, vid2_handle; + +static int video_init(void); +static void video_exit(void); +static int video_status(void); +static int video_autosw(void); +static int video_switch(void); +static int video_switch2(int status); +static int video_expand(void); +static int video_read(char *p); +static int video_write(char *buf); + + +/* + * Volume subdriver + */ + +static int volume_offset = 0x30; + +static int volume_read(char *p); +static int volume_write(char *buf); + + +/* + * Wan subdriver + */ + +static int wan_supported; + +static int wan_init(void); +static int wan_status(void); +static int wan_read(char *p); +static int wan_write(char *buf); + + +#endif /* __IBM_ACPI_H */ -- cgit v1.2.3-59-g8ed1b From 85998248b2e8c6ae7d3ad1fa7b059aed22205ec4 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 29 Mar 2007 01:58:41 -0300 Subject: ACPI: thinkpad-acpi: cleanup Kconfig for thinkpad-acpi Since ibm-acpi was renamed to thinkpad-acpi, rename and update its Kconfig entries and Kconfig-related symbols accordingly. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/Kconfig | 37 ++++++++++++++++++++----------------- drivers/misc/Makefile | 2 +- drivers/misc/thinkpad_acpi.c | 26 +++++++++++++------------- drivers/misc/thinkpad_acpi.h | 8 ++++---- 4 files changed, 38 insertions(+), 35 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 5d2bcbf1e3d4..2cd96a3dff54 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -122,40 +122,43 @@ config SONY_LAPTOP Read for more information. -config ACPI_IBM - tristate "IBM ThinkPad Laptop Extras" +config THINKPAD_ACPI + tristate "ThinkPad ACPI Laptop Extras" depends on X86 && ACPI select BACKLIGHT_CLASS_DEVICE ---help--- - This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds + This is a driver for the IBM and Lenovo ThinkPad laptops. It adds support for Fn-Fx key combinations, Bluetooth control, video output switching, ThinkLight control, UltraBay eject and more. - For more information about this driver see - and . + For more information about this driver see + and . - If you have an IBM ThinkPad laptop, say Y or M here. + This driver was formely known as ibm-acpi. -config ACPI_IBM_DOCK + If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. + +config THINKPAD_ACPI_DOCK bool "Legacy Docking Station Support" - depends on ACPI_IBM + depends on THINKPAD_ACPI depends on ACPI_DOCK=n default n ---help--- - Allows the ibm_acpi driver to handle docking station events. - This support is obsoleted by CONFIG_HOTPLUG_PCI_ACPI. It will - allow locking and removing the laptop from the docking station, - but will not properly connect PCI devices. + Allows the thinkpad_acpi driver to handle docking station events. + This support was made obsolete by the generic ACPI docking station + support (CONFIG_ACPI_DOCK). It will allow locking and removing the + laptop from the docking station, but will not properly connect PCI + devices. If you are not sure, say N here. -config ACPI_IBM_BAY +config THINKPAD_ACPI_BAY bool "Legacy Removable Bay Support" - depends on ACPI_IBM + depends on THINKPAD_ACPI default y ---help--- - Allows the ibm_acpi driver to handle removable bays. It will allow - disabling the device in the bay, and also generate notifications when - the bay lever is ejected or inserted. + Allows the thinkpad_acpi driver to handle removable bays. It will + eletrically disable the device in the bay, and also generate + notifications when the bay lever is ejected or inserted. If you are not sure, say Y here. diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index ebf4ff2f858e..e32516459138 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -12,4 +12,4 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o -obj-$(CONFIG_ACPI_IBM) += thinkpad_acpi.o +obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 2836516ece86..bb789db4d334 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1040,7 +1040,7 @@ static int light_write(char *buf) /* don't list other alternatives as we install a notify handler on the 570 */ IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ -#ifdef CONFIG_ACPI_IBM_DOCK +#ifdef CONFIG_THINKPAD_ACPI_DOCK IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */ @@ -1111,13 +1111,13 @@ static int dock_write(char *buf) return 0; } -#endif /* CONFIG_ACPI_IBM_DOCK */ +#endif /* CONFIG_THINKPAD_ACPI_DOCK */ /************************************************************************* * Bay subdriver */ -#ifdef CONFIG_ACPI_IBM_BAY +#ifdef CONFIG_THINKPAD_ACPI_BAY static int bay_status_supported; static int bay_status2_supported; static int bay_eject_supported; @@ -1208,7 +1208,7 @@ static int bay_write(char *buf) return 0; } -#endif /* CONFIG_ACPI_IBM_BAY */ +#endif /* CONFIG_THINKPAD_ACPI_BAY */ /************************************************************************* * CMOS subdriver @@ -2477,7 +2477,7 @@ static struct ibm_struct ibms[] = { .read = light_read, .write = light_write, }, -#ifdef CONFIG_ACPI_IBM_DOCK +#ifdef CONFIG_THINKPAD_ACPI_DOCK { .name = "dock", .read = dock_read, @@ -2494,7 +2494,7 @@ static struct ibm_struct ibms[] = { .type = ACPI_SYSTEM_NOTIFY, }, #endif -#ifdef CONFIG_ACPI_IBM_BAY +#ifdef CONFIG_THINKPAD_ACPI_BAY { .name = "bay", .init = bay_init, @@ -2504,7 +2504,7 @@ static struct ibm_struct ibms[] = { .handle = &bay_handle, .type = ACPI_SYSTEM_NOTIFY, }, -#endif /* CONFIG_ACPI_IBM_BAY */ +#endif /* CONFIG_THINKPAD_ACPI_BAY */ { .name = "cmos", .read = cmos_read, @@ -2686,12 +2686,12 @@ IBM_PARAM(hotkey); IBM_PARAM(bluetooth); IBM_PARAM(video); IBM_PARAM(light); -#ifdef CONFIG_ACPI_IBM_DOCK +#ifdef CONFIG_THINKPAD_ACPI_DOCK IBM_PARAM(dock); #endif -#ifdef CONFIG_ACPI_IBM_BAY +#ifdef CONFIG_THINKPAD_ACPI_BAY IBM_PARAM(bay); -#endif /* CONFIG_ACPI_IBM_BAY */ +#endif /* CONFIG_THINKPAD_ACPI_BAY */ IBM_PARAM(cmos); IBM_PARAM(led); IBM_PARAM(beep); @@ -2725,18 +2725,18 @@ static int __init acpi_ibm_init(void) IBM_HANDLE_INIT(hkey); IBM_HANDLE_INIT(lght); IBM_HANDLE_INIT(cmos); -#ifdef CONFIG_ACPI_IBM_DOCK +#ifdef CONFIG_THINKPAD_ACPI_DOCK IBM_HANDLE_INIT(dock); #endif IBM_HANDLE_INIT(pci); -#ifdef CONFIG_ACPI_IBM_BAY +#ifdef CONFIG_THINKPAD_ACPI_BAY IBM_HANDLE_INIT(bay); if (bay_handle) IBM_HANDLE_INIT(bay_ej); IBM_HANDLE_INIT(bay2); if (bay2_handle) IBM_HANDLE_INIT(bay2_ej); -#endif /* CONFIG_ACPI_IBM_BAY */ +#endif /* CONFIG_THINKPAD_ACPI_BAY */ IBM_HANDLE_INIT(beep); IBM_HANDLE_INIT(ecrd); IBM_HANDLE_INIT(ecwr); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 7ebaaa40e183..ee1b93a2bbdd 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -163,7 +163,7 @@ static int register_ibmacpi_subdriver(struct ibm_struct *ibm); * Bay subdriver */ -#ifdef CONFIG_ACPI_IBM_BAY +#ifdef CONFIG_THINKPAD_ACPI_BAY static int bay_status_supported, bay_eject_supported; static int bay_status2_supported, bay_eject2_supported; @@ -174,7 +174,7 @@ static int bay_init(void); static void bay_notify(struct ibm_struct *ibm, u32 event); static int bay_read(char *p); static int bay_write(char *buf); -#endif /* CONFIG_ACPI_IBM_BAY */ +#endif /* CONFIG_THINKPAD_ACPI_BAY */ /* @@ -229,13 +229,13 @@ static int cmos_write(char *buf); */ static acpi_handle pci_handle; -#ifdef CONFIG_ACPI_IBM_DOCK +#ifdef CONFIG_THINKPAD_ACPI_DOCK static acpi_handle dock_handle; static void dock_notify(struct ibm_struct *ibm, u32 event); static int dock_read(char *p); static int dock_write(char *buf); -#endif /* CONFIG_ACPI_IBM_DOCK */ +#endif /* CONFIG_THINKPAD_ACPI_DOCK */ /* -- cgit v1.2.3-59-g8ed1b From 643f12dbb660e139fbaea268f3e3ce4d7d594b8f Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Thu, 29 Mar 2007 01:58:43 -0300 Subject: ACPI: thinkpad-acpi: cleanup after rename Cleanup documentation, driver strings and other misc stuff, now that the driver is named "thinkpad-acpi". Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 46 ++++++++++++++++++++++++----------------- drivers/misc/thinkpad_acpi.c | 18 +++++++++------- drivers/misc/thinkpad_acpi.h | 21 ++++++++++--------- 3 files changed, 49 insertions(+), 36 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index f409f4bbdc47..af18d294cf1a 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -1,17 +1,22 @@ - IBM ThinkPad ACPI Extras Driver + ThinkPad ACPI Extras Driver - Version 0.13 - 31 December 2006 + Version 0.14 + March 26th, 2007 Borislav Deianov Henrique de Moraes Holschuh http://ibm-acpi.sf.net/ -This is a Linux ACPI driver for the IBM ThinkPad laptops. It supports -various features of these laptops which are accessible through the -ACPI framework but not otherwise fully supported by the generic Linux -ACPI drivers. +This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It +supports various features of these laptops which are accessible +through the ACPI and ACPI EC framework, but not otherwise fully +supported by the generic Linux ACPI drivers. + +This driver used to be named ibm-acpi until kernel 2.6.21 and release +0.13-20070314. It used to be in the drivers/acpi tree, but it was +moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel +2.6.22, and release 0.14. Status @@ -43,6 +48,8 @@ Please include the following information in your report: - ThinkPad model name - a copy of your DSDT, from /proc/acpi/dsdt + - a copy of the output of dmidecode, with serial numbers + and UUIDs masked off - which driver features work and which don't - the observed behavior of non-working features @@ -53,8 +60,9 @@ Installation ------------ If you are compiling this driver as included in the Linux kernel -sources, simply enable the CONFIG_ACPI_IBM option (Power Management / -ACPI / IBM ThinkPad Laptop Extras). +sources, simply enable the CONFIG_THINKPAD_ACPI option, and optionally +enable the CONFIG_THINKPAD_ACPI_BAY option if you want the +thinkpad-specific bay functionality. Features -------- @@ -210,7 +218,7 @@ hot plugging of devices in the Linux ACPI framework. If the laptop was booted while not in the dock, the following message is shown in the logs: - Mar 17 01:42:34 aero kernel: ibm_acpi: dock device not present + Mar 17 01:42:34 aero kernel: thinkpad_acpi: dock device not present In this case, no dock-related events are generated but the dock and undock commands described below still work. They can be executed @@ -270,7 +278,7 @@ This is due to the current lack of support for hot plugging of devices in the Linux ACPI framework. If the laptop was booted without the UltraBay, the following message is shown in the logs: - Mar 17 01:42:34 aero kernel: ibm_acpi: bay device not present + Mar 17 01:42:34 aero kernel: thinkpad_acpi: bay device not present In this case, no bay-related events are generated but the eject command described below still works. It can be executed manually or @@ -637,12 +645,12 @@ range. The fan cannot be stopped or started with this command. The ThinkPad's ACPI DSDT code will reprogram the fan on its own when certain conditions are met. It will override any fan programming done -through ibm-acpi. +through thinkpad-acpi. -The ibm-acpi kernel driver can be programmed to revert the fan level -to a safe setting if userspace does not issue one of the fan commands: -"enable", "disable", "level" or "watchdog" within a configurable -ammount of time. To do this, use the "watchdog" command. +The thinkpad-acpi kernel driver can be programmed to revert the fan +level to a safe setting if userspace does not issue one of the fan +commands: "enable", "disable", "level" or "watchdog" within a +configurable ammount of time. To do this, use the "watchdog" command. echo 'watchdog ' > /proc/acpi/ibm/fan @@ -686,8 +694,8 @@ separating them with commas, for example: echo enable,0xffff > /proc/acpi/ibm/hotkey echo lcd_disable,crt_enable > /proc/acpi/ibm/video -Commands can also be specified when loading the ibm_acpi module, for -example: +Commands can also be specified when loading the thinkpad-acpi module, +for example: - modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable + modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 90ffc4670a01..ddaedf80d873 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1,5 +1,5 @@ /* - * ibm_acpi.c - IBM ThinkPad ACPI Extras + * thinkpad_acpi.c - ThinkPad ACPI Extras * * * Copyright (C) 2004-2005 Borislav Deianov @@ -21,10 +21,12 @@ * 02110-1301, USA. */ -#define IBM_VERSION "0.13" +#define IBM_VERSION "0.14" /* * Changelog: + * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to + * drivers/misc. * * 2006-11-22 0.13 new maintainer * changelog now lives in git commit history, and will @@ -318,7 +320,9 @@ static int __init setup_notify(struct ibm_struct *ibm) } acpi_driver_data(ibm->device) = ibm; - sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name); + sprintf(acpi_device_class(ibm->device), "%s/%s", + IBM_ACPI_EVENT_PREFIX, + ibm->name); status = acpi_install_notify_handler(*ibm->handle, ibm->type, dispatch_notify, ibm); @@ -458,7 +462,7 @@ static char *next_cmd(char **cmds) * ibm-acpi init subdriver */ -static int ibm_acpi_driver_init(void) +static int thinkpad_acpi_driver_init(void) { printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); printk(IBM_INFO "%s\n", IBM_URL); @@ -470,7 +474,7 @@ static int ibm_acpi_driver_init(void) return 0; } -static int ibm_acpi_driver_read(char *p) +static int thinkpad_acpi_driver_read(char *p) { int len = 0; @@ -2440,8 +2444,8 @@ static struct proc_dir_entry *proc_dir = NULL; static struct ibm_struct ibms[] = { { .name = "driver", - .init = ibm_acpi_driver_init, - .read = ibm_acpi_driver_read, + .init = thinkpad_acpi_driver_init, + .read = thinkpad_acpi_driver_read, }, { .name = "hotkey", diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index ee1b93a2bbdd..015c02beb203 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -1,5 +1,5 @@ /* - * ibm_acpi.h - IBM ThinkPad ACPI Extras + * thinkpad_acpi.h - ThinkPad ACPI Extras * * * Copyright (C) 2004-2005 Borislav Deianov @@ -21,8 +21,8 @@ * 02110-1301, USA. */ -#ifndef __IBM_ACPI_H__ -#define __IBM_ACPI_H__ +#ifndef __THINKPAD_ACPI_H__ +#define __THINKPAD_ACPI_H__ #include #include @@ -47,12 +47,13 @@ * Main driver */ -#define IBM_NAME "ibm" -#define IBM_DESC "IBM ThinkPad ACPI Extras" -#define IBM_FILE "ibm_acpi" +#define IBM_NAME "thinkpad" +#define IBM_DESC "ThinkPad ACPI Extras" +#define IBM_FILE "thinkpad_acpi" #define IBM_URL "http://ibm-acpi.sf.net/" -#define IBM_DIR IBM_NAME +#define IBM_DIR "ibm" +#define IBM_ACPI_EVENT_PREFIX "ibm" #define IBM_LOG IBM_FILE ": " #define IBM_ERR KERN_ERR IBM_LOG @@ -99,8 +100,8 @@ static void ibm_handle_init(char *name, /* procfs support */ static struct proc_dir_entry *proc_dir; -static int ibm_acpi_driver_init(void); -static int ibm_acpi_driver_read(char *p); +static int thinkpad_acpi_driver_init(void); +static int thinkpad_acpi_driver_read(char *p); /* procfs helpers */ static int dispatch_read(char *page, char **start, off_t off, int count, @@ -434,4 +435,4 @@ static int wan_read(char *p); static int wan_write(char *buf); -#endif /* __IBM_ACPI_H */ +#endif /* __THINKPAD_ACPI_H */ -- cgit v1.2.3-59-g8ed1b From 6700121b535fa16fe1c8aaac03559b2f12909726 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:25 -0300 Subject: ACPI: thinkpad-acpi: rename register_ibmacpi_subdriver Rename register_ibmacpi_subdriver to register_tpacpi_subdriver, as we are not called ibmacpi anymore. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 4 ++-- drivers/misc/thinkpad_acpi.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index ddaedf80d873..cac73e5f96e2 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -345,7 +345,7 @@ static int __init ibm_device_add(struct acpi_device *device) return 0; } -static int __init register_ibmacpi_subdriver(struct ibm_struct *ibm) +static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) { int ret; @@ -2574,7 +2574,7 @@ static int __init ibm_init(struct ibm_struct *ibm) return 0; if (ibm->hid) { - ret = register_ibmacpi_subdriver(ibm); + ret = register_tpacpi_subdriver(ibm); if (ret < 0) return ret; ibm->driver_registered = 1; diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 015c02beb203..b86e5740aba4 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -157,7 +157,7 @@ static void ibm_exit(struct ibm_struct *ibm); static void dispatch_notify(acpi_handle handle, u32 event, void *data); static int setup_notify(struct ibm_struct *ibm); static int ibm_device_add(struct acpi_device *device); -static int register_ibmacpi_subdriver(struct ibm_struct *ibm); +static int register_tpacpi_subdriver(struct ibm_struct *ibm); /* -- cgit v1.2.3-59-g8ed1b From 1def7115f0277ce9d2a54efd0ae187aa88d5c7fa Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:27 -0300 Subject: ACPI: thinkpad-acpi: rename module glue Rename module init and exit functions, now that we are not called ibm-acpi anymore. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 12 ++++++------ drivers/misc/thinkpad_acpi.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 4b434866007e..80ef195c9581 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2707,7 +2707,7 @@ IBM_PARAM(brightness); IBM_PARAM(volume); IBM_PARAM(fan); -static int __init acpi_ibm_init(void) +static int __init thinkpad_acpi_module_init(void) { int ret, i; @@ -2754,7 +2754,7 @@ static int __init acpi_ibm_init(void) proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); if (!proc_dir) { printk(IBM_ERR "unable to create proc dir %s", IBM_DIR); - acpi_ibm_exit(); + thinkpad_acpi_module_exit(); return -ENODEV; } proc_dir->owner = THIS_MODULE; @@ -2764,7 +2764,7 @@ static int __init acpi_ibm_init(void) if (ret >= 0 && *ibms[i].param) ret = ibms[i].write(ibms[i].param); if (ret < 0) { - acpi_ibm_exit(); + thinkpad_acpi_module_exit(); return ret; } } @@ -2772,7 +2772,7 @@ static int __init acpi_ibm_init(void) return 0; } -static void acpi_ibm_exit(void) +static void thinkpad_acpi_module_exit(void) { int i; @@ -2786,5 +2786,5 @@ static void acpi_ibm_exit(void) kfree(ibm_thinkpad_ec_found); } -module_init(acpi_ibm_init); -module_exit(acpi_ibm_exit); +module_init(thinkpad_acpi_module_init); +module_exit(thinkpad_acpi_module_exit); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index b86e5740aba4..8b2fd1a1a8a1 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -115,8 +115,8 @@ static int experimental; static char *ibm_thinkpad_ec_found; static char* check_dmi_for_ec(void); -static int acpi_ibm_init(void); -static void acpi_ibm_exit(void); +static int thinkpad_acpi_module_init(void); +static void thinkpad_acpi_module_exit(void); /**************************************************************************** -- cgit v1.2.3-59-g8ed1b From efa27145df34eacf2569bd45f68dbe00003d3616 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:28 -0300 Subject: ACPI: thinkpad-acpi: rename thinkpad constants Rename all IBMACPI_ constants, now that we are not called ibm-acpi anymore. Driver-specific constants are now prefixed TPACPI_, ThinkPad firmware specific ones are now prefixed TP_CMOS_, TP_ACPI_, or TP_EC_. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 188 +++++++++++++++++++++---------------------- drivers/misc/thinkpad_acpi.h | 64 +++++++-------- 2 files changed, 125 insertions(+), 127 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 80ef195c9581..1683bfe15b35 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -781,16 +781,16 @@ static int video_init(void) if (!vid_handle) /* video switching not supported on R30, R31 */ - video_supported = IBMACPI_VIDEO_NONE; + video_supported = TPACPI_VIDEO_NONE; else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd")) /* 570 */ - video_supported = IBMACPI_VIDEO_570; + video_supported = TPACPI_VIDEO_570; else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd")) /* 600e/x, 770e, 770x */ - video_supported = IBMACPI_VIDEO_770; + video_supported = TPACPI_VIDEO_770; else /* all others */ - video_supported = IBMACPI_VIDEO_NEW; + video_supported = TPACPI_VIDEO_NEW; return 0; } @@ -805,15 +805,15 @@ static int video_status(void) int status = 0; int i; - if (video_supported == IBMACPI_VIDEO_570) { + if (video_supported == TPACPI_VIDEO_570) { if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87)) status = i & 3; - } else if (video_supported == IBMACPI_VIDEO_770) { + } else if (video_supported == TPACPI_VIDEO_770) { if (acpi_evalf(NULL, &i, "\\VCDL", "d")) status |= 0x01 * i; if (acpi_evalf(NULL, &i, "\\VCDC", "d")) status |= 0x02 * i; - } else if (video_supported == IBMACPI_VIDEO_NEW) { + } else if (video_supported == TPACPI_VIDEO_NEW) { acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1); if (acpi_evalf(NULL, &i, "\\VCDC", "d")) status |= 0x02 * i; @@ -832,10 +832,10 @@ static int video_autosw(void) { int autosw = 0; - if (video_supported == IBMACPI_VIDEO_570) + if (video_supported == TPACPI_VIDEO_570) acpi_evalf(vid_handle, &autosw, "SWIT", "d"); - else if (video_supported == IBMACPI_VIDEO_770 || - video_supported == IBMACPI_VIDEO_NEW) + else if (video_supported == TPACPI_VIDEO_770 || + video_supported == TPACPI_VIDEO_NEW) acpi_evalf(vid_handle, &autosw, "^VDEE", "d"); return autosw & 1; @@ -848,7 +848,7 @@ static int video_switch(void) if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) return -EIO; - ret = video_supported == IBMACPI_VIDEO_570 ? + ret = video_supported == TPACPI_VIDEO_570 ? acpi_evalf(ec_handle, NULL, "_Q16", "v") : acpi_evalf(vid_handle, NULL, "VSWT", "v"); acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); @@ -858,9 +858,9 @@ static int video_switch(void) static int video_expand(void) { - if (video_supported == IBMACPI_VIDEO_570) + if (video_supported == TPACPI_VIDEO_570) return acpi_evalf(ec_handle, NULL, "_Q17", "v"); - else if (video_supported == IBMACPI_VIDEO_770) + else if (video_supported == TPACPI_VIDEO_770) return acpi_evalf(vid_handle, NULL, "VEXP", "v"); else return acpi_evalf(NULL, NULL, "\\VEXP", "v"); @@ -870,10 +870,10 @@ static int video_switch2(int status) { int ret; - if (video_supported == IBMACPI_VIDEO_570) { + if (video_supported == TPACPI_VIDEO_570) { ret = acpi_evalf(NULL, NULL, "\\_SB.PHS2", "vdd", 0x8b, status | 0x80); - } else if (video_supported == IBMACPI_VIDEO_770) { + } else if (video_supported == TPACPI_VIDEO_770) { int autosw = video_autosw(); if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) return -EIO; @@ -904,12 +904,12 @@ static int video_read(char *p) len += sprintf(p + len, "status:\t\tsupported\n"); len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); - if (video_supported == IBMACPI_VIDEO_NEW) + if (video_supported == TPACPI_VIDEO_NEW) len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); - if (video_supported == IBMACPI_VIDEO_NEW) + if (video_supported == TPACPI_VIDEO_NEW) len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); @@ -936,10 +936,10 @@ static int video_write(char *buf) enable |= 0x02; } else if (strlencmp(cmd, "crt_disable") == 0) { disable |= 0x02; - } else if (video_supported == IBMACPI_VIDEO_NEW && + } else if (video_supported == TPACPI_VIDEO_NEW && strlencmp(cmd, "dvi_enable") == 0) { enable |= 0x08; - } else if (video_supported == IBMACPI_VIDEO_NEW && + } else if (video_supported == TPACPI_VIDEO_NEW && strlencmp(cmd, "dvi_disable") == 0) { disable |= 0x08; } else if (strlencmp(cmd, "auto_enable") == 0) { @@ -1283,16 +1283,16 @@ static int led_init(void) { if (!led_handle) /* led not supported on R30, R31 */ - led_supported = IBMACPI_LED_NONE; + led_supported = TPACPI_LED_NONE; else if (strlencmp(led_path, "SLED") == 0) /* 570 */ - led_supported = IBMACPI_LED_570; + led_supported = TPACPI_LED_570; else if (strlencmp(led_path, "SYSL") == 0) /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ - led_supported = IBMACPI_LED_OLD; + led_supported = TPACPI_LED_OLD; else /* all others */ - led_supported = IBMACPI_LED_NEW; + led_supported = TPACPI_LED_NEW; return 0; } @@ -1309,7 +1309,7 @@ static int led_read(char *p) } len += sprintf(p + len, "status:\t\tsupported\n"); - if (led_supported == IBMACPI_LED_570) { + if (led_supported == TPACPI_LED_570) { /* 570 */ int i, status; for (i = 0; i < 8; i++) { @@ -1354,23 +1354,23 @@ static int led_write(char *buf) } else return -EINVAL; - if (led_supported == IBMACPI_LED_570) { + if (led_supported == TPACPI_LED_570) { /* 570 */ led = 1 << led; if (!acpi_evalf(led_handle, NULL, NULL, "vdd", led, led_sled_arg1[ind])) return -EIO; - } else if (led_supported == IBMACPI_LED_OLD) { + } else if (led_supported == TPACPI_LED_OLD) { /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ led = 1 << led; - ret = ec_write(IBMACPI_LED_EC_HLMS, led); + ret = ec_write(TPACPI_LED_EC_HLMS, led); if (ret >= 0) ret = - ec_write(IBMACPI_LED_EC_HLBL, + ec_write(TPACPI_LED_EC_HLBL, led * led_exp_hlbl[ind]); if (ret >= 0) ret = - ec_write(IBMACPI_LED_EC_HLCL, + ec_write(TPACPI_LED_EC_HLCL, led * led_exp_hlcl[ind]); if (ret < 0) return ret; @@ -1467,29 +1467,29 @@ static int thermal_init(void) printk(IBM_ERR "ThinkPad ACPI EC access misbehaving, " "falling back to ACPI TMPx access mode\n"); - thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07; + thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; } else { printk(IBM_ERR "ThinkPad ACPI EC access misbehaving, " "disabling thermal sensors access\n"); - thermal_read_mode = IBMACPI_THERMAL_NONE; + thermal_read_mode = TPACPI_THERMAL_NONE; } } else { thermal_read_mode = (ta2 != 0) ? - IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8; + TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8; } } else if (acpi_tmp7) { if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) { /* 600e/x, 770e, 770x */ - thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT; + thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT; } else { /* Standard ACPI TMPx access, max 8 sensors */ - thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07; + thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07; } } else { /* temperatures not supported on 570, G4x, R30, R31, R32 */ - thermal_read_mode = IBMACPI_THERMAL_NONE; + thermal_read_mode = TPACPI_THERMAL_NONE; } return 0; @@ -1505,8 +1505,8 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) return -EINVAL; switch (thermal_read_mode) { -#if IBMACPI_MAX_THERMAL_SENSORS >= 16 - case IBMACPI_THERMAL_TPEC_16: +#if TPACPI_MAX_THERMAL_SENSORS >= 16 + case TPACPI_THERMAL_TPEC_16: for (i = 0; i < 8; i++) { if (!acpi_ec_read(0xC0 + i, &tmp)) return -EIO; @@ -1514,15 +1514,15 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) } /* fallthrough */ #endif - case IBMACPI_THERMAL_TPEC_8: + case TPACPI_THERMAL_TPEC_8: for (i = 0; i < 8; i++) { if (!acpi_ec_read(0x78 + i, &tmp)) return -EIO; s->temp[i] = tmp * 1000; } - return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8; + return (thermal_read_mode == TPACPI_THERMAL_TPEC_16) ? 16 : 8; - case IBMACPI_THERMAL_ACPI_UPDT: + case TPACPI_THERMAL_ACPI_UPDT: if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) return -EIO; for (i = 0; i < 8; i++) { @@ -1533,7 +1533,7 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) } return 8; - case IBMACPI_THERMAL_ACPI_TMP07: + case TPACPI_THERMAL_ACPI_TMP07: for (i = 0; i < 8; i++) { tmpi[3] = '0' + i; if (!acpi_evalf(ec_handle, &t, tmpi, "d")) @@ -1542,7 +1542,7 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) } return 8; - case IBMACPI_THERMAL_NONE: + case TPACPI_THERMAL_NONE: default: return 0; } @@ -1848,18 +1848,18 @@ static int volume_write(char *buf) /* * FAN ACCESS MODES * - * IBMACPI_FAN_RD_ACPI_GFAN: + * TPACPI_FAN_RD_ACPI_GFAN: * ACPI GFAN method: returns fan level * - * see IBMACPI_FAN_WR_ACPI_SFAN + * see TPACPI_FAN_WR_ACPI_SFAN * EC 0x2f not available if GFAN exists * - * IBMACPI_FAN_WR_ACPI_SFAN: + * TPACPI_FAN_WR_ACPI_SFAN: * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max) * * EC 0x2f might be available *for reading*, but never for writing. * - * IBMACPI_FAN_WR_TPEC: + * TPACPI_FAN_WR_TPEC: * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported * on almost all ThinkPads * @@ -1888,7 +1888,7 @@ static int volume_write(char *buf) * 0x00 = stop * 0x07 = max (set when temperatures critical) * Some ThinkPads may have other levels, see - * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41) + * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41) * * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at * boot. Apparently the EC does not intialize it, so unless ACPI DSDT @@ -1923,7 +1923,7 @@ static int volume_write(char *buf) * For firmware bugs, refer to: * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues * - * IBMACPI_FAN_WR_ACPI_FANS: + * TPACPI_FAN_WR_ACPI_FANS: * ThinkPad X31, X40, X41. Not available in the X60. * * FANS ACPI handle: takes three arguments: low speed, medium speed, @@ -1940,7 +1940,7 @@ static int volume_write(char *buf) * ACPI DSDT switches which set is in use depending on various * factors. * - * IBMACPI_FAN_WR_TPEC is also available and should be used to + * TPACPI_FAN_WR_TPEC is also available and should be used to * command the fan. The X31/X40/X41 seems to have 8 fan levels, * but the ACPI tables just mention level 7. */ @@ -1966,21 +1966,21 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ static int fan_init(void) { - fan_status_access_mode = IBMACPI_FAN_NONE; - fan_control_access_mode = IBMACPI_FAN_WR_NONE; + fan_status_access_mode = TPACPI_FAN_NONE; + fan_control_access_mode = TPACPI_FAN_WR_NONE; fan_control_commands = 0; fan_control_status_known = 1; fan_watchdog_maxinterval = 0; if (gfan_handle) { /* 570, 600e/x, 770e, 770x */ - fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN; + fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; } else { /* all other ThinkPads: note that even old-style * ThinkPad ECs supports the fan control register */ if (likely(acpi_ec_read(fan_status_offset, &fan_control_initial_status))) { - fan_status_access_mode = IBMACPI_FAN_RD_TPEC; + fan_status_access_mode = TPACPI_FAN_RD_TPEC; /* In some ThinkPads, neither the EC nor the ACPI * DSDT initialize the fan status, and it ends up @@ -2015,9 +2015,9 @@ static int fan_init(void) if (sfan_handle) { /* 570, 770x-JL */ - fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN; + fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN; fan_control_commands |= - IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE; + TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE; } else { if (!gfan_handle) { /* gfan without sfan means no fan control */ @@ -2026,16 +2026,16 @@ static int fan_init(void) if (fans_handle) { /* X31, X40, X41 */ fan_control_access_mode = - IBMACPI_FAN_WR_ACPI_FANS; + TPACPI_FAN_WR_ACPI_FANS; fan_control_commands |= - IBMACPI_FAN_CMD_SPEED | - IBMACPI_FAN_CMD_LEVEL | - IBMACPI_FAN_CMD_ENABLE; + TPACPI_FAN_CMD_SPEED | + TPACPI_FAN_CMD_LEVEL | + TPACPI_FAN_CMD_ENABLE; } else { - fan_control_access_mode = IBMACPI_FAN_WR_TPEC; + fan_control_access_mode = TPACPI_FAN_WR_TPEC; fan_control_commands |= - IBMACPI_FAN_CMD_LEVEL | - IBMACPI_FAN_CMD_ENABLE; + TPACPI_FAN_CMD_LEVEL | + TPACPI_FAN_CMD_ENABLE; } } } @@ -2048,10 +2048,10 @@ static int fan_get_status(u8 *status) u8 s; /* TODO: - * Add IBMACPI_FAN_RD_ACPI_FANS ? */ + * Add TPACPI_FAN_RD_ACPI_FANS ? */ switch (fan_status_access_mode) { - case IBMACPI_FAN_RD_ACPI_GFAN: + case TPACPI_FAN_RD_ACPI_GFAN: /* 570, 600e/x, 770e, 770x */ if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) @@ -2062,7 +2062,7 @@ static int fan_get_status(u8 *status) break; - case IBMACPI_FAN_RD_TPEC: + case TPACPI_FAN_RD_TPEC: /* all except 570, 600e/x, 770e, 770x */ if (unlikely(!acpi_ec_read(fan_status_offset, &s))) return -EIO; @@ -2090,7 +2090,7 @@ static int fan_get_speed(unsigned int *speed) u8 hi, lo; switch (fan_status_access_mode) { - case IBMACPI_FAN_RD_TPEC: + case TPACPI_FAN_RD_TPEC: /* all except 570, 600e/x, 770e, 770x */ if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || !acpi_ec_read(fan_rpm_offset + 1, &hi))) @@ -2140,7 +2140,7 @@ static void fan_watchdog_reset(void) static int fan_set_level(int level) { switch (fan_control_access_mode) { - case IBMACPI_FAN_WR_ACPI_SFAN: + case TPACPI_FAN_WR_ACPI_SFAN: if (level >= 0 && level <= 7) { if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) return -EIO; @@ -2148,10 +2148,10 @@ static int fan_set_level(int level) return -EINVAL; break; - case IBMACPI_FAN_WR_ACPI_FANS: - case IBMACPI_FAN_WR_TPEC: - if ((level != IBMACPI_FAN_EC_AUTO) && - (level != IBMACPI_FAN_EC_DISENGAGED) && + case TPACPI_FAN_WR_ACPI_FANS: + case TPACPI_FAN_WR_TPEC: + if ((level != TP_EC_FAN_AUTO) && + (level != TP_EC_FAN_FULLSPEED) && ((level < 0) || (level > 7))) return -EINVAL; @@ -2173,14 +2173,14 @@ static int fan_set_enable(void) int rc; switch (fan_control_access_mode) { - case IBMACPI_FAN_WR_ACPI_FANS: - case IBMACPI_FAN_WR_TPEC: + case TPACPI_FAN_WR_ACPI_FANS: + case TPACPI_FAN_WR_TPEC: if ((rc = fan_get_status(&s)) < 0) return rc; /* Don't go out of emergency fan mode */ if (s != 7) - s = IBMACPI_FAN_EC_AUTO; + s = TP_EC_FAN_AUTO; if (!acpi_ec_write(fan_status_offset, s)) return -EIO; @@ -2188,7 +2188,7 @@ static int fan_set_enable(void) fan_control_status_known = 1; break; - case IBMACPI_FAN_WR_ACPI_SFAN: + case TPACPI_FAN_WR_ACPI_SFAN: if ((rc = fan_get_status(&s)) < 0) return rc; @@ -2211,15 +2211,15 @@ static int fan_set_enable(void) static int fan_set_disable(void) { switch (fan_control_access_mode) { - case IBMACPI_FAN_WR_ACPI_FANS: - case IBMACPI_FAN_WR_TPEC: + case TPACPI_FAN_WR_ACPI_FANS: + case TPACPI_FAN_WR_TPEC: if (!acpi_ec_write(fan_status_offset, 0x00)) return -EIO; else fan_control_status_known = 1; break; - case IBMACPI_FAN_WR_ACPI_SFAN: + case TPACPI_FAN_WR_ACPI_SFAN: if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) return -EIO; break; @@ -2233,7 +2233,7 @@ static int fan_set_disable(void) static int fan_set_speed(int speed) { switch (fan_control_access_mode) { - case IBMACPI_FAN_WR_ACPI_FANS: + case TPACPI_FAN_WR_ACPI_FANS: if (speed >= 0 && speed <= 65535) { if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", speed, speed, speed)) @@ -2256,7 +2256,7 @@ static int fan_read(char *p) unsigned int speed = 0; switch (fan_status_access_mode) { - case IBMACPI_FAN_RD_ACPI_GFAN: + case TPACPI_FAN_RD_ACPI_GFAN: /* 570, 600e/x, 770e, 770x */ if ((rc = fan_get_status(&status)) < 0) return rc; @@ -2266,7 +2266,7 @@ static int fan_read(char *p) (status != 0) ? "enabled" : "disabled", status); break; - case IBMACPI_FAN_RD_TPEC: + case TPACPI_FAN_RD_TPEC: /* all except 570, 600e/x, 770e, 770x */ if ((rc = fan_get_status(&status)) < 0) return rc; @@ -2277,7 +2277,7 @@ static int fan_read(char *p) else /* Return most likely status. In fact, it * might be the only possible status */ - status = IBMACPI_FAN_EC_AUTO; + status = TP_EC_FAN_AUTO; } len += sprintf(p + len, "status:\t\t%s\n", @@ -2291,25 +2291,25 @@ static int fan_read(char *p) len += sprintf(p + len, "speed:\t\t%d\n", speed); - if (status & IBMACPI_FAN_EC_DISENGAGED) + if (status & TP_EC_FAN_FULLSPEED) /* Disengaged mode takes precedence */ len += sprintf(p + len, "level:\t\tdisengaged\n"); - else if (status & IBMACPI_FAN_EC_AUTO) + else if (status & TP_EC_FAN_AUTO) len += sprintf(p + len, "level:\t\tauto\n"); else len += sprintf(p + len, "level:\t\t%d\n", status); break; - case IBMACPI_FAN_NONE: + case TPACPI_FAN_NONE: default: len += sprintf(p + len, "status:\t\tnot supported\n"); } - if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) { + if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { len += sprintf(p + len, "commands:\tlevel "); switch (fan_control_access_mode) { - case IBMACPI_FAN_WR_ACPI_SFAN: + case TPACPI_FAN_WR_ACPI_SFAN: len += sprintf(p + len, " ( is 0-7)\n"); break; @@ -2320,12 +2320,12 @@ static int fan_read(char *p) } } - if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE) + if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) len += sprintf(p + len, "commands:\tenable, disable\n" "commands:\twatchdog ( is 0 (off), " "1-120 (seconds))\n"); - if (fan_control_commands & IBMACPI_FAN_CMD_SPEED) + if (fan_control_commands & TPACPI_FAN_CMD_SPEED) len += sprintf(p + len, "commands:\tspeed " " ( is 0-65535)\n"); @@ -2337,9 +2337,9 @@ static int fan_write_cmd_level(const char *cmd, int *rc) int level; if (strlencmp(cmd, "level auto") == 0) - level = IBMACPI_FAN_EC_AUTO; + level = TP_EC_FAN_AUTO; else if (strlencmp(cmd, "level disengaged") == 0) - level = IBMACPI_FAN_EC_DISENGAGED; + level = TP_EC_FAN_FULLSPEED; else if (sscanf(cmd, "level %d", &level) != 1) return 0; @@ -2412,13 +2412,13 @@ static int fan_write(char *buf) int rc = 0; while (!rc && (cmd = next_cmd(&buf))) { - if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) && + if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) && fan_write_cmd_level(cmd, &rc)) && - !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) && + !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) && (fan_write_cmd_enable(cmd, &rc) || fan_write_cmd_disable(cmd, &rc) || fan_write_cmd_watchdog(cmd, &rc))) && - !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) && + !((fan_control_commands & TPACPI_FAN_CMD_SPEED) && fan_write_cmd_speed(cmd, &rc)) ) rc = -EINVAL; diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 8b2fd1a1a8a1..02a297e0525f 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -256,29 +256,27 @@ enum { /* Fan control constants */ fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) * 0x84 must be read before 0x85 */ - IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer - * disengaged */ - IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan - * control */ + TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ + TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ }; enum fan_status_access_mode { - IBMACPI_FAN_NONE = 0, /* No fan status or control */ - IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ - IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ + TPACPI_FAN_NONE = 0, /* No fan status or control */ + TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ + TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ }; enum fan_control_access_mode { - IBMACPI_FAN_WR_NONE = 0, /* No fan control */ - IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ - IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ - IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ + TPACPI_FAN_WR_NONE = 0, /* No fan control */ + TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */ + TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */ + TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */ }; enum fan_control_commands { - IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ - IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ - IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, + TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */ + TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */ + TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd, * and also watchdog cmd */ }; @@ -333,16 +331,16 @@ static int hotkey_write(char *buf); */ enum led_access_mode { - IBMACPI_LED_NONE = 0, - IBMACPI_LED_570, /* 570 */ - IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ - IBMACPI_LED_NEW, /* all others */ + TPACPI_LED_NONE = 0, + TPACPI_LED_570, /* 570 */ + TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */ + TPACPI_LED_NEW, /* all others */ }; -enum { /* For IBMACPI_LED_OLD */ - IBMACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ - IBMACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ - IBMACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ +enum { /* For TPACPI_LED_OLD */ + TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */ + TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */ + TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */ }; static enum led_access_mode led_supported; @@ -370,16 +368,16 @@ static int light_write(char *buf); */ enum thermal_access_mode { - IBMACPI_THERMAL_NONE = 0, /* No thermal support */ - IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ - IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ - IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ - IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ + TPACPI_THERMAL_NONE = 0, /* No thermal support */ + TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */ + TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */ + TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */ + TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ }; -#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ +#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ struct ibm_thermal_sensors_struct { - s32 temp[IBMACPI_MAX_THERMAL_SENSORS]; + s32 temp[TPACPI_MAX_THERMAL_SENSORS]; }; static int thermal_init(void); @@ -392,10 +390,10 @@ static int thermal_read(char *p); */ enum video_access_mode { - IBMACPI_VIDEO_NONE = 0, - IBMACPI_VIDEO_570, /* 570 */ - IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */ - IBMACPI_VIDEO_NEW, /* all others */ + TPACPI_VIDEO_NONE = 0, + TPACPI_VIDEO_570, /* 570 */ + TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */ + TPACPI_VIDEO_NEW, /* all others */ }; static enum video_access_mode video_supported; -- cgit v1.2.3-59-g8ed1b From 132ce09123755ec5e3d3a8ae22f4f753c3baac97 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:30 -0300 Subject: ACPI: thinkpad-acpi: add debug mode Add a debug mode parameter and verbose debug mode Kconfig option. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 13 +++++++++++++ drivers/misc/Kconfig | 10 ++++++++++ drivers/misc/thinkpad_acpi.c | 3 +++ drivers/misc/thinkpad_acpi.h | 13 +++++++++++++ 4 files changed, 39 insertions(+) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index af18d294cf1a..82fd8228fd41 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -699,3 +699,16 @@ for example: modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable +Enabling debugging output +------------------------- + +The module takes a debug paramater which can be used to selectively +enable various classes of debugging output, for example: + + modprobe ibm_acpi debug=0xffff + +will enable all debugging output classes. It takes a bitmask, so +to enable more than one output class, just add their values. + +There is also a kernel build option to enable more debugging +information, which may be necessary to debug driver problems. diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 2cd96a3dff54..44e4c8fb7a74 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -137,6 +137,16 @@ config THINKPAD_ACPI If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. +config THINKPAD_ACPI_DEBUG + bool "Verbose debug mode" + depends on THINKPAD_ACPI + default n + ---help--- + Enables extra debugging information, at the expense of a slightly + increase in driver size. + + If you are not sure, say N here. + config THINKPAD_ACPI_DOCK bool "Legacy Docking Station Support" depends on THINKPAD_ACPI diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 4131a7875ad7..7fa906fd45c0 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2684,6 +2684,9 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp) static int experimental; module_param(experimental, int, 0); +static u32 dbg_level; +module_param_named(debug, dbg_level, uint, 0); + #define IBM_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0) diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 02a297e0525f..b2348d7a07c4 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -74,6 +74,18 @@ #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") #define strlencmp(a,b) (strncmp((a), (b), strlen(b))) +/* Debugging */ +#define TPACPI_DBG_ALL 0xffff +#define dbg_printk(a_dbg_level, format, arg...) \ + do { if (dbg_level & a_dbg_level) \ + printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0) +#ifdef CONFIG_THINKPAD_ACPI_DEBUG +#define vdbg_printk(a_dbg_level, format, arg...) \ + dbg_printk(a_dbg_level, format, ## arg) +#else +#define vdbg_printk(a_dbg_level, format, arg...) +#endif + /* ACPI HIDs */ #define IBM_HKEY_HID "IBM0068" #define IBM_PCI_HID "PNP0A03" @@ -112,6 +124,7 @@ static char *next_cmd(char **cmds); /* Module */ static int experimental; +static u32 dbg_level; static char *ibm_thinkpad_ec_found; static char* check_dmi_for_ec(void); -- cgit v1.2.3-59-g8ed1b From 5fba344cfdbaa79e6320da26c3db34dfb219a845 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:31 -0300 Subject: ACPI: thinkpad-acpi: clean up probing and move init to subdrivers Move most of the probing code to its own function, and most of the subdriver-specific init code into subdriver init functions. This allows us to not define pci_handle unless the dock subdriver is enabled, as well. This patch causes a minor userland interface change: if a subdriver doesn't detect a capability, /proc entries for it are not created anymore (as opposed to a /proc entry that just returned "unsupported"). Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 231 ++++++++++++++++++++++++++++--------------- drivers/misc/thinkpad_acpi.h | 4 +- 2 files changed, 151 insertions(+), 84 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 7fa906fd45c0..eeab39418c71 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -277,9 +277,9 @@ static int _sta(acpi_handle handle) * ACPI device model */ -static void __init ibm_handle_init(char *name, - acpi_handle * handle, acpi_handle parent, - char **paths, int num_paths, char **path) +static void ibm_handle_init(char *name, + acpi_handle *handle, acpi_handle parent, + char **paths, int num_paths, char **path) { int i; acpi_status status; @@ -351,8 +351,8 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); if (!ibm->driver) { - printk(IBM_ERR "kmalloc(ibm->driver) failed\n"); - return -1; + printk(IBM_ERR "kzalloc(ibm->driver) failed\n"); + return -ENOMEM; } sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name); @@ -364,7 +364,9 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", ibm->hid, ret); kfree(ibm->driver); - } + ibm->driver = NULL; + } else if (!ret) + ibm->driver_registered = 1; return ret; } @@ -495,6 +497,8 @@ static int hotkey_orig_mask; static int hotkey_init(void) { + IBM_HANDLE_INIT(hkey); + /* hotkey not supported on 570 */ hotkey_supported = hkey_handle != NULL; @@ -508,13 +512,14 @@ static int hotkey_init(void) return -ENODEV; } - return 0; + return (hotkey_supported)? 0 : 1; } static void hotkey_exit(void) { - if (hotkey_supported) + if (hotkey_supported) { hotkey_set(hotkey_orig_status, hotkey_orig_mask); + } } static void hotkey_notify(struct ibm_struct *ibm, u32 event) @@ -628,12 +633,14 @@ static int bluetooth_supported; static int bluetooth_init(void) { + IBM_HANDLE_INIT(hkey); + /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ bluetooth_supported = hkey_handle && acpi_evalf(hkey_handle, NULL, "GBDC", "qv"); - return 0; + return (bluetooth_supported)? 0 : 1; } static int bluetooth_status(void) @@ -697,10 +704,12 @@ static int wan_supported; static int wan_init(void) { + IBM_HANDLE_INIT(hkey); + wan_supported = hkey_handle && acpi_evalf(hkey_handle, NULL, "GWAN", "qv"); - return 0; + return (wan_supported)? 0 : 1; } static int wan_status(void) @@ -775,6 +784,9 @@ static int video_init(void) { int ivga; + IBM_HANDLE_INIT(vid); + IBM_HANDLE_INIT(vid2); + if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) /* G41, assume IVGA doesn't change */ vid_handle = vid2_handle; @@ -792,7 +804,7 @@ static int video_init(void) /* all others */ video_supported = TPACPI_VIDEO_NEW; - return 0; + return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1; } static void video_exit(void) @@ -979,6 +991,10 @@ IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ static int light_init(void) { + IBM_HANDLE_INIT(ledb); + IBM_HANDLE_INIT(lght); + IBM_HANDLE_INIT(cmos); + /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ light_supported = (cmos_handle || lght_handle) && !ledb_handle; @@ -988,7 +1004,7 @@ static int light_init(void) light_status_supported = acpi_evalf(ec_handle, NULL, "KBLT", "qv"); - return 0; + return (light_supported)? 0 : 1; } static int light_read(char *p) @@ -1044,9 +1060,6 @@ static int light_write(char *buf) * Dock subdriver */ -/* don't list other alternatives as we install a notify handler on the 570 */ -IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ - #ifdef CONFIG_THINKPAD_ACPI_DOCK IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ @@ -1055,8 +1068,19 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */ "\\_SB.PCI.ISA.SLCE", /* 570 */ ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */ +/* don't list other alternatives as we install a notify handler on the 570 */ +IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ + #define dock_docked() (_sta(dock_handle) & 1) +static int dock_init(void) +{ + IBM_HANDLE_INIT(dock); + IBM_HANDLE_INIT(pci); + + return (dock_handle)? 0 : 1; +} + static void dock_notify(struct ibm_struct *ibm, u32 event) { int docked = dock_docked(); @@ -1147,6 +1171,13 @@ IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ static int bay_init(void) { + IBM_HANDLE_INIT(bay); + if (bay_handle) + IBM_HANDLE_INIT(bay_ej); + IBM_HANDLE_INIT(bay2); + if (bay2_handle) + IBM_HANDLE_INIT(bay2_ej); + bay_status_supported = bay_handle && acpi_evalf(bay_handle, NULL, "_STA", "qv"); bay_status2_supported = bay2_handle && @@ -1157,7 +1188,8 @@ static int bay_init(void) bay_eject2_supported = bay2_handle && bay2_ej_handle && (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); - return 0; + return (bay_status_supported || bay_eject_supported || + bay_status2_supported || bay_eject2_supported)? 0 : 1; } static void bay_notify(struct ibm_struct *ibm, u32 event) @@ -1221,6 +1253,13 @@ static int bay_write(char *buf) * CMOS subdriver */ +static int cmos_init(void) +{ + IBM_HANDLE_INIT(cmos); + + return (cmos_handle)? 0 : 1; +} + static int cmos_eval(int cmos_cmd) { if (cmos_handle) @@ -1281,6 +1320,8 @@ IBM_HANDLE(led, ec, "SLED", /* 570 */ static int led_init(void) { + IBM_HANDLE_INIT(led); + if (!led_handle) /* led not supported on R30, R31 */ led_supported = TPACPI_LED_NONE; @@ -1294,7 +1335,7 @@ static int led_init(void) /* all others */ led_supported = TPACPI_LED_NEW; - return 0; + return (led_supported != TPACPI_LED_NONE)? 0 : 1; } #define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking")) @@ -1391,6 +1432,13 @@ static int led_write(char *buf) IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ +static int beep_init(void) +{ + IBM_HANDLE_INIT(beep); + + return (beep_handle)? 0 : 1; +} + static int beep_read(char *p) { int len = 0; @@ -1436,7 +1484,9 @@ static int thermal_init(void) { u8 t, ta1, ta2; int i; - int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); + int acpi_tmp7; + + acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); if (ibm_thinkpad_ec_found && experimental) { /* @@ -1492,7 +1542,7 @@ static int thermal_init(void) thermal_read_mode = TPACPI_THERMAL_NONE; } - return 0; + return (thermal_read_mode != TPACPI_THERMAL_NONE)? 0 : 1; } static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) @@ -1973,6 +2023,10 @@ static int fan_init(void) fan_control_status_known = 1; fan_watchdog_maxinterval = 0; + IBM_HANDLE_INIT(fans); + IBM_HANDLE_INIT(gfan); + IBM_HANDLE_INIT(sfan); + if (gfan_handle) { /* 570, 600e/x, 770e, 770x */ fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; @@ -2010,7 +2064,7 @@ static int fan_init(void) printk(IBM_ERR "ThinkPad ACPI EC access misbehaving, " "fan status and control unavailable\n"); - return 0; + return 1; } } @@ -2041,7 +2095,9 @@ static int fan_init(void) } } - return 0; + return (fan_status_access_mode != TPACPI_FAN_NONE || + fan_control_access_mode != TPACPI_FAN_WR_NONE)? + 0 : 1; } static int fan_get_status(u8 *status) @@ -2485,6 +2541,7 @@ static struct ibm_struct ibms[] = { #ifdef CONFIG_THINKPAD_ACPI_DOCK { .name = "dock", + .init = dock_init, .read = dock_read, .write = dock_write, .notify = dock_notify, @@ -2512,6 +2569,7 @@ static struct ibm_struct ibms[] = { #endif /* CONFIG_THINKPAD_ACPI_BAY */ { .name = "cmos", + .init = cmos_init, .read = cmos_read, .write = cmos_write, }, @@ -2523,6 +2581,7 @@ static struct ibm_struct ibms[] = { }, { .name = "beep", + .init = beep_init, .read = beep_read, .write = beep_write, }, @@ -2571,20 +2630,33 @@ static int __init ibm_init(struct ibm_struct *ibm) if (ibm->experimental && !experimental) return 0; - if (ibm->hid) { - ret = register_tpacpi_subdriver(ibm); - if (ret < 0) - return ret; - ibm->driver_registered = 1; - } - if (ibm->init) { ret = ibm->init(); - if (ret != 0) + if (ret > 0) + return 0; /* probe failed */ + if (ret) return ret; ibm->init_called = 1; } + if (ibm->hid) { + ret = register_tpacpi_subdriver(ibm); + if (ret) + goto err_out; + } + + if (ibm->notify) { + ret = setup_notify(ibm); + if (ret == -ENODEV) { + printk(IBM_NOTICE "disabling subdriver %s\n", + ibm->name); + ret = 0; + goto err_out; + } + if (ret < 0) + goto err_out; + } + if (ibm->read) { entry = create_proc_entry(ibm->name, S_IFREG | S_IRUGO | S_IWUSR, @@ -2592,7 +2664,8 @@ static int __init ibm_init(struct ibm_struct *ibm) if (!entry) { printk(IBM_ERR "unable to create proc entry %s\n", ibm->name); - return -ENODEV; + ret = -ENODEV; + goto err_out; } entry->owner = THIS_MODULE; entry->data = ibm; @@ -2602,36 +2675,36 @@ static int __init ibm_init(struct ibm_struct *ibm) ibm->proc_created = 1; } - if (ibm->notify) { - ret = setup_notify(ibm); - if (ret == -ENODEV) { - printk(IBM_NOTICE "disabling subdriver %s\n", - ibm->name); - ibm_exit(ibm); - return 0; - } - if (ret < 0) - return ret; - } - return 0; + +err_out: + ibm_exit(ibm); + return (ret < 0)? ret : 0; } static void ibm_exit(struct ibm_struct *ibm) { - if (ibm->notify_installed) + if (ibm->notify_installed) { acpi_remove_notify_handler(*ibm->handle, ibm->type, dispatch_notify); + ibm->notify_installed = 0; + } - if (ibm->proc_created) + if (ibm->proc_created) { remove_proc_entry(ibm->name, proc_dir); - - if (ibm->init_called && ibm->exit) - ibm->exit(); + ibm->proc_created = 0; + } if (ibm->driver_registered) { acpi_bus_unregister_driver(ibm->driver); kfree(ibm->driver); + ibm->driver = NULL; + ibm->driver_registered = 0; + } + + if (ibm->init_called && ibm->exit) { + ibm->exit(); + ibm->init_called = 0; } } @@ -2663,6 +2736,32 @@ static char* __init check_dmi_for_ec(void) return NULL; } +static int __init probe_for_thinkpad(void) +{ + int is_thinkpad; + + if (acpi_disabled) + return -ENODEV; + + /* + * Non-ancient models have better DMI tagging, but very old models + * don't. + */ + is_thinkpad = dmi_name_in_vendors("ThinkPad"); + + /* ec is required because many other handles are relative to it */ + IBM_HANDLE_INIT(ec); + if (!ec_handle) { + if (is_thinkpad) + printk(IBM_ERR + "Not yet supported ThinkPad detected!\n"); + return -ENODEV; + } + + return 0; +} + + /* Module init, exit, parameters */ static int __init set_ibm_param(const char *val, struct kernel_param *kp) @@ -2712,45 +2811,13 @@ static int __init thinkpad_acpi_module_init(void) { int ret, i; - if (acpi_disabled) - return -ENODEV; + ret = probe_for_thinkpad(); + if (ret) + return ret; - /* ec is required because many other handles are relative to it */ - IBM_HANDLE_INIT(ec); - if (!ec_handle) { - printk(IBM_ERR "ec object not found\n"); - return -ENODEV; - } - - /* Models with newer firmware report the EC in DMI */ ibm_thinkpad_ec_found = check_dmi_for_ec(); - - /* these handles are not required */ - IBM_HANDLE_INIT(vid); - IBM_HANDLE_INIT(vid2); - IBM_HANDLE_INIT(ledb); - IBM_HANDLE_INIT(led); - IBM_HANDLE_INIT(hkey); - IBM_HANDLE_INIT(lght); - IBM_HANDLE_INIT(cmos); -#ifdef CONFIG_THINKPAD_ACPI_DOCK - IBM_HANDLE_INIT(dock); -#endif - IBM_HANDLE_INIT(pci); -#ifdef CONFIG_THINKPAD_ACPI_BAY - IBM_HANDLE_INIT(bay); - if (bay_handle) - IBM_HANDLE_INIT(bay_ej); - IBM_HANDLE_INIT(bay2); - if (bay2_handle) - IBM_HANDLE_INIT(bay2_ej); -#endif /* CONFIG_THINKPAD_ACPI_BAY */ - IBM_HANDLE_INIT(beep); IBM_HANDLE_INIT(ecrd); IBM_HANDLE_INIT(ecwr); - IBM_HANDLE_INIT(fans); - IBM_HANDLE_INIT(gfan); - IBM_HANDLE_INIT(sfan); proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); if (!proc_dir) { diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index b2348d7a07c4..06d4c3839afd 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -104,7 +104,7 @@ static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */ static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */ static void ibm_handle_init(char *name, - acpi_handle * handle, acpi_handle parent, + acpi_handle *handle, acpi_handle parent, char **paths, int num_paths, char **path); #define IBM_HANDLE_INIT(object) \ ibm_handle_init(#object, &object##_handle, *object##_parent, \ @@ -242,8 +242,8 @@ static int cmos_write(char *buf); * Dock subdriver */ -static acpi_handle pci_handle; #ifdef CONFIG_THINKPAD_ACPI_DOCK +static acpi_handle pci_handle; static acpi_handle dock_handle; static void dock_notify(struct ibm_struct *ibm, u32 event); -- cgit v1.2.3-59-g8ed1b From fe08bc4b4fd1371fad111675a564e4d2ebbf39ea Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:32 -0300 Subject: ACPI: thinkpad-acpi: add subdriver debug statements Add debug messages to the subdriver initialization and exit code. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 4 ++ drivers/misc/thinkpad_acpi.c | 111 ++++++++++++++++++++++++++++++++++++++++ drivers/misc/thinkpad_acpi.h | 4 ++ 3 files changed, 119 insertions(+) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index 82fd8228fd41..20d5ec309cbd 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -710,5 +710,9 @@ enable various classes of debugging output, for example: will enable all debugging output classes. It takes a bitmask, so to enable more than one output class, just add their values. + Debug bitmask Description + 0x0001 Initialization and probing + 0x0002 Removal + There is also a kernel build option to enable more debugging information, which may be necessary to debug driver problems. diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index eeab39418c71..e8fc8da35669 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -313,6 +313,9 @@ static int __init setup_notify(struct ibm_struct *ibm) if (!*ibm->handle) return 0; + dbg_printk(TPACPI_DBG_INIT, + "setting up ACPI notify for %s\n", ibm->name); + ret = acpi_bus_get_device(*ibm->handle, &ibm->device); if (ret < 0) { printk(IBM_ERR "%s device not present\n", ibm->name); @@ -349,6 +352,9 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) { int ret; + dbg_printk(TPACPI_DBG_INIT, + "registering %s as an ACPI driver\n", ibm->name); + ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); if (!ibm->driver) { printk(IBM_ERR "kzalloc(ibm->driver) failed\n"); @@ -497,17 +503,25 @@ static int hotkey_orig_mask; static int hotkey_init(void) { + vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); + IBM_HANDLE_INIT(hkey); /* hotkey not supported on 570 */ hotkey_supported = hkey_handle != NULL; + vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", + str_supported(hotkey_supported)); + if (hotkey_supported) { /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, A30, R30, R31, T20-22, X20-21, X22-24 */ hotkey_mask_supported = acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); + vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", + str_supported(hotkey_mask_supported)); + if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask)) return -ENODEV; } @@ -518,6 +532,7 @@ static int hotkey_init(void) static void hotkey_exit(void) { if (hotkey_supported) { + dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n"); hotkey_set(hotkey_orig_status, hotkey_orig_mask); } } @@ -633,6 +648,8 @@ static int bluetooth_supported; static int bluetooth_init(void) { + vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); + IBM_HANDLE_INIT(hkey); /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, @@ -640,6 +657,9 @@ static int bluetooth_init(void) bluetooth_supported = hkey_handle && acpi_evalf(hkey_handle, NULL, "GBDC", "qv"); + vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s\n", + str_supported(bluetooth_supported)); + return (bluetooth_supported)? 0 : 1; } @@ -704,11 +724,16 @@ static int wan_supported; static int wan_init(void) { + vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); + IBM_HANDLE_INIT(hkey); wan_supported = hkey_handle && acpi_evalf(hkey_handle, NULL, "GWAN", "qv"); + vdbg_printk(TPACPI_DBG_INIT, "wan is %s\n", + str_supported(wan_supported)); + return (wan_supported)? 0 : 1; } @@ -784,6 +809,8 @@ static int video_init(void) { int ivga; + vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); + IBM_HANDLE_INIT(vid); IBM_HANDLE_INIT(vid2); @@ -804,11 +831,16 @@ static int video_init(void) /* all others */ video_supported = TPACPI_VIDEO_NEW; + vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n", + str_supported(video_supported != TPACPI_VIDEO_NONE), + video_supported); + return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1; } static void video_exit(void) { + dbg_printk(TPACPI_DBG_EXIT, "restoring original video autoswitch mode\n"); acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw); } @@ -991,6 +1023,8 @@ IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ static int light_init(void) { + vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); + IBM_HANDLE_INIT(ledb); IBM_HANDLE_INIT(lght); IBM_HANDLE_INIT(cmos); @@ -1004,6 +1038,9 @@ static int light_init(void) light_status_supported = acpi_evalf(ec_handle, NULL, "KBLT", "qv"); + vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", + str_supported(light_supported)); + return (light_supported)? 0 : 1; } @@ -1075,9 +1112,14 @@ IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ static int dock_init(void) { + vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); + IBM_HANDLE_INIT(dock); IBM_HANDLE_INIT(pci); + vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n", + str_supported(dock_handle != NULL)); + return (dock_handle)? 0 : 1; } @@ -1171,6 +1213,8 @@ IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ static int bay_init(void) { + vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); + IBM_HANDLE_INIT(bay); if (bay_handle) IBM_HANDLE_INIT(bay_ej); @@ -1188,6 +1232,13 @@ static int bay_init(void) bay_eject2_supported = bay2_handle && bay2_ej_handle && (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); + vdbg_printk(TPACPI_DBG_INIT, + "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n", + str_supported(bay_status_supported), + str_supported(bay_eject_supported), + str_supported(bay_status2_supported), + str_supported(bay_eject2_supported)); + return (bay_status_supported || bay_eject_supported || bay_status2_supported || bay_eject2_supported)? 0 : 1; } @@ -1255,8 +1306,13 @@ static int bay_write(char *buf) static int cmos_init(void) { + vdbg_printk(TPACPI_DBG_INIT, + "initializing cmos commands subdriver\n"); + IBM_HANDLE_INIT(cmos); + vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", + str_supported(cmos_handle != NULL)); return (cmos_handle)? 0 : 1; } @@ -1320,6 +1376,8 @@ IBM_HANDLE(led, ec, "SLED", /* 570 */ static int led_init(void) { + vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); + IBM_HANDLE_INIT(led); if (!led_handle) @@ -1335,6 +1393,9 @@ static int led_init(void) /* all others */ led_supported = TPACPI_LED_NEW; + vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n", + str_supported(led_supported), led_supported); + return (led_supported != TPACPI_LED_NONE)? 0 : 1; } @@ -1434,8 +1495,13 @@ IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ static int beep_init(void) { + vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); + IBM_HANDLE_INIT(beep); + vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", + str_supported(beep_handle != NULL)); + return (beep_handle)? 0 : 1; } @@ -1486,6 +1552,8 @@ static int thermal_init(void) int i; int acpi_tmp7; + vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); + acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); if (ibm_thinkpad_ec_found && experimental) { @@ -1542,6 +1610,10 @@ static int thermal_init(void) thermal_read_mode = TPACPI_THERMAL_NONE; } + vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n", + str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), + thermal_read_mode); + return (thermal_read_mode != TPACPI_THERMAL_NONE)? 0 : 1; } @@ -1698,6 +1770,8 @@ static int brightness_init(void) { int b; + vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); + b = brightness_get(NULL); if (b < 0) return b; @@ -1708,6 +1782,7 @@ static int brightness_init(void) printk(IBM_ERR "Could not register backlight device\n"); return PTR_ERR(ibm_backlight_device); } + vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); ibm_backlight_device->props.max_brightness = 7; ibm_backlight_device->props.brightness = b; @@ -1719,6 +1794,8 @@ static int brightness_init(void) static void brightness_exit(void) { if (ibm_backlight_device) { + vdbg_printk(TPACPI_DBG_EXIT, + "calling backlight_device_unregister()\n"); backlight_device_unregister(ibm_backlight_device); ibm_backlight_device = NULL; } @@ -2017,6 +2094,8 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ static int fan_init(void) { + vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); + fan_status_access_mode = TPACPI_FAN_NONE; fan_control_access_mode = TPACPI_FAN_WR_NONE; fan_control_commands = 0; @@ -2095,6 +2174,11 @@ static int fan_init(void) } } + vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n", + str_supported(fan_status_access_mode != TPACPI_FAN_NONE || + fan_control_access_mode != TPACPI_FAN_WR_NONE), + fan_status_access_mode, fan_control_access_mode); + return (fan_status_access_mode != TPACPI_FAN_NONE || fan_control_access_mode != TPACPI_FAN_WR_NONE)? 0 : 1; @@ -2138,6 +2222,7 @@ static int fan_get_status(u8 *status) static void fan_exit(void) { + vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending watchdogs\n"); cancel_delayed_work(&fan_watchdog_task); flush_scheduled_work(); } @@ -2622,6 +2707,15 @@ static struct ibm_struct ibms[] = { * Module and infrastructure proble, init and exit handling */ +#ifdef CONFIG_THINKPAD_ACPI_DEBUG +static const char * str_supported(int is_supported) +{ + static const char * const text_unsupported = "not supported"; + + return (is_supported)? text_unsupported + 4 : text_unsupported; +} +#endif /* CONFIG_THINKPAD_ACPI_DEBUG */ + static int __init ibm_init(struct ibm_struct *ibm) { int ret; @@ -2630,6 +2724,9 @@ static int __init ibm_init(struct ibm_struct *ibm) if (ibm->experimental && !experimental) return 0; + dbg_printk(TPACPI_DBG_INIT, + "probing for %s\n", ibm->name); + if (ibm->init) { ret = ibm->init(); if (ret > 0) @@ -2657,6 +2754,9 @@ static int __init ibm_init(struct ibm_struct *ibm) goto err_out; } + dbg_printk(TPACPI_DBG_INIT, + "%s installed\n", ibm->name); + if (ibm->read) { entry = create_proc_entry(ibm->name, S_IFREG | S_IRUGO | S_IWUSR, @@ -2678,24 +2778,35 @@ static int __init ibm_init(struct ibm_struct *ibm) return 0; err_out: + dbg_printk(TPACPI_DBG_INIT, + "%s: at error exit path with result %d\n", + ibm->name, ret); + ibm_exit(ibm); return (ret < 0)? ret : 0; } static void ibm_exit(struct ibm_struct *ibm) { + dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); if (ibm->notify_installed) { + dbg_printk(TPACPI_DBG_EXIT, + "%s: acpi_remove_notify_handler\n", ibm->name); acpi_remove_notify_handler(*ibm->handle, ibm->type, dispatch_notify); ibm->notify_installed = 0; } if (ibm->proc_created) { + dbg_printk(TPACPI_DBG_EXIT, + "%s: remove_proc_entry\n", ibm->name); remove_proc_entry(ibm->name, proc_dir); ibm->proc_created = 0; } if (ibm->driver_registered) { + dbg_printk(TPACPI_DBG_EXIT, + "%s: acpi_bus_unregister_driver\n", ibm->name); acpi_bus_unregister_driver(ibm->driver); kfree(ibm->driver); ibm->driver = NULL; diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 06d4c3839afd..beb1447a7f3f 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -76,12 +76,16 @@ /* Debugging */ #define TPACPI_DBG_ALL 0xffff +#define TPACPI_DBG_ALL 0xffff +#define TPACPI_DBG_INIT 0x0001 +#define TPACPI_DBG_EXIT 0x0002 #define dbg_printk(a_dbg_level, format, arg...) \ do { if (dbg_level & a_dbg_level) \ printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0) #ifdef CONFIG_THINKPAD_ACPI_DEBUG #define vdbg_printk(a_dbg_level, format, arg...) \ dbg_printk(a_dbg_level, format, ## arg) +static const char *str_supported(int is_supported); #else #define vdbg_printk(a_dbg_level, format, arg...) #endif -- cgit v1.2.3-59-g8ed1b From a5763f2223ce3fdbc75923f8c948fc7b59ed2f96 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:33 -0300 Subject: ACPI: thinkpad-acpi: uncouple subdriver init from ibms struct Move the .init method from ibms struct to another struct, and use a list head to control which subdrivers have been activated. This allows us to have the subdriver init methods marked __init, saving quite a lot of .text size, and even a bit of .data size as some data can now be made __initdata. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 402 ++++++++++++++++++++++++++----------------- drivers/misc/thinkpad_acpi.h | 51 +++--- 2 files changed, 278 insertions(+), 175 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index e8fc8da35669..56112684967b 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -470,7 +470,7 @@ static char *next_cmd(char **cmds) * thinkpad-acpi init subdriver */ -static int thinkpad_acpi_driver_init(void) +static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) { printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); printk(IBM_INFO "%s\n", IBM_URL); @@ -492,6 +492,11 @@ static int thinkpad_acpi_driver_read(char *p) return len; } +static struct ibm_struct thinkpad_acpi_driver_data = { + .name = "driver", + .read = thinkpad_acpi_driver_read, +}; + /************************************************************************* * Hotkey subdriver */ @@ -501,7 +506,7 @@ static int hotkey_mask_supported; static int hotkey_orig_status; static int hotkey_orig_mask; -static int hotkey_init(void) +static int __init hotkey_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); @@ -640,13 +645,24 @@ static int hotkey_write(char *buf) return 0; } +static struct ibm_struct hotkey_driver_data = { + .name = "hotkey", + .hid = IBM_HKEY_HID, + .read = hotkey_read, + .write = hotkey_write, + .exit = hotkey_exit, + .notify = hotkey_notify, + .handle = &hkey_handle, + .type = ACPI_DEVICE_NOTIFY, +}; + /************************************************************************* * Bluetooth subdriver */ static int bluetooth_supported; -static int bluetooth_init(void) +static int __init bluetooth_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); @@ -716,13 +732,19 @@ static int bluetooth_write(char *buf) return 0; } +static struct ibm_struct bluetooth_driver_data = { + .name = "bluetooth", + .read = bluetooth_read, + .write = bluetooth_write, +}; + /************************************************************************* * Wan subdriver */ static int wan_supported; -static int wan_init(void) +static int __init wan_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); @@ -789,6 +811,13 @@ static int wan_write(char *buf) return 0; } +static struct ibm_struct wan_driver_data = { + .name = "wan", + .read = wan_read, + .write = wan_write, + .experimental = 1, +}; + /************************************************************************* * Video subdriver */ @@ -805,7 +834,7 @@ IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */ IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */ -static int video_init(void) +static int __init video_init(struct ibm_init_struct *iibm) { int ivga; @@ -1011,6 +1040,13 @@ static int video_write(char *buf) return 0; } +static struct ibm_struct video_driver_data = { + .name = "video", + .read = video_read, + .write = video_write, + .exit = video_exit, +}; + /************************************************************************* * Light (thinklight) subdriver */ @@ -1021,7 +1057,7 @@ static int light_status_supported; IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ -static int light_init(void) +static int __init light_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); @@ -1093,6 +1129,12 @@ static int light_write(char *buf) return 0; } +static struct ibm_struct light_driver_data = { + .name = "light", + .read = light_read, + .write = light_write, +}; + /************************************************************************* * Dock subdriver */ @@ -1110,7 +1152,7 @@ IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */ #define dock_docked() (_sta(dock_handle) & 1) -static int dock_init(void) +static int __init dock_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); @@ -1184,6 +1226,24 @@ static int dock_write(char *buf) return 0; } +static struct ibm_struct dock_driver_data[2] = { + { + .name = "dock", + .read = dock_read, + .write = dock_write, + .notify = dock_notify, + .handle = &dock_handle, + .type = ACPI_SYSTEM_NOTIFY, + }, + { + .name = "dock", + .hid = IBM_PCI_HID, + .notify = dock_notify, + .handle = &pci_handle, + .type = ACPI_SYSTEM_NOTIFY, + }, +}; + #endif /* CONFIG_THINKPAD_ACPI_DOCK */ /************************************************************************* @@ -1211,7 +1271,7 @@ IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */ "_EJ0", /* 770x */ ); /* all others */ -static int bay_init(void) +static int __init bay_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); @@ -1298,13 +1358,23 @@ static int bay_write(char *buf) return 0; } + +static struct ibm_struct bay_driver_data = { + .name = "bay", + .read = bay_read, + .write = bay_write, + .notify = bay_notify, + .handle = &bay_handle, + .type = ACPI_SYSTEM_NOTIFY, +}; + #endif /* CONFIG_THINKPAD_ACPI_BAY */ /************************************************************************* * CMOS subdriver */ -static int cmos_init(void) +static int __init cmos_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing cmos commands subdriver\n"); @@ -1362,6 +1432,11 @@ static int cmos_write(char *buf) return 0; } +static struct ibm_struct cmos_driver_data = { + .name = "cmos", + .read = cmos_read, + .write = cmos_write, +}; /************************************************************************* * LED subdriver @@ -1374,7 +1449,7 @@ IBM_HANDLE(led, ec, "SLED", /* 570 */ "LED", /* all others */ ); /* R30, R31 */ -static int led_init(void) +static int __init led_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); @@ -1487,13 +1562,19 @@ static int led_write(char *buf) return 0; } +static struct ibm_struct led_driver_data = { + .name = "led", + .read = led_read, + .write = led_write, +}; + /************************************************************************* * Beep subdriver */ IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */ -static int beep_init(void) +static int __init beep_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); @@ -1540,13 +1621,19 @@ static int beep_write(char *buf) return 0; } +static struct ibm_struct beep_driver_data = { + .name = "beep", + .read = beep_read, + .write = beep_write, +}; + /************************************************************************* * Thermal subdriver */ static enum thermal_access_mode thermal_read_mode; -static int thermal_init(void) +static int __init thermal_init(struct ibm_init_struct *iibm) { u8 t, ta1, ta2; int i; @@ -1692,6 +1779,11 @@ static int thermal_read(char *p) return len; } +static struct ibm_struct thermal_driver_data = { + .name = "thermal", + .read = thermal_read, +}; + /************************************************************************* * EC Dump subdriver */ @@ -1755,6 +1847,13 @@ static int ecdump_write(char *buf) return 0; } +static struct ibm_struct ecdump_driver_data = { + .name = "ecdump", + .read = ecdump_read, + .write = ecdump_write, + .experimental = 1, +}; + /************************************************************************* * Backlight/brightness subdriver */ @@ -1766,7 +1865,7 @@ static struct backlight_ops ibm_backlight_data = { .update_status = brightness_update_status, }; -static int brightness_init(void) +static int __init brightness_init(struct ibm_init_struct *iibm) { int b; @@ -1883,6 +1982,13 @@ static int brightness_write(char *buf) return 0; } +static struct ibm_struct brightness_driver_data = { + .name = "brightness", + .read = brightness_read, + .write = brightness_write, + .exit = brightness_exit, +}; + /************************************************************************* * Volume subdriver */ @@ -1967,6 +2073,11 @@ static int volume_write(char *buf) return 0; } +static struct ibm_struct volume_driver_data = { + .name = "volume", + .read = volume_read, + .write = volume_write, +}; /************************************************************************* * Fan subdriver @@ -2092,7 +2203,7 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ "JFNS", /* 770x-JL */ ); /* all others */ -static int fan_init(void) +static int __init fan_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); @@ -2568,6 +2679,14 @@ static int fan_write(char *buf) return rc; } +static struct ibm_struct fan_driver_data = { + .name = "fan", + .read = fan_read, + .write = fan_write, + .exit = fan_exit, + .experimental = 1, +}; + /**************************************************************************** **************************************************************************** * @@ -2580,159 +2699,45 @@ static int fan_write(char *buf) static struct proc_dir_entry *proc_dir = NULL; /* Subdriver registry */ -static struct ibm_struct ibms[] = { - { - .name = "driver", - .init = thinkpad_acpi_driver_init, - .read = thinkpad_acpi_driver_read, - }, - { - .name = "hotkey", - .hid = IBM_HKEY_HID, - .init = hotkey_init, - .read = hotkey_read, - .write = hotkey_write, - .exit = hotkey_exit, - .notify = hotkey_notify, - .handle = &hkey_handle, - .type = ACPI_DEVICE_NOTIFY, - }, - { - .name = "bluetooth", - .init = bluetooth_init, - .read = bluetooth_read, - .write = bluetooth_write, - }, - { - .name = "wan", - .init = wan_init, - .read = wan_read, - .write = wan_write, - .experimental = 1, - }, - { - .name = "video", - .init = video_init, - .read = video_read, - .write = video_write, - .exit = video_exit, - }, - { - .name = "light", - .init = light_init, - .read = light_read, - .write = light_write, - }, -#ifdef CONFIG_THINKPAD_ACPI_DOCK - { - .name = "dock", - .init = dock_init, - .read = dock_read, - .write = dock_write, - .notify = dock_notify, - .handle = &dock_handle, - .type = ACPI_SYSTEM_NOTIFY, - }, - { - .name = "dock", - .hid = IBM_PCI_HID, - .notify = dock_notify, - .handle = &pci_handle, - .type = ACPI_SYSTEM_NOTIFY, - }, -#endif -#ifdef CONFIG_THINKPAD_ACPI_BAY - { - .name = "bay", - .init = bay_init, - .read = bay_read, - .write = bay_write, - .notify = bay_notify, - .handle = &bay_handle, - .type = ACPI_SYSTEM_NOTIFY, - }, -#endif /* CONFIG_THINKPAD_ACPI_BAY */ - { - .name = "cmos", - .init = cmos_init, - .read = cmos_read, - .write = cmos_write, - }, - { - .name = "led", - .init = led_init, - .read = led_read, - .write = led_write, - }, - { - .name = "beep", - .init = beep_init, - .read = beep_read, - .write = beep_write, - }, - { - .name = "thermal", - .init = thermal_init, - .read = thermal_read, - }, - { - .name = "ecdump", - .read = ecdump_read, - .write = ecdump_write, - .experimental = 1, - }, - { - .name = "brightness", - .read = brightness_read, - .write = brightness_write, - .init = brightness_init, - .exit = brightness_exit, - }, - { - .name = "volume", - .read = volume_read, - .write = volume_write, - }, - { - .name = "fan", - .read = fan_read, - .write = fan_write, - .init = fan_init, - .exit = fan_exit, - .experimental = 1, - }, -}; +static LIST_HEAD(tpacpi_all_drivers); + /* * Module and infrastructure proble, init and exit handling */ #ifdef CONFIG_THINKPAD_ACPI_DEBUG -static const char * str_supported(int is_supported) +static const char * __init str_supported(int is_supported) { - static const char * const text_unsupported = "not supported"; + static char text_unsupported[] __initdata = "not supported"; - return (is_supported)? text_unsupported + 4 : text_unsupported; + return (is_supported)? &text_unsupported[4] : &text_unsupported[0]; } #endif /* CONFIG_THINKPAD_ACPI_DEBUG */ -static int __init ibm_init(struct ibm_struct *ibm) +static int __init ibm_init(struct ibm_init_struct *iibm) { int ret; + struct ibm_struct *ibm = iibm->data; struct proc_dir_entry *entry; + BUG_ON(ibm == NULL); + + INIT_LIST_HEAD(&ibm->all_drivers); + if (ibm->experimental && !experimental) return 0; dbg_printk(TPACPI_DBG_INIT, "probing for %s\n", ibm->name); - if (ibm->init) { - ret = ibm->init(); + if (iibm->init) { + ret = iibm->init(iibm); if (ret > 0) return 0; /* probe failed */ if (ret) return ret; + ibm->init_called = 1; } @@ -2775,6 +2780,8 @@ static int __init ibm_init(struct ibm_struct *ibm) ibm->proc_created = 1; } + list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers); + return 0; err_out: @@ -2789,6 +2796,9 @@ err_out: static void ibm_exit(struct ibm_struct *ibm) { dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); + + list_del_init(&ibm->all_drivers); + if (ibm->notify_installed) { dbg_printk(TPACPI_DBG_EXIT, "%s: acpi_remove_notify_handler\n", ibm->name); @@ -2817,6 +2827,8 @@ static void ibm_exit(struct ibm_struct *ibm) ibm->exit(); ibm->init_called = 0; } + + dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); } /* Probing */ @@ -2875,18 +2887,95 @@ static int __init probe_for_thinkpad(void) /* Module init, exit, parameters */ +static struct ibm_init_struct ibms_init[] __initdata = { + { + .init = thinkpad_acpi_driver_init, + .data = &thinkpad_acpi_driver_data, + }, + { + .init = hotkey_init, + .data = &hotkey_driver_data, + }, + { + .init = bluetooth_init, + .data = &bluetooth_driver_data, + }, + { + .init = wan_init, + .data = &wan_driver_data, + }, + { + .init = video_init, + .data = &video_driver_data, + }, + { + .init = light_init, + .data = &light_driver_data, + }, +#ifdef CONFIG_THINKPAD_ACPI_DOCK + { + .init = dock_init, + .data = &dock_driver_data[0], + }, + { + .data = &dock_driver_data[1], + }, +#endif +#ifdef CONFIG_THINKPAD_ACPI_BAY + { + .init = bay_init, + .data = &bay_driver_data, + }, +#endif + { + .init = cmos_init, + .data = &cmos_driver_data, + }, + { + .init = led_init, + .data = &led_driver_data, + }, + { + .init = beep_init, + .data = &beep_driver_data, + }, + { + .init = thermal_init, + .data = &thermal_driver_data, + }, + { + .data = &ecdump_driver_data, + }, + { + .init = brightness_init, + .data = &brightness_driver_data, + }, + { + .data = &volume_driver_data, + }, + { + .init = fan_init, + .data = &fan_driver_data, + }, +}; + static int __init set_ibm_param(const char *val, struct kernel_param *kp) { unsigned int i; + struct ibm_struct *ibm; - for (i = 0; i < ARRAY_SIZE(ibms); i++) - if (strcmp(ibms[i].name, kp->name) == 0 && ibms[i].write) { - if (strlen(val) > sizeof(ibms[i].param) - 2) + for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { + ibm = ibms_init[i].data; + BUG_ON(ibm == NULL); + + if (strcmp(ibm->name, kp->name) == 0 && ibm->write) { + if (strlen(val) > sizeof(ibms_init[i].param) - 2) return -ENOSPC; - strcpy(ibms[i].param, val); - strcat(ibms[i].param, ","); + strcpy(ibms_init[i].param, val); + strcat(ibms_init[i].param, ","); return 0; } + } return -EINVAL; } @@ -2938,10 +3027,10 @@ static int __init thinkpad_acpi_module_init(void) } proc_dir->owner = THIS_MODULE; - for (i = 0; i < ARRAY_SIZE(ibms); i++) { - ret = ibm_init(&ibms[i]); - if (ret >= 0 && *ibms[i].param) - ret = ibms[i].write(ibms[i].param); + for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { + ret = ibm_init(&ibms_init[i]); + if (ret >= 0 && *ibms_init[i].param) + ret = ibms_init[i].data->write(ibms_init[i].param); if (ret < 0) { thinkpad_acpi_module_exit(); return ret; @@ -2953,10 +3042,15 @@ static int __init thinkpad_acpi_module_init(void) static void thinkpad_acpi_module_exit(void) { - int i; + struct ibm_struct *ibm, *itmp; + + list_for_each_entry_safe_reverse(ibm, itmp, + &tpacpi_all_drivers, + all_drivers) { + ibm_exit(ibm); + } - for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--) - ibm_exit(&ibms[i]); + dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); if (proc_dir) remove_proc_entry(IBM_DIR, acpi_root_dir); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index beb1447a7f3f..97467b71b727 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -116,8 +117,6 @@ static void ibm_handle_init(char *name, /* procfs support */ static struct proc_dir_entry *proc_dir; -static int thinkpad_acpi_driver_init(void); -static int thinkpad_acpi_driver_read(char *p); /* procfs helpers */ static int dispatch_read(char *page, char **start, off_t off, int count, @@ -142,12 +141,10 @@ static void thinkpad_acpi_module_exit(void); struct ibm_struct { char *name; - char param[32]; char *hid; struct acpi_driver *driver; - int (*init) (void); int (*read) (char *); int (*write) (char *); void (*exit) (void); @@ -157,6 +154,8 @@ struct ibm_struct { int type; struct acpi_device *device; + struct list_head all_drivers; + int driver_registered; int proc_created; int init_called; @@ -165,16 +164,26 @@ struct ibm_struct { int experimental; }; -static struct ibm_struct ibms[]; +struct ibm_init_struct { + char param[32]; + + int (*init) (struct ibm_init_struct *); + struct ibm_struct *data; +}; + +static struct list_head tpacpi_all_drivers; + +static struct ibm_init_struct ibms_init[]; static int set_ibm_param(const char *val, struct kernel_param *kp); -static int ibm_init(struct ibm_struct *ibm); +static int ibm_init(struct ibm_init_struct *iibm); static void ibm_exit(struct ibm_struct *ibm); -/* ACPI devices */ -static void dispatch_notify(acpi_handle handle, u32 event, void *data); -static int setup_notify(struct ibm_struct *ibm); -static int ibm_device_add(struct acpi_device *device); -static int register_tpacpi_subdriver(struct ibm_struct *ibm); + +/* + * procfs master subdriver + */ +static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm); +static int thinkpad_acpi_driver_read(char *p); /* @@ -188,7 +197,7 @@ static int bay_status2_supported, bay_eject2_supported; static acpi_handle bay_handle, bay_ej_handle; static acpi_handle bay2_handle, bay2_ej_handle; -static int bay_init(void); +static int bay_init(struct ibm_init_struct *iibm); static void bay_notify(struct ibm_struct *ibm, u32 event); static int bay_read(char *p); static int bay_write(char *buf); @@ -211,7 +220,7 @@ static int beep_write(char *buf); static int bluetooth_supported; -static int bluetooth_init(void); +static int bluetooth_init(struct ibm_init_struct *iibm); static int bluetooth_status(void); static int bluetooth_read(char *p); static int bluetooth_write(char *buf); @@ -224,7 +233,7 @@ static int bluetooth_write(char *buf); static struct backlight_device *ibm_backlight_device; static int brightness_offset = 0x31; -static int brightness_init(void); +static int brightness_init(struct ibm_init_struct *iibm); static void brightness_exit(void); static int brightness_get(struct backlight_device *bd); static int brightness_set(int value); @@ -306,7 +315,7 @@ static int fan_watchdog_maxinterval; static acpi_handle fans_handle, gfan_handle, sfan_handle; -static int fan_init(void); +static int fan_init(struct ibm_init_struct *iibm); static void fan_exit(void); static int fan_get_status(u8 *status); static int fan_get_speed(unsigned int *speed); @@ -334,7 +343,7 @@ static int hotkey_mask_supported; static int hotkey_orig_status; static int hotkey_orig_mask; -static int hotkey_init(void); +static int hotkey_init(struct ibm_init_struct *iibm); static void hotkey_exit(void); static int hotkey_get(int *status, int *mask); static int hotkey_set(int status, int mask); @@ -363,7 +372,7 @@ enum { /* For TPACPI_LED_OLD */ static enum led_access_mode led_supported; static acpi_handle led_handle; -static int led_init(void); +static int led_init(struct ibm_init_struct *iibm); static int led_read(char *p); static int led_write(char *buf); @@ -375,7 +384,7 @@ static int light_supported; static int light_status_supported; static acpi_handle lght_handle, ledb_handle; -static int light_init(void); +static int light_init(struct ibm_init_struct *iibm); static int light_read(char *p); static int light_write(char *buf); @@ -397,7 +406,7 @@ struct ibm_thermal_sensors_struct { s32 temp[TPACPI_MAX_THERMAL_SENSORS]; }; -static int thermal_init(void); +static int thermal_init(struct ibm_init_struct *iibm); static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); static int thermal_read(char *p); @@ -417,7 +426,7 @@ static enum video_access_mode video_supported; static int video_orig_autosw; static acpi_handle vid_handle, vid2_handle; -static int video_init(void); +static int video_init(struct ibm_init_struct *iibm); static void video_exit(void); static int video_status(void); static int video_autosw(void); @@ -444,7 +453,7 @@ static int volume_write(char *buf); static int wan_supported; -static int wan_init(void); +static int wan_init(struct ibm_init_struct *iibm); static int wan_status(void); static int wan_read(char *p); static int wan_write(char *buf); -- cgit v1.2.3-59-g8ed1b From 0dcef77c5b889338811d35e786b42046259fe433 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:34 -0300 Subject: ACPI: thinkpad-acpi: improve thinkpad detection Improve the detection of ThinkPads, so as to reduce the chances of false positives. Since this could potentially add false negatives on the very old models, add a module parameter to force the detection of a thinkpad. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 7 +++++++ drivers/misc/thinkpad_acpi.c | 13 +++++++++++++ drivers/misc/thinkpad_acpi.h | 1 + 3 files changed, 21 insertions(+) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index 20d5ec309cbd..1a42b77e2ece 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -716,3 +716,10 @@ to enable more than one output class, just add their values. There is also a kernel build option to enable more debugging information, which may be necessary to debug driver problems. + +Force loading of module +----------------------- + +If thinkpad-acpi refuses to detect your ThinkPad, you can try to specify +the module parameter force_load=1. Regardless of whether this works or +not, please contact ibm-acpi-devel@lists.sourceforge.net with a report. diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 56112684967b..cddf81bb2d97 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2881,6 +2881,16 @@ static int __init probe_for_thinkpad(void) return -ENODEV; } + /* + * Risks a regression on very old machines, but reduces potential + * false positives a damn great deal + */ + if (!is_thinkpad) + is_thinkpad = dmi_name_in_vendors("IBM"); + + if (!is_thinkpad && !force_load) + return -ENODEV; + return 0; } @@ -2986,6 +2996,9 @@ module_param(experimental, int, 0); static u32 dbg_level; module_param_named(debug, dbg_level, uint, 0); +static int force_load; +module_param(force_load, int, 0); + #define IBM_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0) diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 97467b71b727..20203981cb7a 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -128,6 +128,7 @@ static char *next_cmd(char **cmds); /* Module */ static int experimental; static u32 dbg_level; +static int force_load; static char *ibm_thinkpad_ec_found; static char* check_dmi_for_ec(void); -- cgit v1.2.3-59-g8ed1b From 926411779287ad4f7013c9d80aa44fd131b70cd9 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:35 -0300 Subject: ACPI: thinkpad-acpi: use bitfields to hold subdriver flags Save some memory by using bitfields to hold boolean flags for the subdrivers. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 32 ++++++++++++++++---------------- drivers/misc/thinkpad_acpi.h | 13 +++++++------ 2 files changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index cddf81bb2d97..a5efd06523dd 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -339,7 +339,7 @@ static int __init setup_notify(struct ibm_struct *ibm) } return -ENODEV; } - ibm->notify_installed = 1; + ibm->flags.notify_installed = 1; return 0; } @@ -372,7 +372,7 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) kfree(ibm->driver); ibm->driver = NULL; } else if (!ret) - ibm->driver_registered = 1; + ibm->flags.driver_registered = 1; return ret; } @@ -815,7 +815,7 @@ static struct ibm_struct wan_driver_data = { .name = "wan", .read = wan_read, .write = wan_write, - .experimental = 1, + .flags.experimental = 1, }; /************************************************************************* @@ -1851,7 +1851,7 @@ static struct ibm_struct ecdump_driver_data = { .name = "ecdump", .read = ecdump_read, .write = ecdump_write, - .experimental = 1, + .flags.experimental = 1, }; /************************************************************************* @@ -2684,7 +2684,7 @@ static struct ibm_struct fan_driver_data = { .read = fan_read, .write = fan_write, .exit = fan_exit, - .experimental = 1, + .flags.experimental = 1, }; /**************************************************************************** @@ -2725,7 +2725,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm) INIT_LIST_HEAD(&ibm->all_drivers); - if (ibm->experimental && !experimental) + if (ibm->flags.experimental && !experimental) return 0; dbg_printk(TPACPI_DBG_INIT, @@ -2738,7 +2738,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm) if (ret) return ret; - ibm->init_called = 1; + ibm->flags.init_called = 1; } if (ibm->hid) { @@ -2777,7 +2777,7 @@ static int __init ibm_init(struct ibm_init_struct *iibm) entry->read_proc = &dispatch_read; if (ibm->write) entry->write_proc = &dispatch_write; - ibm->proc_created = 1; + ibm->flags.proc_created = 1; } list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers); @@ -2799,33 +2799,33 @@ static void ibm_exit(struct ibm_struct *ibm) list_del_init(&ibm->all_drivers); - if (ibm->notify_installed) { + if (ibm->flags.notify_installed) { dbg_printk(TPACPI_DBG_EXIT, "%s: acpi_remove_notify_handler\n", ibm->name); acpi_remove_notify_handler(*ibm->handle, ibm->type, dispatch_notify); - ibm->notify_installed = 0; + ibm->flags.notify_installed = 0; } - if (ibm->proc_created) { + if (ibm->flags.proc_created) { dbg_printk(TPACPI_DBG_EXIT, "%s: remove_proc_entry\n", ibm->name); remove_proc_entry(ibm->name, proc_dir); - ibm->proc_created = 0; + ibm->flags.proc_created = 0; } - if (ibm->driver_registered) { + if (ibm->flags.driver_registered) { dbg_printk(TPACPI_DBG_EXIT, "%s: acpi_bus_unregister_driver\n", ibm->name); acpi_bus_unregister_driver(ibm->driver); kfree(ibm->driver); ibm->driver = NULL; - ibm->driver_registered = 0; + ibm->flags.driver_registered = 0; } - if (ibm->init_called && ibm->exit) { + if (ibm->flags.init_called && ibm->exit) { ibm->exit(); - ibm->init_called = 0; + ibm->flags.init_called = 0; } dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 20203981cb7a..8b72061d8f0e 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -157,12 +157,13 @@ struct ibm_struct { struct list_head all_drivers; - int driver_registered; - int proc_created; - int init_called; - int notify_installed; - - int experimental; + struct { + u8 driver_registered:1; + u8 proc_created:1; + u8 init_called:1; + u8 notify_installed:1; + u8 experimental:1; + } flags; }; struct ibm_init_struct { -- cgit v1.2.3-59-g8ed1b From d8fd94d9f08237ffda7e44e6825b057bf20a90e3 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:36 -0300 Subject: ACPI: thinkpad-acpi: use bitfields for module flags Use a bitfield to hold boolean module-wide flags, to conserve some memory. It is easy and it is clean, so we do it just for the heck of it even if it saves very little space. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 147 ++++++++++++++++++++----------------------- drivers/misc/thinkpad_acpi.h | 28 +++++---- 2 files changed, 83 insertions(+), 92 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index a5efd06523dd..e2a1b63a812f 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -501,8 +501,6 @@ static struct ibm_struct thinkpad_acpi_driver_data = { * Hotkey subdriver */ -static int hotkey_supported; -static int hotkey_mask_supported; static int hotkey_orig_status; static int hotkey_orig_mask; @@ -513,30 +511,30 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) IBM_HANDLE_INIT(hkey); /* hotkey not supported on 570 */ - hotkey_supported = hkey_handle != NULL; + tp_features.hotkey = hkey_handle != NULL; vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", - str_supported(hotkey_supported)); + str_supported(tp_features.hotkey)); - if (hotkey_supported) { + if (tp_features.hotkey) { /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, A30, R30, R31, T20-22, X20-21, X22-24 */ - hotkey_mask_supported = - acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); + tp_features.hotkey_mask = + acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", - str_supported(hotkey_mask_supported)); + str_supported(tp_features.hotkey_mask)); if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask)) return -ENODEV; } - return (hotkey_supported)? 0 : 1; + return (tp_features.hotkey)? 0 : 1; } static void hotkey_exit(void) { - if (hotkey_supported) { + if (tp_features.hotkey) { dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n"); hotkey_set(hotkey_orig_status, hotkey_orig_mask); } @@ -559,7 +557,7 @@ static int hotkey_get(int *status, int *mask) if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) return 0; - if (hotkey_mask_supported) + if (tp_features.hotkey_mask) if (!acpi_evalf(hkey_handle, mask, "DHKN", "d")) return 0; @@ -573,7 +571,7 @@ static int hotkey_set(int status, int mask) if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) return 0; - if (hotkey_mask_supported) + if (tp_features.hotkey_mask) for (i = 0; i < 32; i++) { int bit = ((1 << i) & mask) != 0; if (!acpi_evalf(hkey_handle, @@ -589,7 +587,7 @@ static int hotkey_read(char *p) int status, mask; int len = 0; - if (!hotkey_supported) { + if (!tp_features.hotkey) { len += sprintf(p + len, "status:\t\tnot supported\n"); return len; } @@ -598,7 +596,7 @@ static int hotkey_read(char *p) return -EIO; len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); - if (hotkey_mask_supported) { + if (tp_features.hotkey_mask) { len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); len += sprintf(p + len, "commands:\tenable, disable, reset, \n"); @@ -616,7 +614,7 @@ static int hotkey_write(char *buf) char *cmd; int do_cmd = 0; - if (!hotkey_supported) + if (!tp_features.hotkey) return -ENODEV; if (!hotkey_get(&status, &mask)) @@ -660,8 +658,6 @@ static struct ibm_struct hotkey_driver_data = { * Bluetooth subdriver */ -static int bluetooth_supported; - static int __init bluetooth_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); @@ -670,20 +666,20 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ - bluetooth_supported = hkey_handle && + tp_features.bluetooth = hkey_handle && acpi_evalf(hkey_handle, NULL, "GBDC", "qv"); vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s\n", - str_supported(bluetooth_supported)); + str_supported(tp_features.bluetooth)); - return (bluetooth_supported)? 0 : 1; + return (tp_features.bluetooth)? 0 : 1; } static int bluetooth_status(void) { int status; - if (!bluetooth_supported || + if (!tp_features.bluetooth || !acpi_evalf(hkey_handle, &status, "GBDC", "d")) status = 0; @@ -695,7 +691,7 @@ static int bluetooth_read(char *p) int len = 0; int status = bluetooth_status(); - if (!bluetooth_supported) + if (!tp_features.bluetooth) len += sprintf(p + len, "status:\t\tnot supported\n"); else if (!(status & 1)) len += sprintf(p + len, "status:\t\tnot installed\n"); @@ -713,7 +709,7 @@ static int bluetooth_write(char *buf) char *cmd; int do_cmd = 0; - if (!bluetooth_supported) + if (!tp_features.bluetooth) return -ENODEV; while ((cmd = next_cmd(&buf))) { @@ -742,28 +738,27 @@ static struct ibm_struct bluetooth_driver_data = { * Wan subdriver */ -static int wan_supported; - static int __init wan_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); IBM_HANDLE_INIT(hkey); - wan_supported = hkey_handle && - acpi_evalf(hkey_handle, NULL, "GWAN", "qv"); + tp_features.wan = hkey_handle && + acpi_evalf(hkey_handle, NULL, "GWAN", "qv"); vdbg_printk(TPACPI_DBG_INIT, "wan is %s\n", - str_supported(wan_supported)); + str_supported(tp_features.wan)); - return (wan_supported)? 0 : 1; + return (tp_features.wan)? 0 : 1; } static int wan_status(void) { int status; - if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d")) + if (!tp_features.wan || + !acpi_evalf(hkey_handle, &status, "GWAN", "d")) status = 0; return status; @@ -774,7 +769,7 @@ static int wan_read(char *p) int len = 0; int status = wan_status(); - if (!wan_supported) + if (!tp_features.wan) len += sprintf(p + len, "status:\t\tnot supported\n"); else if (!(status & 1)) len += sprintf(p + len, "status:\t\tnot installed\n"); @@ -792,7 +787,7 @@ static int wan_write(char *buf) char *cmd; int do_cmd = 0; - if (!wan_supported) + if (!tp_features.wan) return -ENODEV; while ((cmd = next_cmd(&buf))) { @@ -1051,9 +1046,6 @@ static struct ibm_struct video_driver_data = { * Light (thinklight) subdriver */ -static int light_supported; -static int light_status_supported; - IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */ IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */ @@ -1066,18 +1058,18 @@ static int __init light_init(struct ibm_init_struct *iibm) IBM_HANDLE_INIT(cmos); /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ - light_supported = (cmos_handle || lght_handle) && !ledb_handle; + tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; - if (light_supported) + if (tp_features.light) /* light status not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */ - light_status_supported = acpi_evalf(ec_handle, NULL, - "KBLT", "qv"); + tp_features.light_status = + acpi_evalf(ec_handle, NULL, "KBLT", "qv"); vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", - str_supported(light_supported)); + str_supported(tp_features.light)); - return (light_supported)? 0 : 1; + return (tp_features.light)? 0 : 1; } static int light_read(char *p) @@ -1085,9 +1077,9 @@ static int light_read(char *p) int len = 0; int status = 0; - if (!light_supported) { + if (!tp_features.light) { len += sprintf(p + len, "status:\t\tnot supported\n"); - } else if (!light_status_supported) { + } else if (!tp_features.light_status) { len += sprintf(p + len, "status:\t\tunknown\n"); len += sprintf(p + len, "commands:\ton, off\n"); } else { @@ -1106,7 +1098,7 @@ static int light_write(char *buf) char *cmd; int success; - if (!light_supported) + if (!tp_features.light) return -ENODEV; while ((cmd = next_cmd(&buf))) { @@ -1251,11 +1243,6 @@ static struct ibm_struct dock_driver_data[2] = { */ #ifdef CONFIG_THINKPAD_ACPI_BAY -static int bay_status_supported; -static int bay_status2_supported; -static int bay_eject_supported; -static int bay_eject2_supported; - IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */ "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */ "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */ @@ -1282,25 +1269,25 @@ static int __init bay_init(struct ibm_init_struct *iibm) if (bay2_handle) IBM_HANDLE_INIT(bay2_ej); - bay_status_supported = bay_handle && - acpi_evalf(bay_handle, NULL, "_STA", "qv"); - bay_status2_supported = bay2_handle && - acpi_evalf(bay2_handle, NULL, "_STA", "qv"); + tp_features.bay_status = bay_handle && + acpi_evalf(bay_handle, NULL, "_STA", "qv"); + tp_features.bay_status2 = bay2_handle && + acpi_evalf(bay2_handle, NULL, "_STA", "qv"); - bay_eject_supported = bay_handle && bay_ej_handle && - (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental); - bay_eject2_supported = bay2_handle && bay2_ej_handle && - (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); + tp_features.bay_eject = bay_handle && bay_ej_handle && + (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental); + tp_features.bay_eject2 = bay2_handle && bay2_ej_handle && + (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental); vdbg_printk(TPACPI_DBG_INIT, "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n", - str_supported(bay_status_supported), - str_supported(bay_eject_supported), - str_supported(bay_status2_supported), - str_supported(bay_eject2_supported)); + str_supported(tp_features.bay_status), + str_supported(tp_features.bay_eject), + str_supported(tp_features.bay_status2), + str_supported(tp_features.bay_eject2)); - return (bay_status_supported || bay_eject_supported || - bay_status2_supported || bay_eject2_supported)? 0 : 1; + return (tp_features.bay_status || tp_features.bay_eject || + tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1; } static void bay_notify(struct ibm_struct *ibm, u32 event) @@ -1317,15 +1304,16 @@ static int bay_read(char *p) int occupied2 = bay_occupied(bay2); int eject, eject2; - len += sprintf(p + len, "status:\t\t%s\n", bay_status_supported ? - (occupied ? "occupied" : "unoccupied") : - "not supported"); - if (bay_status2_supported) + len += sprintf(p + len, "status:\t\t%s\n", + tp_features.bay_status ? + (occupied ? "occupied" : "unoccupied") : + "not supported"); + if (tp_features.bay_status2) len += sprintf(p + len, "status2:\t%s\n", occupied2 ? "occupied" : "unoccupied"); - eject = bay_eject_supported && occupied; - eject2 = bay_eject2_supported && occupied2; + eject = tp_features.bay_eject && occupied; + eject2 = tp_features.bay_eject2 && occupied2; if (eject && eject2) len += sprintf(p + len, "commands:\teject, eject2\n"); @@ -1341,14 +1329,14 @@ static int bay_write(char *buf) { char *cmd; - if (!bay_eject_supported && !bay_eject2_supported) + if (!tp_features.bay_eject && !tp_features.bay_eject2) return -ENODEV; while ((cmd = next_cmd(&buf))) { - if (bay_eject_supported && strlencmp(cmd, "eject") == 0) { + if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) { if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1)) return -EIO; - } else if (bay_eject2_supported && + } else if (tp_features.bay_eject2 && strlencmp(cmd, "eject2") == 0) { if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1)) return -EIO; @@ -2188,7 +2176,6 @@ static enum fan_status_access_mode fan_status_access_mode; static enum fan_control_access_mode fan_control_access_mode; static enum fan_control_commands fan_control_commands; -static int fan_control_status_known; static u8 fan_control_initial_status; static void fan_watchdog_fire(struct work_struct *ignored); @@ -2210,8 +2197,8 @@ static int __init fan_init(struct ibm_init_struct *iibm) fan_status_access_mode = TPACPI_FAN_NONE; fan_control_access_mode = TPACPI_FAN_WR_NONE; fan_control_commands = 0; - fan_control_status_known = 1; fan_watchdog_maxinterval = 0; + tp_features.fan_ctrl_status_undef = 0; IBM_HANDLE_INIT(fans); IBM_HANDLE_INIT(gfan); @@ -2248,7 +2235,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) "fan_init: initial fan status is " "unknown, assuming it is in auto " "mode\n"); - fan_control_status_known = 0; + tp_features.fan_ctrl_status_undef = 1; } } else { printk(IBM_ERR @@ -2411,7 +2398,7 @@ static int fan_set_level(int level) if (!acpi_ec_write(fan_status_offset, level)) return -EIO; else - fan_control_status_known = 1; + tp_features.fan_ctrl_status_undef = 0; break; default: @@ -2438,7 +2425,7 @@ static int fan_set_enable(void) if (!acpi_ec_write(fan_status_offset, s)) return -EIO; else - fan_control_status_known = 1; + tp_features.fan_ctrl_status_undef = 0; break; case TPACPI_FAN_WR_ACPI_SFAN: @@ -2469,7 +2456,7 @@ static int fan_set_disable(void) if (!acpi_ec_write(fan_status_offset, 0x00)) return -EIO; else - fan_control_status_known = 1; + tp_features.fan_ctrl_status_undef = 0; break; case TPACPI_FAN_WR_ACPI_SFAN: @@ -2524,9 +2511,9 @@ static int fan_read(char *p) if ((rc = fan_get_status(&status)) < 0) return rc; - if (unlikely(!fan_control_status_known)) { + if (unlikely(tp_features.fan_ctrl_status_undef)) { if (status != fan_control_initial_status) - fan_control_status_known = 1; + tp_features.fan_ctrl_status_undef = 0; else /* Return most likely status. In fact, it * might be the only possible status */ diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 8b72061d8f0e..4d3ab4015ff2 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -173,6 +173,22 @@ struct ibm_init_struct { struct ibm_struct *data; }; +static struct { +#ifdef CONFIG_THINKPAD_ACPI_BAY + u16 bay_status:1; + u16 bay_eject:1; + u16 bay_status2:1; + u16 bay_eject2:1; +#endif + u16 bluetooth:1; + u16 hotkey:1; + u16 hotkey_mask:1; + u16 light:1; + u16 light_status:1; + u16 wan:1; + u16 fan_ctrl_status_undef:1; +} tp_features; + static struct list_head tpacpi_all_drivers; static struct ibm_init_struct ibms_init[]; @@ -193,9 +209,6 @@ static int thinkpad_acpi_driver_read(char *p); */ #ifdef CONFIG_THINKPAD_ACPI_BAY -static int bay_status_supported, bay_eject_supported; -static int bay_status2_supported, bay_eject2_supported; - static acpi_handle bay_handle, bay_ej_handle; static acpi_handle bay2_handle, bay2_ej_handle; @@ -220,8 +233,6 @@ static int beep_write(char *buf); * Bluetooth subdriver */ -static int bluetooth_supported; - static int bluetooth_init(struct ibm_init_struct *iibm); static int bluetooth_status(void); static int bluetooth_read(char *p); @@ -311,7 +322,6 @@ enum fan_control_commands { static enum fan_status_access_mode fan_status_access_mode; static enum fan_control_access_mode fan_control_access_mode; static enum fan_control_commands fan_control_commands; -static int fan_control_status_known; static u8 fan_control_initial_status; static int fan_watchdog_maxinterval; @@ -340,8 +350,6 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc); * Hotkey subdriver */ -static int hotkey_supported; -static int hotkey_mask_supported; static int hotkey_orig_status; static int hotkey_orig_mask; @@ -382,8 +390,6 @@ static int led_write(char *buf); * Light (thinklight) subdriver */ -static int light_supported; -static int light_status_supported; static acpi_handle lght_handle, ledb_handle; static int light_init(struct ibm_init_struct *iibm); @@ -453,8 +459,6 @@ static int volume_write(char *buf); * Wan subdriver */ -static int wan_supported; - static int wan_init(struct ibm_init_struct *iibm); static int wan_status(void); static int wan_read(char *p); -- cgit v1.2.3-59-g8ed1b From 8d376cd6543d57ef10799be02ba5f19aa6678032 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:37 -0300 Subject: ACPI: thinkpad-acpi: prepare for device model conversion Prepare the thinkpad-acpi driver for the conversion to the device model, by renaming variables and doing other glue work that shall make the later patches much cleaner. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 231 ++++++++++++++++++++++++------------------- drivers/misc/thinkpad_acpi.h | 40 +++++--- 2 files changed, 153 insertions(+), 118 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index e2a1b63a812f..809ec8400ec5 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -277,7 +277,7 @@ static int _sta(acpi_handle handle) * ACPI device model */ -static void ibm_handle_init(char *name, +static void drv_acpi_handle_init(char *name, acpi_handle *handle, acpi_handle parent, char **paths, int num_paths, char **path) { @@ -295,40 +295,42 @@ static void ibm_handle_init(char *name, *handle = NULL; } -static void dispatch_notify(acpi_handle handle, u32 event, void *data) +static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) { struct ibm_struct *ibm = data; - if (!ibm || !ibm->notify) + if (!ibm || !ibm->acpi || !ibm->acpi->notify) return; - ibm->notify(ibm, event); + ibm->acpi->notify(ibm, event); } -static int __init setup_notify(struct ibm_struct *ibm) +static int __init setup_acpi_notify(struct ibm_struct *ibm) { acpi_status status; int ret; - if (!*ibm->handle) + BUG_ON(!ibm->acpi); + + if (!*ibm->acpi->handle) return 0; dbg_printk(TPACPI_DBG_INIT, "setting up ACPI notify for %s\n", ibm->name); - ret = acpi_bus_get_device(*ibm->handle, &ibm->device); + ret = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); if (ret < 0) { printk(IBM_ERR "%s device not present\n", ibm->name); return -ENODEV; } - acpi_driver_data(ibm->device) = ibm; - sprintf(acpi_device_class(ibm->device), "%s/%s", + acpi_driver_data(ibm->acpi->device) = ibm; + sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", IBM_ACPI_EVENT_PREFIX, ibm->name); - status = acpi_install_notify_handler(*ibm->handle, ibm->type, - dispatch_notify, ibm); + status = acpi_install_notify_handler(*ibm->acpi->handle, + ibm->acpi->type, dispatch_acpi_notify, ibm); if (ACPI_FAILURE(status)) { if (status == AE_ALREADY_EXISTS) { printk(IBM_NOTICE "another device driver is already handling %s events\n", @@ -339,11 +341,11 @@ static int __init setup_notify(struct ibm_struct *ibm) } return -ENODEV; } - ibm->flags.notify_installed = 1; + ibm->flags.acpi_notify_installed = 1; return 0; } -static int __init ibm_device_add(struct acpi_device *device) +static int __init tpacpi_device_add(struct acpi_device *device) { return 0; } @@ -355,24 +357,26 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) dbg_printk(TPACPI_DBG_INIT, "registering %s as an ACPI driver\n", ibm->name); - ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); - if (!ibm->driver) { + BUG_ON(!ibm->acpi); + + ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); + if (!ibm->acpi->driver) { printk(IBM_ERR "kzalloc(ibm->driver) failed\n"); return -ENOMEM; } - sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name); - ibm->driver->ids = ibm->hid; - ibm->driver->ops.add = &ibm_device_add; + sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); + ibm->acpi->driver->ids = ibm->acpi->hid; + ibm->acpi->driver->ops.add = &tpacpi_device_add; - ret = acpi_bus_register_driver(ibm->driver); + ret = acpi_bus_register_driver(ibm->acpi->driver); if (ret < 0) { printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", - ibm->hid, ret); - kfree(ibm->driver); - ibm->driver = NULL; + ibm->acpi->hid, ret); + kfree(ibm->acpi->driver); + ibm->acpi->driver = NULL; } else if (!ret) - ibm->flags.driver_registered = 1; + ibm->flags.acpi_driver_registered = 1; return ret; } @@ -386,8 +390,8 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) **************************************************************************** ****************************************************************************/ -static int dispatch_read(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int dispatch_procfs_read(char *page, char **start, off_t off, + int count, int *eof, void *data) { struct ibm_struct *ibm = data; int len; @@ -411,8 +415,9 @@ static int dispatch_read(char *page, char **start, off_t off, int count, return len; } -static int dispatch_write(struct file *file, const char __user * userbuf, - unsigned long count, void *data) +static int dispatch_procfs_write(struct file *file, + const char __user * userbuf, + unsigned long count, void *data) { struct ibm_struct *ibm = data; char *kernbuf; @@ -508,7 +513,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); - IBM_HANDLE_INIT(hkey); + IBM_ACPIHANDLE_INIT(hkey); /* hotkey not supported on 570 */ tp_features.hotkey = hkey_handle != NULL; @@ -545,10 +550,10 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) int hkey; if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) - acpi_bus_generate_event(ibm->device, event, hkey); + acpi_bus_generate_event(ibm->acpi->device, event, hkey); else { printk(IBM_ERR "unknown hotkey event %d\n", event); - acpi_bus_generate_event(ibm->device, event, 0); + acpi_bus_generate_event(ibm->acpi->device, event, 0); } } @@ -643,15 +648,19 @@ static int hotkey_write(char *buf) return 0; } +static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { + .hid = IBM_HKEY_HID, + .notify = hotkey_notify, + .handle = &hkey_handle, + .type = ACPI_DEVICE_NOTIFY, +}; + static struct ibm_struct hotkey_driver_data = { .name = "hotkey", - .hid = IBM_HKEY_HID, .read = hotkey_read, .write = hotkey_write, .exit = hotkey_exit, - .notify = hotkey_notify, - .handle = &hkey_handle, - .type = ACPI_DEVICE_NOTIFY, + .acpi = &ibm_hotkey_acpidriver, }; /************************************************************************* @@ -662,7 +671,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); - IBM_HANDLE_INIT(hkey); + IBM_ACPIHANDLE_INIT(hkey); /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ @@ -742,7 +751,7 @@ static int __init wan_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); - IBM_HANDLE_INIT(hkey); + IBM_ACPIHANDLE_INIT(hkey); tp_features.wan = hkey_handle && acpi_evalf(hkey_handle, NULL, "GWAN", "qv"); @@ -835,8 +844,8 @@ static int __init video_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n"); - IBM_HANDLE_INIT(vid); - IBM_HANDLE_INIT(vid2); + IBM_ACPIHANDLE_INIT(vid); + IBM_ACPIHANDLE_INIT(vid2); if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga) /* G41, assume IVGA doesn't change */ @@ -1053,9 +1062,9 @@ static int __init light_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); - IBM_HANDLE_INIT(ledb); - IBM_HANDLE_INIT(lght); - IBM_HANDLE_INIT(cmos); + IBM_ACPIHANDLE_INIT(ledb); + IBM_ACPIHANDLE_INIT(lght); + IBM_ACPIHANDLE_INIT(cmos); /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; @@ -1148,8 +1157,8 @@ static int __init dock_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n"); - IBM_HANDLE_INIT(dock); - IBM_HANDLE_INIT(pci); + IBM_ACPIHANDLE_INIT(dock); + IBM_ACPIHANDLE_INIT(pci); vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n", str_supported(dock_handle != NULL)); @@ -1160,22 +1169,22 @@ static int __init dock_init(struct ibm_init_struct *iibm) static void dock_notify(struct ibm_struct *ibm, u32 event) { int docked = dock_docked(); - int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID); + int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID); if (event == 1 && !pci) /* 570 */ - acpi_bus_generate_event(ibm->device, event, 1); /* button */ + acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ else if (event == 1 && pci) /* 570 */ - acpi_bus_generate_event(ibm->device, event, 3); /* dock */ + acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ else if (event == 3 && docked) - acpi_bus_generate_event(ibm->device, event, 1); /* button */ + acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ else if (event == 3 && !docked) - acpi_bus_generate_event(ibm->device, event, 2); /* undock */ + acpi_bus_generate_event(ibm->acpi->device, event, 2); /* undock */ else if (event == 0 && docked) - acpi_bus_generate_event(ibm->device, event, 3); /* dock */ + acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */ else { printk(IBM_ERR "unknown dock event %d, status %d\n", event, _sta(dock_handle)); - acpi_bus_generate_event(ibm->device, event, 0); /* unknown */ + acpi_bus_generate_event(ibm->acpi->device, event, 0); /* unknown */ } } @@ -1218,17 +1227,13 @@ static int dock_write(char *buf) return 0; } -static struct ibm_struct dock_driver_data[2] = { +static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { { - .name = "dock", - .read = dock_read, - .write = dock_write, .notify = dock_notify, .handle = &dock_handle, .type = ACPI_SYSTEM_NOTIFY, }, { - .name = "dock", .hid = IBM_PCI_HID, .notify = dock_notify, .handle = &pci_handle, @@ -1236,6 +1241,19 @@ static struct ibm_struct dock_driver_data[2] = { }, }; +static struct ibm_struct dock_driver_data[2] = { + { + .name = "dock", + .read = dock_read, + .write = dock_write, + .acpi = &ibm_dock_acpidriver[0], + }, + { + .name = "dock", + .acpi = &ibm_dock_acpidriver[1], + }, +}; + #endif /* CONFIG_THINKPAD_ACPI_DOCK */ /************************************************************************* @@ -1262,12 +1280,12 @@ static int __init bay_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n"); - IBM_HANDLE_INIT(bay); + IBM_ACPIHANDLE_INIT(bay); if (bay_handle) - IBM_HANDLE_INIT(bay_ej); - IBM_HANDLE_INIT(bay2); + IBM_ACPIHANDLE_INIT(bay_ej); + IBM_ACPIHANDLE_INIT(bay2); if (bay2_handle) - IBM_HANDLE_INIT(bay2_ej); + IBM_ACPIHANDLE_INIT(bay2_ej); tp_features.bay_status = bay_handle && acpi_evalf(bay_handle, NULL, "_STA", "qv"); @@ -1292,7 +1310,7 @@ static int __init bay_init(struct ibm_init_struct *iibm) static void bay_notify(struct ibm_struct *ibm, u32 event) { - acpi_bus_generate_event(ibm->device, event, 0); + acpi_bus_generate_event(ibm->acpi->device, event, 0); } #define bay_occupied(b) (_sta(b##_handle) & 1) @@ -1347,13 +1365,17 @@ static int bay_write(char *buf) return 0; } +static struct tp_acpi_drv_struct ibm_bay_acpidriver = { + .notify = bay_notify, + .handle = &bay_handle, + .type = ACPI_SYSTEM_NOTIFY, +}; + static struct ibm_struct bay_driver_data = { .name = "bay", .read = bay_read, .write = bay_write, - .notify = bay_notify, - .handle = &bay_handle, - .type = ACPI_SYSTEM_NOTIFY, + .acpi = &ibm_bay_acpidriver, }; #endif /* CONFIG_THINKPAD_ACPI_BAY */ @@ -1367,7 +1389,7 @@ static int __init cmos_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing cmos commands subdriver\n"); - IBM_HANDLE_INIT(cmos); + IBM_ACPIHANDLE_INIT(cmos); vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n", str_supported(cmos_handle != NULL)); @@ -1441,7 +1463,7 @@ static int __init led_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n"); - IBM_HANDLE_INIT(led); + IBM_ACPIHANDLE_INIT(led); if (!led_handle) /* led not supported on R30, R31 */ @@ -1566,7 +1588,7 @@ static int __init beep_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n"); - IBM_HANDLE_INIT(beep); + IBM_ACPIHANDLE_INIT(beep); vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n", str_supported(beep_handle != NULL)); @@ -2200,9 +2222,9 @@ static int __init fan_init(struct ibm_init_struct *iibm) fan_watchdog_maxinterval = 0; tp_features.fan_ctrl_status_undef = 0; - IBM_HANDLE_INIT(fans); - IBM_HANDLE_INIT(gfan); - IBM_HANDLE_INIT(sfan); + IBM_ACPIHANDLE_INIT(fans); + IBM_ACPIHANDLE_INIT(gfan); + IBM_ACPIHANDLE_INIT(sfan); if (gfan_handle) { /* 570, 600e/x, 770e, 770x */ @@ -2728,22 +2750,24 @@ static int __init ibm_init(struct ibm_init_struct *iibm) ibm->flags.init_called = 1; } - if (ibm->hid) { - ret = register_tpacpi_subdriver(ibm); - if (ret) - goto err_out; - } + if (ibm->acpi) { + if (ibm->acpi->hid) { + ret = register_tpacpi_subdriver(ibm); + if (ret) + goto err_out; + } - if (ibm->notify) { - ret = setup_notify(ibm); - if (ret == -ENODEV) { - printk(IBM_NOTICE "disabling subdriver %s\n", - ibm->name); - ret = 0; - goto err_out; + if (ibm->acpi->notify) { + ret = setup_acpi_notify(ibm); + if (ret == -ENODEV) { + printk(IBM_NOTICE "disabling subdriver %s\n", + ibm->name); + ret = 0; + goto err_out; + } + if (ret < 0) + goto err_out; } - if (ret < 0) - goto err_out; } dbg_printk(TPACPI_DBG_INIT, @@ -2761,9 +2785,9 @@ static int __init ibm_init(struct ibm_init_struct *iibm) } entry->owner = THIS_MODULE; entry->data = ibm; - entry->read_proc = &dispatch_read; + entry->read_proc = &dispatch_procfs_read; if (ibm->write) - entry->write_proc = &dispatch_write; + entry->write_proc = &dispatch_procfs_write; ibm->flags.proc_created = 1; } @@ -2786,12 +2810,15 @@ static void ibm_exit(struct ibm_struct *ibm) list_del_init(&ibm->all_drivers); - if (ibm->flags.notify_installed) { + if (ibm->flags.acpi_notify_installed) { dbg_printk(TPACPI_DBG_EXIT, "%s: acpi_remove_notify_handler\n", ibm->name); - acpi_remove_notify_handler(*ibm->handle, ibm->type, - dispatch_notify); - ibm->flags.notify_installed = 0; + BUG_ON(!ibm->acpi); + acpi_remove_notify_handler(*ibm->acpi->handle, + ibm->acpi->type, + dispatch_acpi_notify); + ibm->flags.acpi_notify_installed = 0; + ibm->flags.acpi_notify_installed = 0; } if (ibm->flags.proc_created) { @@ -2801,13 +2828,14 @@ static void ibm_exit(struct ibm_struct *ibm) ibm->flags.proc_created = 0; } - if (ibm->flags.driver_registered) { + if (ibm->flags.acpi_driver_registered) { dbg_printk(TPACPI_DBG_EXIT, "%s: acpi_bus_unregister_driver\n", ibm->name); - acpi_bus_unregister_driver(ibm->driver); - kfree(ibm->driver); - ibm->driver = NULL; - ibm->flags.driver_registered = 0; + BUG_ON(!ibm->acpi); + acpi_bus_unregister_driver(ibm->acpi->driver); + kfree(ibm->acpi->driver); + ibm->acpi->driver = NULL; + ibm->flags.acpi_driver_registered = 0; } if (ibm->flags.init_called && ibm->exit) { @@ -2860,7 +2888,7 @@ static int __init probe_for_thinkpad(void) is_thinkpad = dmi_name_in_vendors("ThinkPad"); /* ec is required because many other handles are relative to it */ - IBM_HANDLE_INIT(ec); + IBM_ACPIHANDLE_INIT(ec); if (!ec_handle) { if (is_thinkpad) printk(IBM_ERR @@ -3016,12 +3044,12 @@ static int __init thinkpad_acpi_module_init(void) return ret; ibm_thinkpad_ec_found = check_dmi_for_ec(); - IBM_HANDLE_INIT(ecrd); - IBM_HANDLE_INIT(ecwr); + IBM_ACPIHANDLE_INIT(ecrd); + IBM_ACPIHANDLE_INIT(ecwr); - proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); + proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir); if (!proc_dir) { - printk(IBM_ERR "unable to create proc dir %s", IBM_DIR); + printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR); thinkpad_acpi_module_exit(); return -ENODEV; } @@ -3053,10 +3081,9 @@ static void thinkpad_acpi_module_exit(void) dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); if (proc_dir) - remove_proc_entry(IBM_DIR, acpi_root_dir); + remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); - if (ibm_thinkpad_ec_found) - kfree(ibm_thinkpad_ec_found); + kfree(ibm_thinkpad_ec_found); } module_init(thinkpad_acpi_module_init); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 4d3ab4015ff2..529528c2fb5d 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -52,8 +52,9 @@ #define IBM_DESC "ThinkPad ACPI Extras" #define IBM_FILE "thinkpad_acpi" #define IBM_URL "http://ibm-acpi.sf.net/" +#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" -#define IBM_DIR "ibm" +#define IBM_PROC_DIR "ibm" #define IBM_ACPI_EVENT_PREFIX "ibm" #define IBM_LOG IBM_FILE ": " @@ -108,20 +109,21 @@ static acpi_handle ec_handle; /* EC */ static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */ static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */ -static void ibm_handle_init(char *name, +static void drv_acpi_handle_init(char *name, acpi_handle *handle, acpi_handle parent, char **paths, int num_paths, char **path); -#define IBM_HANDLE_INIT(object) \ - ibm_handle_init(#object, &object##_handle, *object##_parent, \ +#define IBM_ACPIHANDLE_INIT(object) \ + drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ object##_paths, ARRAY_SIZE(object##_paths), &object##_path) /* procfs support */ static struct proc_dir_entry *proc_dir; /* procfs helpers */ -static int dispatch_read(char *page, char **start, off_t off, int count, - int *eof, void *data); -static int dispatch_write(struct file *file, const char __user * userbuf, +static int dispatch_procfs_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int dispatch_procfs_write(struct file *file, + const char __user * userbuf, unsigned long count, void *data); static char *next_cmd(char **cmds); @@ -140,28 +142,34 @@ static void thinkpad_acpi_module_exit(void); * Subdrivers */ -struct ibm_struct { - char *name; +struct ibm_struct; +struct tp_acpi_drv_struct { char *hid; struct acpi_driver *driver; - int (*read) (char *); - int (*write) (char *); - void (*exit) (void); - void (*notify) (struct ibm_struct *, u32); acpi_handle *handle; - int type; + u32 type; struct acpi_device *device; +}; + +struct ibm_struct { + char *name; + + int (*read) (char *); + int (*write) (char *); + void (*exit) (void); struct list_head all_drivers; + struct tp_acpi_drv_struct *acpi; + struct { - u8 driver_registered:1; + u8 acpi_driver_registered:1; + u8 acpi_notify_installed:1; u8 proc_created:1; u8 init_called:1; - u8 notify_installed:1; u8 experimental:1; } flags; }; -- cgit v1.2.3-59-g8ed1b From d01320e606d334a0cd35d781a58f9f3c254829ab Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:38 -0300 Subject: ACPI: thinkpad-acpi: mark acpi helper functions __must_check Mark acpi_evalf and friends __must_check. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 529528c2fb5d..1b4cd167ebd2 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -97,11 +97,11 @@ static const char *str_supported(int is_supported); #define IBM_PCI_HID "PNP0A03" /* ACPI helpers */ -static int acpi_evalf(acpi_handle handle, +static int __must_check acpi_evalf(acpi_handle handle, void *res, char *method, char *fmt, ...); -static int acpi_ec_read(int i, u8 * p); -static int acpi_ec_write(int i, u8 v); -static int _sta(acpi_handle handle); +static int __must_check acpi_ec_read(int i, u8 * p); +static int __must_check acpi_ec_write(int i, u8 v); +static int __must_check _sta(acpi_handle handle); /* ACPI handles */ static acpi_handle root_handle; /* root namespace */ -- cgit v1.2.3-59-g8ed1b From d6fdd1e91a8a4cd852dc1d945165e3a69ac9e257 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:40 -0300 Subject: ACPI: thinkpad-acpi: cleanup bluetooth and wan for sysfs conversion Prepare bluetooth and wan driver code to be more easily hooked into sysfs helpers, by separating the procfs logic from the device attribute handling. These changes also remove the entries from procfs on notebooks without the bluetooth/wan hardware installed. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 130 ++++++++++++++++++++++++++++++------------- drivers/misc/thinkpad_acpi.h | 20 ++++++- 2 files changed, 108 insertions(+), 42 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 344eb551c443..a77368f90181 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -681,6 +681,8 @@ static struct ibm_struct hotkey_driver_data = { static int __init bluetooth_init(struct ibm_init_struct *iibm) { + int status = 0; + vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); IBM_ACPIHANDLE_INIT(hkey); @@ -688,36 +690,65 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ tp_features.bluetooth = hkey_handle && - acpi_evalf(hkey_handle, NULL, "GBDC", "qv"); + acpi_evalf(hkey_handle, &status, "GBDC", "qd"); - vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s\n", - str_supported(tp_features.bluetooth)); + vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n", + str_supported(tp_features.bluetooth), + status); + + if (tp_features.bluetooth && + !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { + /* no bluetooth hardware present in system */ + tp_features.bluetooth = 0; + dbg_printk(TPACPI_DBG_INIT, + "bluetooth hardware not installed\n"); + } return (tp_features.bluetooth)? 0 : 1; } -static int bluetooth_status(void) +static int bluetooth_get_radiosw(void) { int status; - if (!tp_features.bluetooth || - !acpi_evalf(hkey_handle, &status, "GBDC", "d")) - status = 0; + if (!tp_features.bluetooth) + return -ENODEV; - return status; + if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) + return -EIO; + + return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0); +} + +static int bluetooth_set_radiosw(int radio_on) +{ + int status; + + if (!tp_features.bluetooth) + return -ENODEV; + + if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) + return -EIO; + if (radio_on) + status |= TP_ACPI_BLUETOOTH_RADIOSSW; + else + status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; + if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) + return -EIO; + + return 0; } static int bluetooth_read(char *p) { int len = 0; - int status = bluetooth_status(); + int status = bluetooth_get_radiosw(); if (!tp_features.bluetooth) len += sprintf(p + len, "status:\t\tnot supported\n"); - else if (!(status & 1)) - len += sprintf(p + len, "status:\t\tnot installed\n"); else { - len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1)); + len += sprintf(p + len, "status:\t\t%s\n", + (status)? "enabled" : "disabled"); len += sprintf(p + len, "commands:\tenable, disable\n"); } @@ -726,26 +757,20 @@ static int bluetooth_read(char *p) static int bluetooth_write(char *buf) { - int status = bluetooth_status(); char *cmd; - int do_cmd = 0; if (!tp_features.bluetooth) return -ENODEV; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "enable") == 0) { - status |= 2; + bluetooth_set_radiosw(1); } else if (strlencmp(cmd, "disable") == 0) { - status &= ~2; + bluetooth_set_radiosw(0); } else return -EINVAL; - do_cmd = 1; } - if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) - return -EIO; - return 0; } @@ -761,41 +786,72 @@ static struct ibm_struct bluetooth_driver_data = { static int __init wan_init(struct ibm_init_struct *iibm) { + int status = 0; + vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); IBM_ACPIHANDLE_INIT(hkey); tp_features.wan = hkey_handle && - acpi_evalf(hkey_handle, NULL, "GWAN", "qv"); + acpi_evalf(hkey_handle, &status, "GWAN", "qd"); - vdbg_printk(TPACPI_DBG_INIT, "wan is %s\n", - str_supported(tp_features.wan)); + vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n", + str_supported(tp_features.wan), + status); + + if (tp_features.wan && + !(status & TP_ACPI_WANCARD_HWPRESENT)) { + /* no wan hardware present in system */ + tp_features.wan = 0; + dbg_printk(TPACPI_DBG_INIT, + "wan hardware not installed\n"); + } return (tp_features.wan)? 0 : 1; } -static int wan_status(void) +static int wan_get_radiosw(void) { int status; - if (!tp_features.wan || - !acpi_evalf(hkey_handle, &status, "GWAN", "d")) - status = 0; + if (!tp_features.wan) + return -ENODEV; - return status; + if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) + return -EIO; + + return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0); +} + +static int wan_set_radiosw(int radio_on) +{ + int status; + + if (!tp_features.wan) + return -ENODEV; + + if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) + return -EIO; + if (radio_on) + status |= TP_ACPI_WANCARD_RADIOSSW; + else + status &= ~TP_ACPI_WANCARD_RADIOSSW; + if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) + return -EIO; + + return 0; } static int wan_read(char *p) { int len = 0; - int status = wan_status(); + int status = wan_get_radiosw(); if (!tp_features.wan) len += sprintf(p + len, "status:\t\tnot supported\n"); - else if (!(status & 1)) - len += sprintf(p + len, "status:\t\tnot installed\n"); else { - len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1)); + len += sprintf(p + len, "status:\t\t%s\n", + (status)? "enabled" : "disabled"); len += sprintf(p + len, "commands:\tenable, disable\n"); } @@ -804,26 +860,20 @@ static int wan_read(char *p) static int wan_write(char *buf) { - int status = wan_status(); char *cmd; - int do_cmd = 0; if (!tp_features.wan) return -ENODEV; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "enable") == 0) { - status |= 2; + wan_set_radiosw(1); } else if (strlencmp(cmd, "disable") == 0) { - status &= ~2; + wan_set_radiosw(0); } else return -EINVAL; - do_cmd = 1; } - if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) - return -EIO; - return 0; } diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 1b4cd167ebd2..e06bad5c8fe4 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -241,8 +241,16 @@ static int beep_write(char *buf); * Bluetooth subdriver */ +enum { + /* ACPI GBDC/SBDC bits */ + TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ + TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */ + TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */ +}; + static int bluetooth_init(struct ibm_init_struct *iibm); -static int bluetooth_status(void); +static int bluetooth_get_radiosw(void); +static int bluetooth_set_radiosw(int radio_on); static int bluetooth_read(char *p); static int bluetooth_write(char *buf); @@ -467,8 +475,16 @@ static int volume_write(char *buf); * Wan subdriver */ +enum { + /* ACPI GWAN/SWAN bits */ + TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ + TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */ + TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */ +}; + static int wan_init(struct ibm_init_struct *iibm); -static int wan_status(void); +static int wan_get_radiosw(void); +static int wan_set_radiosw(int radio_on); static int wan_read(char *p); static int wan_write(char *buf); -- cgit v1.2.3-59-g8ed1b From 83f34724643a3b0ec9322490b9ad9f1b60170a6c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:41 -0300 Subject: ACPI: thinkpad-acpi: cleanup video subdriver Cleanup video subdriver for sysfs conversion, and properly check result status of acpi_evalf. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 262 +++++++++++++++++++++++++++++-------------- drivers/misc/thinkpad_acpi.h | 25 ++++- 2 files changed, 197 insertions(+), 90 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index a77368f90181..19c14bbe8b29 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -935,111 +935,194 @@ static int __init video_init(struct ibm_init_struct *iibm) static void video_exit(void) { - dbg_printk(TPACPI_DBG_EXIT, "restoring original video autoswitch mode\n"); - acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw); + dbg_printk(TPACPI_DBG_EXIT, + "restoring original video autoswitch mode\n"); + if (video_autosw_set(video_orig_autosw)) + printk(IBM_ERR "error while trying to restore original " + "video autoswitch mode\n"); } -static int video_status(void) +static int video_outputsw_get(void) { int status = 0; int i; - if (video_supported == TPACPI_VIDEO_570) { - if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87)) - status = i & 3; - } else if (video_supported == TPACPI_VIDEO_770) { - if (acpi_evalf(NULL, &i, "\\VCDL", "d")) - status |= 0x01 * i; - if (acpi_evalf(NULL, &i, "\\VCDC", "d")) - status |= 0x02 * i; - } else if (video_supported == TPACPI_VIDEO_NEW) { - acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1); - if (acpi_evalf(NULL, &i, "\\VCDC", "d")) - status |= 0x02 * i; - - acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0); - if (acpi_evalf(NULL, &i, "\\VCDL", "d")) - status |= 0x01 * i; - if (acpi_evalf(NULL, &i, "\\VCDD", "d")) - status |= 0x08 * i; + switch (video_supported) { + case TPACPI_VIDEO_570: + if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", + TP_ACPI_VIDEO_570_PHSCMD)) + return -EIO; + status = i & TP_ACPI_VIDEO_570_PHSMASK; + break; + case TPACPI_VIDEO_770: + if (!acpi_evalf(NULL, &i, "\\VCDL", "d")) + return -EIO; + if (i) + status |= TP_ACPI_VIDEO_S_LCD; + if (!acpi_evalf(NULL, &i, "\\VCDC", "d")) + return -EIO; + if (i) + status |= TP_ACPI_VIDEO_S_CRT; + break; + case TPACPI_VIDEO_NEW: + if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) || + !acpi_evalf(NULL, &i, "\\VCDC", "d")) + return -EIO; + if (i) + status |= TP_ACPI_VIDEO_S_CRT; + + if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) || + !acpi_evalf(NULL, &i, "\\VCDL", "d")) + return -EIO; + if (i) + status |= TP_ACPI_VIDEO_S_LCD; + if (!acpi_evalf(NULL, &i, "\\VCDD", "d")) + return -EIO; + if (i) + status |= TP_ACPI_VIDEO_S_DVI; + break; + default: + return -ENOSYS; } return status; } -static int video_autosw(void) +static int video_outputsw_set(int status) { - int autosw = 0; + int autosw; + int res = 0; - if (video_supported == TPACPI_VIDEO_570) - acpi_evalf(vid_handle, &autosw, "SWIT", "d"); - else if (video_supported == TPACPI_VIDEO_770 || - video_supported == TPACPI_VIDEO_NEW) - acpi_evalf(vid_handle, &autosw, "^VDEE", "d"); + switch (video_supported) { + case TPACPI_VIDEO_570: + res = acpi_evalf(NULL, NULL, + "\\_SB.PHS2", "vdd", + TP_ACPI_VIDEO_570_PHS2CMD, + status | TP_ACPI_VIDEO_570_PHS2SET); + break; + case TPACPI_VIDEO_770: + autosw = video_autosw_get(); + if (autosw < 0) + return autosw; - return autosw & 1; + res = video_autosw_set(1); + if (res) + return res; + res = acpi_evalf(vid_handle, NULL, + "ASWT", "vdd", status * 0x100, 0); + if (!autosw && video_autosw_set(autosw)) { + printk(IBM_ERR "video auto-switch left enabled due to error\n"); + return -EIO; + } + break; + case TPACPI_VIDEO_NEW: + res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && + acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); + break; + default: + return -ENOSYS; + } + + return (res)? 0 : -EIO; } -static int video_switch(void) +static int video_autosw_get(void) { - int autosw = video_autosw(); - int ret; + int autosw = 0; - if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) - return -EIO; - ret = video_supported == TPACPI_VIDEO_570 ? - acpi_evalf(ec_handle, NULL, "_Q16", "v") : - acpi_evalf(vid_handle, NULL, "VSWT", "v"); - acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); + switch (video_supported) { + case TPACPI_VIDEO_570: + if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d")) + return -EIO; + break; + case TPACPI_VIDEO_770: + case TPACPI_VIDEO_NEW: + if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d")) + return -EIO; + break; + default: + return -ENOSYS; + } - return ret; + return autosw & 1; } -static int video_expand(void) +static int video_autosw_set(int enable) { - if (video_supported == TPACPI_VIDEO_570) - return acpi_evalf(ec_handle, NULL, "_Q17", "v"); - else if (video_supported == TPACPI_VIDEO_770) - return acpi_evalf(vid_handle, NULL, "VEXP", "v"); - else - return acpi_evalf(NULL, NULL, "\\VEXP", "v"); + if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0)) + return -EIO; + return 0; } -static int video_switch2(int status) +static int video_outputsw_cycle(void) { - int ret; - - if (video_supported == TPACPI_VIDEO_570) { - ret = acpi_evalf(NULL, NULL, - "\\_SB.PHS2", "vdd", 0x8b, status | 0x80); - } else if (video_supported == TPACPI_VIDEO_770) { - int autosw = video_autosw(); - if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) - return -EIO; + int autosw = video_autosw_get(); + int res; - ret = acpi_evalf(vid_handle, NULL, - "ASWT", "vdd", status * 0x100, 0); + if (autosw < 0) + return autosw; - acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw); - } else { - ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) && - acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1); + switch (video_supported) { + case TPACPI_VIDEO_570: + res = video_autosw_set(1); + if (res) + return res; + res = acpi_evalf(ec_handle, NULL, "_Q16", "v"); + break; + case TPACPI_VIDEO_770: + case TPACPI_VIDEO_NEW: + res = video_autosw_set(1); + if (res) + return res; + res = acpi_evalf(vid_handle, NULL, "VSWT", "v"); + break; + default: + return -ENOSYS; + } + if (!autosw && video_autosw_set(autosw)) { + printk(IBM_ERR "video auto-switch left enabled due to error\n"); + return -EIO; } - return ret; + return (res)? 0 : -EIO; +} + +static int video_expand_toggle(void) +{ + switch (video_supported) { + case TPACPI_VIDEO_570: + return acpi_evalf(ec_handle, NULL, "_Q17", "v")? + 0 : -EIO; + case TPACPI_VIDEO_770: + return acpi_evalf(vid_handle, NULL, "VEXP", "v")? + 0 : -EIO; + case TPACPI_VIDEO_NEW: + return acpi_evalf(NULL, NULL, "\\VEXP", "v")? + 0 : -EIO; + default: + return -ENOSYS; + } + /* not reached */ } static int video_read(char *p) { - int status = video_status(); - int autosw = video_autosw(); + int status, autosw; int len = 0; - if (!video_supported) { + if (video_supported == TPACPI_VIDEO_NONE) { len += sprintf(p + len, "status:\t\tnot supported\n"); return len; } + status = video_outputsw_get(); + if (status < 0) + return status; + + autosw = video_autosw_get(); + if (autosw < 0) + return autosw; + len += sprintf(p + len, "status:\t\tsupported\n"); len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); @@ -1060,47 +1143,56 @@ static int video_write(char *buf) { char *cmd; int enable, disable, status; + int res; - if (!video_supported) + if (video_supported == TPACPI_VIDEO_NONE) return -ENODEV; - enable = disable = 0; + enable = 0; + disable = 0; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "lcd_enable") == 0) { - enable |= 0x01; + enable |= TP_ACPI_VIDEO_S_LCD; } else if (strlencmp(cmd, "lcd_disable") == 0) { - disable |= 0x01; + disable |= TP_ACPI_VIDEO_S_LCD; } else if (strlencmp(cmd, "crt_enable") == 0) { - enable |= 0x02; + enable |= TP_ACPI_VIDEO_S_CRT; } else if (strlencmp(cmd, "crt_disable") == 0) { - disable |= 0x02; + disable |= TP_ACPI_VIDEO_S_CRT; } else if (video_supported == TPACPI_VIDEO_NEW && strlencmp(cmd, "dvi_enable") == 0) { - enable |= 0x08; + enable |= TP_ACPI_VIDEO_S_DVI; } else if (video_supported == TPACPI_VIDEO_NEW && strlencmp(cmd, "dvi_disable") == 0) { - disable |= 0x08; + disable |= TP_ACPI_VIDEO_S_DVI; } else if (strlencmp(cmd, "auto_enable") == 0) { - if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1)) - return -EIO; + res = video_autosw_set(1); + if (res) + return res; } else if (strlencmp(cmd, "auto_disable") == 0) { - if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0)) - return -EIO; + res = video_autosw_set(0); + if (res) + return res; } else if (strlencmp(cmd, "video_switch") == 0) { - if (!video_switch()) - return -EIO; + res = video_outputsw_cycle(); + if (res) + return res; } else if (strlencmp(cmd, "expand_toggle") == 0) { - if (!video_expand()) - return -EIO; + res = video_expand_toggle(); + if (res) + return res; } else return -EINVAL; } if (enable || disable) { - status = (video_status() & 0x0f & ~disable) | enable; - if (!video_switch2(status)) - return -EIO; + status = video_outputsw_get(); + if (status < 0) + return status; + res = video_outputsw_set((status & ~disable) | enable); + if (res) + return res; } return 0; diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index e06bad5c8fe4..3a8718a08116 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -446,17 +446,32 @@ enum video_access_mode { TPACPI_VIDEO_NEW, /* all others */ }; +enum { /* video status flags, based on VIDEO_570 */ + TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */ + TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */ + TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */ +}; + +enum { /* TPACPI_VIDEO_570 constants */ + TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */ + TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to + * video_status_flags */ + TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */ + TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */ +}; + static enum video_access_mode video_supported; static int video_orig_autosw; static acpi_handle vid_handle, vid2_handle; static int video_init(struct ibm_init_struct *iibm); static void video_exit(void); -static int video_status(void); -static int video_autosw(void); -static int video_switch(void); -static int video_switch2(int status); -static int video_expand(void); +static int video_outputsw_get(void); +static int video_outputsw_set(int status); +static int video_autosw_get(void); +static int video_autosw_set(int enable); +static int video_outputsw_cycle(void); +static int video_expand_toggle(void); static int video_read(char *p); static int video_write(char *buf); -- cgit v1.2.3-59-g8ed1b From c9bea99c1a712548db3437cbca52b0da8f30069c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:42 -0300 Subject: ACPI: thinkpad-acpi: clean up CMOS commands subdriver Some ThinkPad CMOS commands subdriver cleanups, and also rename/promote cmos_eval to a ACPI helper function, as it is used by many other subdrivers. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 39 ++++++++++++++++++++------------------- drivers/misc/thinkpad_acpi.h | 4 +++- 2 files changed, 23 insertions(+), 20 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 19c14bbe8b29..8829d3c6b444 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -273,6 +273,17 @@ static int _sta(acpi_handle handle) return status; } +static int issue_thinkpad_cmos_command(int cmos_cmd) +{ + if (!cmos_handle) + return -ENXIO; + + if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd)) + return -EIO; + + return 0; +} + /************************************************************************* * ACPI device model */ @@ -1550,14 +1561,6 @@ static int __init cmos_init(struct ibm_init_struct *iibm) return (cmos_handle)? 0 : 1; } -static int cmos_eval(int cmos_cmd) -{ - if (cmos_handle) - return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd); - else - return 1; -} - static int cmos_read(char *p) { int len = 0; @@ -1577,10 +1580,7 @@ static int cmos_read(char *p) static int cmos_write(char *buf) { char *cmd; - int cmos_cmd; - - if (!cmos_handle) - return -EINVAL; + int cmos_cmd, res; while ((cmd = next_cmd(&buf))) { if (sscanf(cmd, "%u", &cmos_cmd) == 1 && @@ -1589,8 +1589,9 @@ static int cmos_write(char *buf) } else return -EINVAL; - if (!cmos_eval(cmos_cmd)) - return -EIO; + res = issue_thinkpad_cmos_command(cmos_cmd); + if (res) + return res; } return 0; @@ -2093,7 +2094,7 @@ static int brightness_set(int value) cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN; inc = value > current_value ? 1 : -1; for (i = current_value; i != value; i += inc) { - if (!cmos_eval(cmos_cmd)) + if (issue_thinkpad_cmos_command(cmos_cmd)) return -EIO; if (!acpi_ec_write(brightness_offset, i + inc)) return -EIO; @@ -2210,16 +2211,16 @@ static int volume_write(char *buf) cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; inc = new_level > level ? 1 : -1; - if (mute && (!cmos_eval(cmos_cmd) || + if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || !acpi_ec_write(volume_offset, level))) return -EIO; for (i = level; i != new_level; i += inc) - if (!cmos_eval(cmos_cmd) || + if (issue_thinkpad_cmos_command(cmos_cmd) || !acpi_ec_write(volume_offset, i + inc)) return -EIO; - if (mute && (!cmos_eval(TP_CMOS_VOLUME_MUTE) || + if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || !acpi_ec_write(volume_offset, new_level + mute))) return -EIO; @@ -2228,7 +2229,7 @@ static int volume_write(char *buf) if (new_mute != mute) { /* level doesn't change */ cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; - if (!cmos_eval(cmos_cmd) || + if (issue_thinkpad_cmos_command(cmos_cmd) || !acpi_ec_write(volume_offset, level + new_mute)) return -EIO; } diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 3a8718a08116..fb0abb02a016 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -116,6 +116,9 @@ static void drv_acpi_handle_init(char *name, drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \ object##_paths, ARRAY_SIZE(object##_paths), &object##_path) +/* ThinkPad ACPI helpers */ +static int issue_thinkpad_cmos_command(int cmos_cmd); + /* procfs support */ static struct proc_dir_entry *proc_dir; @@ -275,7 +278,6 @@ static int brightness_write(char *buf); * CMOS subdriver */ -static int cmos_eval(int cmos_cmd); static int cmos_read(char *p); static int cmos_write(char *buf); -- cgit v1.2.3-59-g8ed1b From 04cc862c1893a055ab1117fa6f3aa0886c0ba032 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Sat, 21 Apr 2007 11:08:43 -0300 Subject: ACPI: thinkpad-acpi: cleanup thermal subdriver for sysfs conversion Clean-up the thermal subdriver for sysfs conversion. Make thermal_get_* reentrancy-safe while at it, and add the missing thermal_read_mode variable to the header file. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 79 +++++++++++++++++++++++++++++--------------- drivers/misc/thinkpad_acpi.h | 8 +++++ 2 files changed, 61 insertions(+), 26 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 8829d3c6b444..e9aec87a9f09 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1818,13 +1818,13 @@ static int __init thermal_init(struct ibm_init_struct *iibm) ta1 = ta2 = 0; for (i = 0; i < 8; i++) { - if (likely(acpi_ec_read(0x78 + i, &t))) { + if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) { ta1 |= t; } else { ta1 = 0; break; } - if (likely(acpi_ec_read(0xC0 + i, &t))) { + if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) { ta2 |= t; } else { ta1 = 0; @@ -1869,57 +1869,84 @@ static int __init thermal_init(struct ibm_init_struct *iibm) return (thermal_read_mode != TPACPI_THERMAL_NONE)? 0 : 1; } -static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) +/* idx is zero-based */ +static int thermal_get_sensor(int idx, s32 *value) { - int i, t; + int t; s8 tmp; - char tmpi[] = "TMPi"; + char tmpi[5]; - if (!s) - return -EINVAL; + t = TP_EC_THERMAL_TMP0; switch (thermal_read_mode) { #if TPACPI_MAX_THERMAL_SENSORS >= 16 case TPACPI_THERMAL_TPEC_16: - for (i = 0; i < 8; i++) { - if (!acpi_ec_read(0xC0 + i, &tmp)) - return -EIO; - s->temp[i + 8] = tmp * 1000; + if (idx >= 8 && idx <= 15) { + t = TP_EC_THERMAL_TMP8; + idx -= 8; } /* fallthrough */ #endif case TPACPI_THERMAL_TPEC_8: - for (i = 0; i < 8; i++) { - if (!acpi_ec_read(0x78 + i, &tmp)) + if (idx <= 7) { + if (!acpi_ec_read(t + idx, &tmp)) return -EIO; - s->temp[i] = tmp * 1000; + *value = tmp * 1000; + return 0; } - return (thermal_read_mode == TPACPI_THERMAL_TPEC_16) ? 16 : 8; + break; case TPACPI_THERMAL_ACPI_UPDT: - if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) - return -EIO; - for (i = 0; i < 8; i++) { - tmpi[3] = '0' + i; + if (idx <= 7) { + snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); + if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) + return -EIO; if (!acpi_evalf(ec_handle, &t, tmpi, "d")) return -EIO; - s->temp[i] = (t - 2732) * 100; + *value = (t - 2732) * 100; + return 0; } - return 8; + break; case TPACPI_THERMAL_ACPI_TMP07: - for (i = 0; i < 8; i++) { - tmpi[3] = '0' + i; + if (idx <= 7) { + snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); if (!acpi_evalf(ec_handle, &t, tmpi, "d")) return -EIO; - s->temp[i] = t * 1000; + *value = t * 1000; + return 0; } - return 8; + break; case TPACPI_THERMAL_NONE: default: - return 0; + return -ENOSYS; } + + return -EINVAL; +} + +static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) +{ + int res, i; + int n; + + n = 8; + i = 0; + + if (!s) + return -EINVAL; + + if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) + n = 16; + + for(i = 0 ; i < n; i++) { + res = thermal_get_sensor(i, &s->temp[i]); + if (res) + return res; + } + + return n; } static int thermal_read(char *p) diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index fb0abb02a016..6432b28339af 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -427,12 +427,20 @@ enum thermal_access_mode { TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */ }; +enum { /* TPACPI_THERMAL_TPEC_* */ + TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ + TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ +}; + #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ struct ibm_thermal_sensors_struct { s32 temp[TPACPI_MAX_THERMAL_SENSORS]; }; +static enum thermal_access_mode thermal_read_mode; + static int thermal_init(struct ibm_init_struct *iibm); +static int thermal_get_sensor(int idx, s32 *value); static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); static int thermal_read(char *p); -- cgit v1.2.3-59-g8ed1b From 54ae15014c306b3d7ad32c996fea9a5ac8560b60 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 24 Apr 2007 11:48:12 -0300 Subject: ACPI: thinkpad-acpi: register with the device model Register thinkpad-acpi platform driver and platform device for the device model. Also register the platform device with the hwmon class. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 40 +++++++++++++++++++++++++----- drivers/misc/Kconfig | 1 + drivers/misc/thinkpad_acpi.c | 54 +++++++++++++++++++++++++++++++++++++++++ drivers/misc/thinkpad_acpi.h | 8 ++++++ 4 files changed, 97 insertions(+), 6 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index 1a42b77e2ece..0e4e053cface 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -1,7 +1,7 @@ ThinkPad ACPI Extras Driver Version 0.14 - March 26th, 2007 + April 21st, 2007 Borislav Deianov Henrique de Moraes Holschuh @@ -67,11 +67,39 @@ thinkpad-specific bay functionality. Features -------- -The driver creates the /proc/acpi/ibm directory. There is a file under -that directory for each feature described below. Note that while the -driver is still in the alpha stage, the exact proc file format and -commands supported by the various features is guaranteed to change -frequently. +The driver exports two different interfaces to userspace, which can be +used to access the features it provides. One is a legacy procfs-based +interface, which will be removed at some time in the distant future. +The other is a new sysfs-based interface which is not complete yet. + +The procfs interface creates the /proc/acpi/ibm directory. There is a +file under that directory for each feature it supports. The procfs +interface is mostly frozen, and will change very little if at all: it +will not be extended to add any new functionality in the driver, instead +all new functionality will be implemented on the sysfs interface. + +The sysfs interface tries to blend in the generic Linux sysfs subsystems +and classes as much as possible. Since some of these subsystems are not +yet ready or stabilized, it is expected that this interface will change, +and any and all userspace programs must deal with it. + + +Notes about the sysfs interface: + +Unlike what was done with the procfs interface, correctness when talking +to the sysfs interfaces will be enforced, as will correctness in the +thinkpad-acpi's implementation of sysfs interfaces. + +Also, any bugs in the thinkpad-acpi sysfs driver code or in the +thinkpad-acpi's implementation of the sysfs interfaces will be fixed for +maximum correctness, even if that means changing an interface in +non-compatible ways. As these interfaces mature both in the kernel and +in thinkpad-acpi, such changes should become quite rare. + +Applications interfacing to the thinkpad-acpi sysfs interfaces must +follow all sysfs guidelines and correctly process all errors (the sysfs +interface makes extensive use of errors). File descriptors and open / +close operations to the sysfs inodes must also be properly implemented. Driver version -- /proc/acpi/ibm/driver --------------------------------------- diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 44e4c8fb7a74..445c4b10c41e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -126,6 +126,7 @@ config THINKPAD_ACPI tristate "ThinkPad ACPI Laptop Extras" depends on X86 && ACPI select BACKLIGHT_CLASS_DEVICE + select HWMON ---help--- This is a driver for the IBM and Lenovo ThinkPad laptops. It adds support for Fn-Fx key combinations, Bluetooth control, video diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 9b4eea4c8ff7..e47eaf72763d 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -474,6 +474,25 @@ static char *next_cmd(char **cmds) } +/**************************************************************************** + **************************************************************************** + * + * Device model: hwmon and platform + * + **************************************************************************** + ****************************************************************************/ + +static struct platform_device *tpacpi_pdev = NULL; +static struct class_device *tpacpi_hwmon = NULL; + +static struct platform_driver tpacpi_pdriver = { + .driver = { + .name = IBM_DRVR_NAME, + .owner = THIS_MODULE, + }, +}; + + /**************************************************************************** **************************************************************************** * @@ -3225,10 +3244,12 @@ static int __init thinkpad_acpi_module_init(void) { int ret, i; + /* Driver-level probe */ ret = probe_for_thinkpad(); if (ret) return ret; + /* Driver initialization */ ibm_thinkpad_ec_found = check_dmi_for_ec(); IBM_ACPIHANDLE_INIT(ecrd); IBM_ACPIHANDLE_INIT(ecwr); @@ -3241,6 +3262,31 @@ static int __init thinkpad_acpi_module_init(void) } proc_dir->owner = THIS_MODULE; + ret = platform_driver_register(&tpacpi_pdriver); + if (ret) { + printk(IBM_ERR "unable to register platform driver\n"); + thinkpad_acpi_module_exit(); + return ret; + } + + /* Device initialization */ + tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1, + NULL, 0); + if (IS_ERR(tpacpi_pdev)) { + ret = PTR_ERR(tpacpi_pdev); + tpacpi_pdev = NULL; + printk(IBM_ERR "unable to register platform device\n"); + thinkpad_acpi_module_exit(); + return ret; + } + tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev); + if (IS_ERR(tpacpi_hwmon)) { + ret = PTR_ERR(tpacpi_hwmon); + tpacpi_hwmon = NULL; + printk(IBM_ERR "unable to register hwmon device\n"); + thinkpad_acpi_module_exit(); + return ret; + } for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { ret = ibm_init(&ibms_init[i]); if (ret >= 0 && *ibms_init[i].param) @@ -3266,6 +3312,14 @@ static void thinkpad_acpi_module_exit(void) dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); + if (tpacpi_hwmon) + hwmon_device_unregister(tpacpi_hwmon); + + if (tpacpi_pdev) + platform_device_unregister(tpacpi_pdev); + + platform_driver_unregister(&tpacpi_pdriver); + if (proc_dir) remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 6432b28339af..fea580999e94 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -56,6 +58,7 @@ #define IBM_PROC_DIR "ibm" #define IBM_ACPI_EVENT_PREFIX "ibm" +#define IBM_DRVR_NAME IBM_FILE #define IBM_LOG IBM_FILE ": " #define IBM_ERR KERN_ERR IBM_LOG @@ -130,6 +133,11 @@ static int dispatch_procfs_write(struct file *file, unsigned long count, void *data); static char *next_cmd(char **cmds); +/* Device model */ +static struct platform_device *tpacpi_pdev; +static struct class_device *tpacpi_hwmon; +static struct platform_driver tpacpi_pdriver; + /* Module */ static int experimental; static u32 dbg_level; -- cgit v1.2.3-59-g8ed1b From 176750d68801bfa4a88d1cf54174aa0347d7e5d8 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 24 Apr 2007 11:48:13 -0300 Subject: ACPI: thinkpad-acpi: driver sysfs conversion Add the sysfs attributes for the platform driver. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 42 ++++++++++++++++++- drivers/misc/thinkpad_acpi.c | 90 +++++++++++++++++++++++++++++++++++++++++ drivers/misc/thinkpad_acpi.h | 3 ++ 3 files changed, 133 insertions(+), 2 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index 0e4e053cface..cc079afaf66b 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -101,11 +101,39 @@ follow all sysfs guidelines and correctly process all errors (the sysfs interface makes extensive use of errors). File descriptors and open / close operations to the sysfs inodes must also be properly implemented. -Driver version -- /proc/acpi/ibm/driver ---------------------------------------- +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/. + +Sysfs device attributes are on the driver's sysfs attribute space, +for 2.6.20 this is /sys/devices/platform/thinkpad-acpi/. + +Driver version +-------------- + +procfs: /proc/acpi/ibm/driver +sysfs driver attribute: version The driver name and version. No commands can be written to this file. +Sysfs interface version +----------------------- + +sysfs driver attribute: interface_version + +Version of the thinkpad-acpi sysfs interface, as an unsigned long +(output in hex format: 0xAAAABBCC), where: + AAAA - major revision + BB - minor revision + CC - bugfix revision + +The sysfs interface version changelog for the driver can be found at the +end of this document. Changes to the sysfs interface done by the kernel +subsystems are not documented here, nor are they tracked by this +attribute. + Hot keys -- /proc/acpi/ibm/hotkey --------------------------------- @@ -745,9 +773,19 @@ to enable more than one output class, just add their values. There is also a kernel build option to enable more debugging information, which may be necessary to debug driver problems. +The level of debugging information output by the driver can be changed +at runtime through sysfs, using the driver attribute debug_level. The +attribute takes the same bitmask as the debug module parameter above. + Force loading of module ----------------------- If thinkpad-acpi refuses to detect your ThinkPad, you can try to specify the module parameter force_load=1. Regardless of whether this works or not, please contact ibm-acpi-devel@lists.sourceforge.net with a report. + + +Sysfs interface changelog: + +0x000100: Initial sysfs support, as a single platform driver and + device. diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index e47eaf72763d..a31d00d570cb 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -22,6 +22,7 @@ */ #define IBM_VERSION "0.14" +#define TPACPI_SYSFS_VERSION 0x000100 /* * Changelog: @@ -493,6 +494,87 @@ static struct platform_driver tpacpi_pdriver = { }; +/************************************************************************* + * thinkpad-acpi driver attributes + */ + +/* interface_version --------------------------------------------------- */ +static ssize_t tpacpi_driver_interface_version_show( + struct device_driver *drv, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); +} + +static DRIVER_ATTR(interface_version, S_IRUGO, + tpacpi_driver_interface_version_show, NULL); + +/* debug_level --------------------------------------------------------- */ +static ssize_t tpacpi_driver_debug_show(struct device_driver *drv, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); +} + +static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, + const char *buf, size_t count) +{ + unsigned long t; + char *endp; + + t = simple_strtoul(buf, &endp, 0); + while (*endp && isspace(*endp)) + endp++; + if (*endp) + return -EINVAL; + + dbg_level = t; + + return count; +} + +static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, + tpacpi_driver_debug_show, tpacpi_driver_debug_store); + +/* version ------------------------------------------------------------- */ +static ssize_t tpacpi_driver_version_show(struct device_driver *drv, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION); +} + +static DRIVER_ATTR(version, S_IRUGO, + tpacpi_driver_version_show, NULL); + +/* --------------------------------------------------------------------- */ + +static struct driver_attribute* tpacpi_driver_attributes[] = { + &driver_attr_debug_level, &driver_attr_version, + &driver_attr_interface_version, +}; + +static int __init tpacpi_create_driver_attributes(struct device_driver *drv) +{ + int i, res; + + i = 0; + res = 0; + while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { + res = driver_create_file(drv, tpacpi_driver_attributes[i]); + i++; + } + + return res; +} + +static void tpacpi_remove_driver_attributes(struct device_driver *drv) +{ + int i; + + for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) + driver_remove_file(drv, tpacpi_driver_attributes[i]); +} + /**************************************************************************** **************************************************************************** * @@ -3268,6 +3350,13 @@ static int __init thinkpad_acpi_module_init(void) thinkpad_acpi_module_exit(); return ret; } + ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); + if (ret) { + printk(IBM_ERR "unable to create sysfs driver attributes\n"); + thinkpad_acpi_module_exit(); + return ret; + } + /* Device initialization */ tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1, @@ -3318,6 +3407,7 @@ static void thinkpad_acpi_module_exit(void) if (tpacpi_pdev) platform_device_unregister(tpacpi_pdev); + tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); platform_driver_unregister(&tpacpi_pdriver); if (proc_dir) diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index fea580999e94..37860582956f 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -137,6 +138,8 @@ static char *next_cmd(char **cmds); static struct platform_device *tpacpi_pdev; static struct class_device *tpacpi_hwmon; static struct platform_driver tpacpi_pdriver; +static int tpacpi_create_driver_attributes(struct device_driver *drv); +static void tpacpi_remove_driver_attributes(struct device_driver *drv); /* Module */ static int experimental; -- cgit v1.2.3-59-g8ed1b From 7252374a39d794879f5e47bcfa0a16e7599b27b5 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 24 Apr 2007 11:48:14 -0300 Subject: ACPI: thinkpad-acpi: add infrastructure for the sysfs device attributes Add infrastructure to deal with sysfs attributes and grouping, and helpers for common sysfs parsing. Switch driver attributes to use them. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 86 +++++++++++++++++++++++++++++++++++++++++--- drivers/misc/thinkpad_acpi.h | 21 +++++++++++ 2 files changed, 102 insertions(+), 5 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index a31d00d570cb..ca6d15cdc5f0 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -520,12 +520,8 @@ static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, const char *buf, size_t count) { unsigned long t; - char *endp; - t = simple_strtoul(buf, &endp, 0); - while (*endp && isspace(*endp)) - endp++; - if (*endp) + if (parse_strtoul(buf, 0xffff, &t)) return -EINVAL; dbg_level = t; @@ -575,6 +571,86 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) driver_remove_file(drv, tpacpi_driver_attributes[i]); } +/************************************************************************* + * sysfs support helpers + */ + +struct attribute_set_obj { + struct attribute_set s; + struct attribute *a; +} __attribute__((packed)); + +static struct attribute_set *create_attr_set(unsigned int max_members, + const char* name) +{ + struct attribute_set_obj *sobj; + + if (max_members == 0) + return NULL; + + /* Allocates space for implicit NULL at the end too */ + sobj = kzalloc(sizeof(struct attribute_set_obj) + + max_members * sizeof(struct attribute *), + GFP_KERNEL); + if (!sobj) + return NULL; + sobj->s.max_members = max_members; + sobj->s.group.attrs = &sobj->a; + sobj->s.group.name = name; + + return &sobj->s; +} + +/* not multi-threaded safe, use it in a single thread per set */ +static int add_to_attr_set(struct attribute_set* s, struct attribute *attr) +{ + if (!s || !attr) + return -EINVAL; + + if (s->members >= s->max_members) + return -ENOMEM; + + s->group.attrs[s->members] = attr; + s->members++; + + return 0; +} + +static int add_many_to_attr_set(struct attribute_set* s, + struct attribute **attr, + unsigned int count) +{ + int i, res; + + for (i = 0; i < count; i++) { + res = add_to_attr_set(s, attr[i]); + if (res) + return res; + } + + return 0; +} + +static void delete_attr_set(struct attribute_set* s, struct kobject *kobj) +{ + sysfs_remove_group(kobj, &s->group); + destroy_attr_set(s); +} + +static int parse_strtoul(const char *buf, + unsigned long max, unsigned long *value) +{ + char *endp; + + *value = simple_strtoul(buf, &endp, 0); + while (*endp && isspace(*endp)) + endp++; + if (*endp || *value > max) + return -EINVAL; + + return 0; +} + /**************************************************************************** **************************************************************************** * diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 37860582956f..84fdefe0d200 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -134,6 +134,27 @@ static int dispatch_procfs_write(struct file *file, unsigned long count, void *data); static char *next_cmd(char **cmds); +/* sysfs support */ +struct attribute_set { + unsigned int members, max_members; + struct attribute_group group; +}; + +static struct attribute_set *create_attr_set(unsigned int max_members, + const char* name); +#define destroy_attr_set(_set) \ + kfree(_set); +static int add_to_attr_set(struct attribute_set* s, struct attribute *attr); +static int add_many_to_attr_set(struct attribute_set* s, + struct attribute **attr, + unsigned int count); +#define register_attr_set_with_sysfs(_attr_set, _kobj) \ + sysfs_create_group(_kobj, &_attr_set->group) +static void delete_attr_set(struct attribute_set* s, struct kobject *kobj); + +static int parse_strtoul(const char *buf, unsigned long max, + unsigned long *value); + /* Device model */ static struct platform_device *tpacpi_pdev; static struct class_device *tpacpi_hwmon; -- cgit v1.2.3-59-g8ed1b From 40ca9fdf8aa7d929e2b8939be1e6380d107381e1 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 24 Apr 2007 11:48:15 -0300 Subject: ACPI: thinkpad-acpi: protect fan and hotkey data structures Add proper mutex locking to some data structures access subject to races due to concurrent access of driver functions on the hotkey and fan subdrivers. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 114 +++++++++++++++++++++++++++++++++---------- drivers/misc/thinkpad_acpi.h | 5 ++ 2 files changed, 92 insertions(+), 27 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index ca6d15cdc5f0..aa69ff0c1c91 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -704,6 +704,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); IBM_ACPIHANDLE_INIT(hkey); + mutex_init(&hotkey_mutex); /* hotkey not supported on 570 */ tp_features.hotkey = hkey_handle != NULL; @@ -752,6 +753,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event) } } +/* + * Call with hotkey_mutex held + */ static int hotkey_get(int *status, int *mask) { if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) @@ -764,6 +768,9 @@ static int hotkey_get(int *status, int *mask) return 0; } +/* + * Call with hotkey_mutex held + */ static int hotkey_set(int status, int mask) { int i; @@ -792,7 +799,11 @@ static int hotkey_read(char *p) return len; } + res = mutex_lock_interruptible(&hotkey_mutex); + if (res < 0) + return res; res = hotkey_get(&status, &mask); + mutex_unlock(&hotkey_mutex); if (res) return res; @@ -818,10 +829,15 @@ static int hotkey_write(char *buf) if (!tp_features.hotkey) return -ENODEV; + res = mutex_lock_interruptible(&hotkey_mutex); + if (res < 0) + return res; + res = hotkey_get(&status, &mask); if (res) - return res; + goto errexit; + res = 0; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "enable") == 0) { status = 1; @@ -834,18 +850,19 @@ static int hotkey_write(char *buf) /* mask set */ } else if (sscanf(cmd, "%x", &mask) == 1) { /* mask set */ - } else - return -EINVAL; + } else { + res = -EINVAL; + goto errexit; + } do_cmd = 1; } - if (do_cmd) { + if (do_cmd) res = hotkey_set(status, mask); - if (res) - return res; - } - return 0; +errexit: + mutex_unlock(&hotkey_mutex); + return res; } static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { @@ -2575,6 +2592,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) { vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); + mutex_init(&fan_mutex); fan_status_access_mode = TPACPI_FAN_NONE; fan_control_access_mode = TPACPI_FAN_WR_NONE; fan_control_commands = 0; @@ -2764,10 +2782,17 @@ static void fan_watchdog_reset(void) static int fan_set_level(int level) { + int res; + switch (fan_control_access_mode) { case TPACPI_FAN_WR_ACPI_SFAN: if (level >= 0 && level <= 7) { - if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) + res = mutex_lock_interruptible(&fan_mutex); + if (res < 0) + return res; + res = acpi_evalf(sfan_handle, NULL, NULL, "vd", level); + mutex_unlock(&fan_mutex); + if (!res) return -EIO; } else return -EINVAL; @@ -2780,7 +2805,12 @@ static int fan_set_level(int level) ((level < 0) || (level > 7))) return -EINVAL; - if (!acpi_ec_write(fan_status_offset, level)) + res = mutex_lock_interruptible(&fan_mutex); + if (res < 0) + return res; + res = acpi_ec_write(fan_status_offset, level); + mutex_unlock(&fan_mutex); + if (!res) return -EIO; else tp_features.fan_ctrl_status_undef = 0; @@ -2797,25 +2827,33 @@ static int fan_set_enable(void) u8 s; int rc; + rc = mutex_lock_interruptible(&fan_mutex); + if (rc < 0) + return rc; + switch (fan_control_access_mode) { case TPACPI_FAN_WR_ACPI_FANS: case TPACPI_FAN_WR_TPEC: - if ((rc = fan_get_status(&s)) < 0) - return rc; + rc = fan_get_status(&s); + if (rc < 0) + break; /* Don't go out of emergency fan mode */ if (s != 7) s = TP_EC_FAN_AUTO; if (!acpi_ec_write(fan_status_offset, s)) - return -EIO; - else + rc = -EIO; + else { tp_features.fan_ctrl_status_undef = 0; + rc = 0; + } break; case TPACPI_FAN_WR_ACPI_SFAN: - if ((rc = fan_get_status(&s)) < 0) - return rc; + rc = fan_get_status(&s); + if (rc < 0) + break; s &= 0x07; @@ -2824,53 +2862,75 @@ static int fan_set_enable(void) s = 4; if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) - return -EIO; + rc= -EIO; + else + rc = 0; break; default: - return -ENXIO; + rc = -ENXIO; } - return 0; + + mutex_unlock(&fan_mutex); + return rc; } static int fan_set_disable(void) { + int rc; + + rc = mutex_lock_interruptible(&fan_mutex); + if (rc < 0) + return rc; + + rc = 0; switch (fan_control_access_mode) { case TPACPI_FAN_WR_ACPI_FANS: case TPACPI_FAN_WR_TPEC: if (!acpi_ec_write(fan_status_offset, 0x00)) - return -EIO; + rc = -EIO; else tp_features.fan_ctrl_status_undef = 0; break; case TPACPI_FAN_WR_ACPI_SFAN: if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) - return -EIO; + rc = -EIO; break; default: - return -ENXIO; + rc = -ENXIO; } - return 0; + + mutex_unlock(&fan_mutex); + return rc; } static int fan_set_speed(int speed) { + int rc; + + rc = mutex_lock_interruptible(&fan_mutex); + if (rc < 0) + return rc; + + rc = 0; switch (fan_control_access_mode) { case TPACPI_FAN_WR_ACPI_FANS: if (speed >= 0 && speed <= 65535) { if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", speed, speed, speed)) - return -EIO; + rc = -EIO; } else - return -EINVAL; + rc = -EINVAL; break; default: - return -ENXIO; + rc = -ENXIO; } - return 0; + + mutex_unlock(&fan_mutex); + return rc; } static int fan_read(char *p) diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 84fdefe0d200..a9feb53c6d3c 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -375,6 +376,8 @@ static enum fan_control_commands fan_control_commands; static u8 fan_control_initial_status; static int fan_watchdog_maxinterval; +struct mutex fan_mutex; + static acpi_handle fans_handle, gfan_handle, sfan_handle; static int fan_init(struct ibm_init_struct *iibm); @@ -403,6 +406,8 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc); static int hotkey_orig_status; static int hotkey_orig_mask; +static struct mutex hotkey_mutex; + static int hotkey_init(struct ibm_init_struct *iibm); static void hotkey_exit(void); static int hotkey_get(int *status, int *mask); -- cgit v1.2.3-59-g8ed1b From 2c37aa4e22dd55070c608290c5031f2ee93e69ce Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 24 Apr 2007 11:48:16 -0300 Subject: ACPI: thinkpad-acpi: add sysfs support to the thermal subdriver Export thinkpad thermal sensors to sysfs, following the hwmon specification for thermal monitoring sensors. ThinkPad thermal monitoring is done by the EC. Sensors can show up or disappear at runtime when they are inside hotswappable hardware, such as batteries. Sensors that are not available return -ENXIO when accessed. Up to 16 thermal sensors are supported on new firmware (but nobody has reported a ThinkPad with more than 12 sensors so far), and 8 sensors are supported on older firmware. Thermal sensor mapping is model-specific. Precision varies, it is 1 degree Celcius on new ThinkPads, but higher on some older models. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 26 +++++++-- drivers/misc/thinkpad_acpi.c | 122 +++++++++++++++++++++++++++++++++++++++- drivers/misc/thinkpad_acpi.h | 2 + 3 files changed, 143 insertions(+), 7 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index cc079afaf66b..80c0bf28e392 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -458,17 +458,17 @@ X40: 16 - one medium-pitched beep repeating constantly, stop with 17 17 - stop 16 -Temperature sensors -- /proc/acpi/ibm/thermal ---------------------------------------------- +Temperature sensors +------------------- + +procfs: /proc/acpi/ibm/thermal +sysfs device attributes: (hwmon) temp*_input Most ThinkPads include six or more separate temperature sensors but only expose the CPU temperature through the standard ACPI methods. This feature shows readings from up to eight different sensors on older ThinkPads, and it has experimental support for up to sixteen different -sensors on newer ThinkPads. Readings from sensors that are not available -return -128. - -No commands can be written to this file. +sensors on newer ThinkPads. EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the implementation directly accesses hardware registers and may not work as @@ -525,6 +525,20 @@ The A31 has a very atypical layout for the thermal sensors 8: Bay Battery: secondary sensor +Procfs notes: + Readings from sensors that are not available return -128. + No commands can be written to this file. + +Sysfs notes: + Sensors that are not available return the ENXIO error. This + status may change at runtime, as there are hotplug thermal + sensors, like those inside the batteries and docks. + + thinkpad-acpi thermal sensors are reported through the hwmon + subsystem, and follow all of the hwmon guidelines at + Documentation/hwmon. + + EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump ------------------------------------------------------------------------ diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index aa69ff0c1c91..d5526e882ddd 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1992,11 +1992,91 @@ static struct ibm_struct beep_driver_data = { static enum thermal_access_mode thermal_read_mode; +/* sysfs temp##_input -------------------------------------------------- */ + +static ssize_t thermal_temp_input_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = + to_sensor_dev_attr(attr); + int idx = sensor_attr->index; + s32 value; + int res; + + res = thermal_get_sensor(idx, &value); + if (res) + return res; + if (value == TP_EC_THERMAL_TMP_NA * 1000) + return -ENXIO; + + return snprintf(buf, PAGE_SIZE, "%d\n", value); +} + +#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \ + SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB) + +static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = { + THERMAL_SENSOR_ATTR_TEMP(1, 0), + THERMAL_SENSOR_ATTR_TEMP(2, 1), + THERMAL_SENSOR_ATTR_TEMP(3, 2), + THERMAL_SENSOR_ATTR_TEMP(4, 3), + THERMAL_SENSOR_ATTR_TEMP(5, 4), + THERMAL_SENSOR_ATTR_TEMP(6, 5), + THERMAL_SENSOR_ATTR_TEMP(7, 6), + THERMAL_SENSOR_ATTR_TEMP(8, 7), + THERMAL_SENSOR_ATTR_TEMP(9, 8), + THERMAL_SENSOR_ATTR_TEMP(10, 9), + THERMAL_SENSOR_ATTR_TEMP(11, 10), + THERMAL_SENSOR_ATTR_TEMP(12, 11), + THERMAL_SENSOR_ATTR_TEMP(13, 12), + THERMAL_SENSOR_ATTR_TEMP(14, 13), + THERMAL_SENSOR_ATTR_TEMP(15, 14), + THERMAL_SENSOR_ATTR_TEMP(16, 15), +}; + +#define THERMAL_ATTRS(X) \ + &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr + +static struct attribute *thermal_temp_input_attr[] = { + THERMAL_ATTRS(8), + THERMAL_ATTRS(9), + THERMAL_ATTRS(10), + THERMAL_ATTRS(11), + THERMAL_ATTRS(12), + THERMAL_ATTRS(13), + THERMAL_ATTRS(14), + THERMAL_ATTRS(15), + THERMAL_ATTRS(0), + THERMAL_ATTRS(1), + THERMAL_ATTRS(2), + THERMAL_ATTRS(3), + THERMAL_ATTRS(4), + THERMAL_ATTRS(5), + THERMAL_ATTRS(6), + THERMAL_ATTRS(7), + NULL +}; + +static const struct attribute_group thermal_temp_input16_group = { + .attrs = thermal_temp_input_attr +}; + +static const struct attribute_group thermal_temp_input8_group = { + .attrs = &thermal_temp_input_attr[8] +}; + +#undef THERMAL_SENSOR_ATTR_TEMP +#undef THERMAL_ATTRS + +/* --------------------------------------------------------------------- */ + static int __init thermal_init(struct ibm_init_struct *iibm) { u8 t, ta1, ta2; int i; int acpi_tmp7; + int res; vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n"); @@ -2060,7 +2140,46 @@ static int __init thermal_init(struct ibm_init_struct *iibm) str_supported(thermal_read_mode != TPACPI_THERMAL_NONE), thermal_read_mode); - return (thermal_read_mode != TPACPI_THERMAL_NONE)? 0 : 1; + switch(thermal_read_mode) { + case TPACPI_THERMAL_TPEC_16: + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &thermal_temp_input16_group); + if (res) + return res; + break; + case TPACPI_THERMAL_TPEC_8: + case TPACPI_THERMAL_ACPI_TMP07: + case TPACPI_THERMAL_ACPI_UPDT: + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &thermal_temp_input8_group); + if (res) + return res; + break; + case TPACPI_THERMAL_NONE: + default: + return 1; + } + + return 0; +} + +static void thermal_exit(void) +{ + switch(thermal_read_mode) { + case TPACPI_THERMAL_TPEC_16: + sysfs_remove_group(&tpacpi_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, + &thermal_temp_input16_group); + break; + case TPACPI_THERMAL_NONE: + default: + break; + } } /* idx is zero-based */ @@ -2168,6 +2287,7 @@ static int thermal_read(char *p) static struct ibm_struct thermal_driver_data = { .name = "thermal", .read = thermal_read, + .exit = thermal_exit, }; /************************************************************************* diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index a9feb53c6d3c..e833ff3caf39 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -467,6 +468,7 @@ enum thermal_access_mode { enum { /* TPACPI_THERMAL_TPEC_* */ TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ + TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ }; #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ -- cgit v1.2.3-59-g8ed1b From fe98a52ce7540fb3a19d57488a08864110cf4d5c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 24 Apr 2007 11:48:17 -0300 Subject: ACPI: thinkpad-acpi: add sysfs support to fan subdriver Export sysfs attributes to monitor and control the internal thinkpad fan (some thinkpads have more than one fan, but thinkpad-acpi doesn't support the second fan yet). The sysfs interface follows the hwmon design guide for fan devices. Also, fix some stray "thermal" files in the fan procfs description that have been there forever, and officially support "full-speed" as the name for the PWM-disabled state of the fan controller to keep it in line with the hwmon interface. It is much better a name for that mode than the unobvious "disengaged" anyway. Change the procfs interface to also accept full-speed as a fan level, but still report it as disengaged for backwards compatibility. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 157 ++++++++++++------- drivers/misc/thinkpad_acpi.c | 326 +++++++++++++++++++++++++++++++++++++--- drivers/misc/thinkpad_acpi.h | 6 + 3 files changed, 415 insertions(+), 74 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index 80c0bf28e392..339ce21e59df 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -642,8 +642,11 @@ distinct. The unmute the volume after the mute command, use either the up or down command (the level command will not unmute the volume). The current volume level and mute state is shown in the file. -EXPERIMENTAL: fan speed, fan enable/disable -- /proc/acpi/ibm/fan ------------------------------------------------------------------ +EXPERIMENTAL: fan speed, fan enable/disable +------------------------------------------- + +procfs: /proc/acpi/ibm/fan +sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable This feature is marked EXPERIMENTAL because the implementation directly accesses hardware registers and may not work as expected. USE @@ -656,27 +659,26 @@ from the hardware registers of the embedded controller. This is known to work on later R, T and X series ThinkPads but may show a bogus value on other models. -Most ThinkPad fans work in "levels". Level 0 stops the fan. The higher -the level, the higher the fan speed, although adjacent levels often map -to the same fan speed. 7 is the highest level, where the fan reaches -the maximum recommended speed. Level "auto" means the EC changes the -fan level according to some internal algorithm, usually based on -readings from the thermal sensors. Level "disengaged" means the EC -disables the speed-locked closed-loop fan control, and drives the fan as -fast as it can go, which might exceed hardware limits, so use this level -with caution. +Fan levels: -The fan usually ramps up or down slowly from one speed to another, -and it is normal for the EC to take several seconds to react to fan -commands. +Most ThinkPad fans work in "levels" at the firmware interface. Level 0 +stops the fan. The higher the level, the higher the fan speed, although +adjacent levels often map to the same fan speed. 7 is the highest +level, where the fan reaches the maximum recommended speed. -The fan may be enabled or disabled with the following commands: +Level "auto" means the EC changes the fan level according to some +internal algorithm, usually based on readings from the thermal sensors. - echo enable >/proc/acpi/ibm/fan - echo disable >/proc/acpi/ibm/fan +There is also a "full-speed" level, also known as "disengaged" level. +In this level, the EC disables the speed-locked closed-loop fan control, +and drives the fan as fast as it can go, which might exceed hardware +limits, so use this level with caution. -Placing a fan on level 0 is the same as disabling it. Enabling a fan -will try to place it in a safe level if it is too slow or disabled. +The fan usually ramps up or down slowly from one speed to another, and +it is normal for the EC to take several seconds to react to fan +commands. The full-speed level may take up to two minutes to ramp up to +maximum speed, and in some ThinkPads, the tachometer readings go stale +while the EC is transitioning to the full-speed level. WARNING WARNING WARNING: do not leave the fan disabled unless you are monitoring all of the temperature sensor readings and you are ready to @@ -694,48 +696,101 @@ fan is turned off when the CPU temperature drops to 49 degrees and the HDD temperature drops to 41 degrees. These thresholds cannot currently be controlled. +The ThinkPad's ACPI DSDT code will reprogram the fan on its own when +certain conditions are met. It will override any fan programming done +through thinkpad-acpi. + +The thinkpad-acpi kernel driver can be programmed to revert the fan +level to a safe setting if userspace does not issue one of the procfs +fan commands: "enable", "disable", "level" or "watchdog", or if there +are no writes to pwm1_enable (or to pwm1 *if and only if* pwm1_enable is +set to 1, manual mode) within a configurable amount of time of up to +120 seconds. This functionality is called fan safety watchdog. + +Note that the watchdog timer stops after it enables the fan. It will be +rearmed again automatically (using the same interval) when one of the +above mentioned fan commands is received. The fan watchdog is, +therefore, not suitable to protect against fan mode changes made through +means other than the "enable", "disable", and "level" procfs fan +commands, or the hwmon fan control sysfs interface. + +Procfs notes: + +The fan may be enabled or disabled with the following commands: + + echo enable >/proc/acpi/ibm/fan + echo disable >/proc/acpi/ibm/fan + +Placing a fan on level 0 is the same as disabling it. Enabling a fan +will try to place it in a safe level if it is too slow or disabled. + The fan level can be controlled with the command: - echo 'level ' > /proc/acpi/ibm/thermal + echo 'level ' > /proc/acpi/ibm/fan -Where is an integer from 0 to 7, or one of the words "auto" -or "disengaged" (without the quotes). Not all ThinkPads support the -"auto" and "disengaged" levels. +Where is an integer from 0 to 7, or one of the words "auto" or +"full-speed" (without the quotes). Not all ThinkPads support the "auto" +and "full-speed" levels. The driver accepts "disengaged" as an alias for +"full-speed", and reports it as "disengaged" for backwards +compatibility. On the X31 and X40 (and ONLY on those models), the fan speed can be -controlled to a certain degree. Once the fan is running, it can be +controlled to a certain degree. Once the fan is running, it can be forced to run faster or slower with the following command: - echo 'speed ' > /proc/acpi/ibm/thermal + echo 'speed ' > /proc/acpi/ibm/fan -The sustainable range of fan speeds on the X40 appears to be from -about 3700 to about 7350. Values outside this range either do not have -any effect or the fan speed eventually settles somewhere in that -range. The fan cannot be stopped or started with this command. +The sustainable range of fan speeds on the X40 appears to be from about +3700 to about 7350. Values outside this range either do not have any +effect or the fan speed eventually settles somewhere in that range. The +fan cannot be stopped or started with this command. This functionality +is incomplete, and not available through the sysfs interface. -The ThinkPad's ACPI DSDT code will reprogram the fan on its own when -certain conditions are met. It will override any fan programming done -through thinkpad-acpi. +To program the safety watchdog, use the "watchdog" command. + + echo 'watchdog ' > /proc/acpi/ibm/fan + +If you want to disable the watchdog, use 0 as the interval. + +Sysfs notes: + +The sysfs interface follows the hwmon subsystem guidelines for the most +part, and the exception is the fan safety watchdog. + +hwmon device attribute pwm1_enable: + 0: PWM offline (fan is set to full-speed mode) + 1: Manual PWM control (use pwm1 to set fan level) + 2: Hardware PWM control (EC "auto" mode) + 3: reserved (Software PWM control, not implemented yet) + + Modes 0 and 2 are not supported by all ThinkPads, and the driver + is not always able to detect this. If it does know a mode is + unsupported, it will return -EINVAL. + +hwmon device attribute pwm1: + Fan level, scaled from the firmware values of 0-7 to the hwmon + scale of 0-255. 0 means fan stopped, 255 means highest normal + speed (level 7). + + This attribute only commands the fan if pmw1_enable is set to 1 + (manual PWM control). + +hwmon device attribute fan1_input: + Fan tachometer reading, in RPM. May go stale on certain + ThinkPads while the EC transitions the PWM to offline mode, + which can take up to two minutes. May return rubbish on older + ThinkPads. + +driver attribute fan_watchdog: + Fan safety watchdog timer interval, in seconds. Minimum is + 1 second, maximum is 120 seconds. 0 disables the watchdog. + +To stop the fan: set pwm1 to zero, and pwm1_enable to 1. + +To start the fan in a safe mode: set pwm1_enable to 2. If that fails +with ENOTSUP, set it to 1 and set pwm1 to at least 128 (255 would be the +safest choice, though). -The thinkpad-acpi kernel driver can be programmed to revert the fan -level to a safe setting if userspace does not issue one of the fan -commands: "enable", "disable", "level" or "watchdog" within a -configurable ammount of time. To do this, use the "watchdog" command. - - echo 'watchdog ' > /proc/acpi/ibm/fan - -Interval is the ammount of time in seconds to wait for one of the -above mentioned fan commands before reseting the fan level to a safe -one. If set to zero, the watchdog is disabled (default). When the -watchdog timer runs out, it does the exact equivalent of the "enable" -fan command. - -Note that the watchdog timer stops after it enables the fan. It will -be rearmed again automatically (using the same interval) when one of -the above mentioned fan commands is received. The fan watchdog is, -therefore, not suitable to protect against fan mode changes made -through means other than the "enable", "disable", and "level" fan -commands. EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan --------------------------------------- diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index d5526e882ddd..a4d7ee472396 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2695,6 +2695,7 @@ static enum fan_control_access_mode fan_control_access_mode; static enum fan_control_commands fan_control_commands; static u8 fan_control_initial_status; +static u8 fan_control_desired_level; static void fan_watchdog_fire(struct work_struct *ignored); static int fan_watchdog_maxinterval; @@ -2708,8 +2709,222 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ "JFNS", /* 770x-JL */ ); /* all others */ +/* + * SYSFS fan layout: hwmon compatible (device) + * + * pwm*_enable: + * 0: "disengaged" mode + * 1: manual mode + * 2: native EC "auto" mode (recommended, hardware default) + * + * pwm*: set speed in manual mode, ignored otherwise. + * 0 is level 0; 255 is level 7. Intermediate points done with linear + * interpolation. + * + * fan*_input: tachometer reading, RPM + * + * + * SYSFS fan layout: extensions + * + * fan_watchdog (driver): + * fan watchdog interval in seconds, 0 disables (default), max 120 + */ + +/* sysfs fan pwm1_enable ----------------------------------------------- */ +static ssize_t fan_pwm1_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int res, mode; + u8 status; + + res = fan_get_status_safe(&status); + if (res) + return res; + + if (unlikely(tp_features.fan_ctrl_status_undef)) { + if (status != fan_control_initial_status) { + tp_features.fan_ctrl_status_undef = 0; + } else { + /* Return most likely status. In fact, it + * might be the only possible status */ + status = TP_EC_FAN_AUTO; + } + } + + if (status & TP_EC_FAN_FULLSPEED) { + mode = 0; + } else if (status & TP_EC_FAN_AUTO) { + mode = 2; + } else + mode = 1; + + return snprintf(buf, PAGE_SIZE, "%d\n", mode); +} + +static ssize_t fan_pwm1_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + int res, level; + + if (parse_strtoul(buf, 2, &t)) + return -EINVAL; + + switch (t) { + case 0: + level = TP_EC_FAN_FULLSPEED; + break; + case 1: + level = TPACPI_FAN_LAST_LEVEL; + break; + case 2: + level = TP_EC_FAN_AUTO; + break; + case 3: + /* reserved for software-controlled auto mode */ + return -ENOSYS; + default: + return -EINVAL; + } + + res = fan_set_level_safe(level); + if (res < 0) + return res; + + fan_watchdog_reset(); + + return count; +} + +static struct device_attribute dev_attr_fan_pwm1_enable = + __ATTR(pwm1_enable, S_IWUSR | S_IRUGO, + fan_pwm1_enable_show, fan_pwm1_enable_store); + +/* sysfs fan pwm1 ------------------------------------------------------ */ +static ssize_t fan_pwm1_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int res; + u8 status; + + res = fan_get_status_safe(&status); + if (res) + return res; + + if (unlikely(tp_features.fan_ctrl_status_undef)) { + if (status != fan_control_initial_status) { + tp_features.fan_ctrl_status_undef = 0; + } else { + status = TP_EC_FAN_AUTO; + } + } + + if ((status & + (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) + status = fan_control_desired_level; + + if (status > 7) + status = 7; + + return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7); +} + +static ssize_t fan_pwm1_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long s; + int rc; + u8 status, newlevel; + + if (parse_strtoul(buf, 255, &s)) + return -EINVAL; + + /* scale down from 0-255 to 0-7 */ + newlevel = (s >> 5) & 0x07; + + rc = mutex_lock_interruptible(&fan_mutex); + if (rc < 0) + return rc; + + rc = fan_get_status(&status); + if (!rc && (status & + (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { + rc = fan_set_level(newlevel); + if (!rc) + fan_update_desired_level(newlevel); + fan_watchdog_reset(); + } + + mutex_unlock(&fan_mutex); + return (rc)? rc : count; +} + +static struct device_attribute dev_attr_fan_pwm1 = + __ATTR(pwm1, S_IWUSR | S_IRUGO, + fan_pwm1_show, fan_pwm1_store); + +/* sysfs fan fan1_input ------------------------------------------------ */ +static ssize_t fan_fan1_input_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int res; + unsigned int speed; + + res = fan_get_speed(&speed); + if (res < 0) + return res; + + return snprintf(buf, PAGE_SIZE, "%u\n", speed); +} + +static struct device_attribute dev_attr_fan_fan1_input = + __ATTR(fan1_input, S_IRUGO, + fan_fan1_input_show, NULL); + +/* sysfs fan fan_watchdog (driver) ------------------------------------- */ +static ssize_t fan_fan_watchdog_show(struct device_driver *drv, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval); +} + +static ssize_t fan_fan_watchdog_store(struct device_driver *drv, + const char *buf, size_t count) +{ + unsigned long t; + + if (parse_strtoul(buf, 120, &t)) + return -EINVAL; + + fan_watchdog_maxinterval = t; + fan_watchdog_reset(); + + return count; +} + +static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, + fan_fan_watchdog_show, fan_fan_watchdog_store); + +/* --------------------------------------------------------------------- */ +static struct attribute *fan_attributes[] = { + &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, + &dev_attr_fan_fan1_input.attr, + NULL +}; + +static const struct attribute_group fan_attr_group = { + .attrs = fan_attributes, +}; + static int __init fan_init(struct ibm_init_struct *iibm) { + int rc; + vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); mutex_init(&fan_mutex); @@ -2718,6 +2933,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) fan_control_commands = 0; fan_watchdog_maxinterval = 0; tp_features.fan_ctrl_status_undef = 0; + fan_control_desired_level = 7; IBM_ACPIHANDLE_INIT(fans); IBM_ACPIHANDLE_INIT(gfan); @@ -2796,9 +3012,36 @@ static int __init fan_init(struct ibm_init_struct *iibm) fan_control_access_mode != TPACPI_FAN_WR_NONE), fan_status_access_mode, fan_control_access_mode); - return (fan_status_access_mode != TPACPI_FAN_NONE || - fan_control_access_mode != TPACPI_FAN_WR_NONE)? - 0 : 1; + /* update fan_control_desired_level */ + if (fan_status_access_mode != TPACPI_FAN_NONE) + fan_get_status_safe(NULL); + + if (fan_status_access_mode != TPACPI_FAN_NONE || + fan_control_access_mode != TPACPI_FAN_WR_NONE) { + rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &fan_attr_group); + if (!(rc < 0)) + rc = driver_create_file(&tpacpi_pdriver.driver, + &driver_attr_fan_watchdog); + if (rc < 0) + return rc; + return 0; + } else + return 1; +} + +/* + * Call with fan_mutex held + */ +static void fan_update_desired_level(u8 status) +{ + if ((status & + (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { + if (status > 7) + fan_control_desired_level = 7; + else + fan_control_desired_level = status; + } } static int fan_get_status(u8 *status) @@ -2837,9 +3080,33 @@ static int fan_get_status(u8 *status) return 0; } +static int fan_get_status_safe(u8 *status) +{ + int rc; + u8 s; + + rc = mutex_lock_interruptible(&fan_mutex); + if (rc < 0) + return rc; + rc = fan_get_status(&s); + if (!rc) + fan_update_desired_level(s); + mutex_unlock(&fan_mutex); + + if (status) + *status = s; + + return rc; +} + 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); + cancel_delayed_work(&fan_watchdog_task); flush_scheduled_work(); } @@ -2902,17 +3169,10 @@ static void fan_watchdog_reset(void) static int fan_set_level(int level) { - int res; - switch (fan_control_access_mode) { case TPACPI_FAN_WR_ACPI_SFAN: if (level >= 0 && level <= 7) { - res = mutex_lock_interruptible(&fan_mutex); - if (res < 0) - return res; - res = acpi_evalf(sfan_handle, NULL, NULL, "vd", level); - mutex_unlock(&fan_mutex); - if (!res) + if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) return -EIO; } else return -EINVAL; @@ -2925,12 +3185,7 @@ static int fan_set_level(int level) ((level < 0) || (level > 7))) return -EINVAL; - res = mutex_lock_interruptible(&fan_mutex); - if (res < 0) - return res; - res = acpi_ec_write(fan_status_offset, level); - mutex_unlock(&fan_mutex); - if (!res) + if (!acpi_ec_write(fan_status_offset, level)) return -EIO; else tp_features.fan_ctrl_status_undef = 0; @@ -2942,6 +3197,25 @@ static int fan_set_level(int level) return 0; } +static int fan_set_level_safe(int level) +{ + int rc; + + rc = mutex_lock_interruptible(&fan_mutex); + if (rc < 0) + return rc; + + if (level == TPACPI_FAN_LAST_LEVEL) + level = fan_control_desired_level; + + rc = fan_set_level(level); + if (!rc) + fan_update_desired_level(level); + + mutex_unlock(&fan_mutex); + return rc; +} + static int fan_set_enable(void) { u8 s; @@ -3009,19 +3283,24 @@ static int fan_set_disable(void) case TPACPI_FAN_WR_TPEC: if (!acpi_ec_write(fan_status_offset, 0x00)) rc = -EIO; - else + else { + fan_control_desired_level = 0; tp_features.fan_ctrl_status_undef = 0; + } break; case TPACPI_FAN_WR_ACPI_SFAN: if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) rc = -EIO; + else + fan_control_desired_level = 0; break; default: rc = -ENXIO; } + mutex_unlock(&fan_mutex); return rc; } @@ -3063,7 +3342,7 @@ static int fan_read(char *p) switch (fan_status_access_mode) { case TPACPI_FAN_RD_ACPI_GFAN: /* 570, 600e/x, 770e, 770x */ - if ((rc = fan_get_status(&status)) < 0) + if ((rc = fan_get_status_safe(&status)) < 0) return rc; len += sprintf(p + len, "status:\t\t%s\n" @@ -3073,7 +3352,7 @@ static int fan_read(char *p) case TPACPI_FAN_RD_TPEC: /* all except 570, 600e/x, 770e, 770x */ - if ((rc = fan_get_status(&status)) < 0) + if ((rc = fan_get_status_safe(&status)) < 0) return rc; if (unlikely(tp_features.fan_ctrl_status_undef)) { @@ -3117,7 +3396,7 @@ static int fan_read(char *p) default: len += sprintf(p + len, " ( is 0-7, " - "auto, disengaged)\n"); + "auto, disengaged, full-speed)\n"); break; } } @@ -3140,12 +3419,13 @@ static int fan_write_cmd_level(const char *cmd, int *rc) if (strlencmp(cmd, "level auto") == 0) level = TP_EC_FAN_AUTO; - else if (strlencmp(cmd, "level disengaged") == 0) + else if ((strlencmp(cmd, "level disengaged") == 0) | + (strlencmp(cmd, "level full-speed") == 0)) level = TP_EC_FAN_FULLSPEED; else if (sscanf(cmd, "level %d", &level) != 1) return 0; - if ((*rc = fan_set_level(level)) == -ENXIO) + if ((*rc = fan_set_level_safe(level)) == -ENXIO) printk(IBM_ERR "level command accepted for unsupported " "access mode %d", fan_control_access_mode); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index e833ff3caf39..2fe4d61cc27f 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -349,6 +349,8 @@ enum { /* Fan control constants */ TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ + + TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */ }; enum fan_status_access_mode { @@ -375,6 +377,7 @@ static enum fan_status_access_mode fan_status_access_mode; static enum fan_control_access_mode fan_control_access_mode; static enum fan_control_commands fan_control_commands; static u8 fan_control_initial_status; +static u8 fan_control_desired_level; static int fan_watchdog_maxinterval; struct mutex fan_mutex; @@ -384,10 +387,13 @@ static acpi_handle fans_handle, gfan_handle, sfan_handle; static int fan_init(struct ibm_init_struct *iibm); static void fan_exit(void); static int fan_get_status(u8 *status); +static int fan_get_status_safe(u8 *status); static int fan_get_speed(unsigned int *speed); +static void fan_update_desired_level(u8 status); static void fan_watchdog_fire(struct work_struct *ignored); static void fan_watchdog_reset(void); static int fan_set_level(int level); +static int fan_set_level_safe(int level); static int fan_set_enable(void); static int fan_set_disable(void); static int fan_set_speed(int speed); -- cgit v1.2.3-59-g8ed1b From 7d5a015eece8be9186d3613d595643a520555e33 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 24 Apr 2007 11:48:20 -0300 Subject: ACPI: thinkpad-acpi: update brightness sysfs interface support Update the brightness sysfs interface (done through the backlight class) to be in line with the rest of the thinkpad-acpi driver. This renames the incorrect, un-obvious, and clash-prone name of "ibm" for the backlight device to a much more fitting and descriptive "thinkpad_screen". This is something I wanted to do for quite a while... Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 52 ++++++++++++++++++++++++++++++++++++----- drivers/misc/thinkpad_acpi.c | 5 ++-- drivers/misc/thinkpad_acpi.h | 2 ++ 3 files changed, 51 insertions(+), 8 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index 352e8aee63fe..eab4997efc0f 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -611,19 +611,59 @@ registers contain the current battery capacity, etc. If you experiment with this, do send me your results (including some complete dumps with a description of the conditions when they were taken.) -LCD brightness control -- /proc/acpi/ibm/brightness ---------------------------------------------------- +LCD brightness control +---------------------- + +procfs: /proc/acpi/ibm/brightness +sysfs backlight device "thinkpad_screen" This feature allows software control of the LCD brightness on ThinkPad -models which don't have a hardware brightness slider. The available -commands are: +models which don't have a hardware brightness slider. + +It has some limitations: the LCD backlight cannot be actually turned on or off +by this interface, and in many ThinkPad models, the "dim while on battery" +functionality will be enabled by the BIOS when this interface is used, and +cannot be controlled. + +The backlight control has eight levels, ranging from 0 to 7. Some of the +levels may not be distinct. + +Procfs notes: + + The available commands are: echo up >/proc/acpi/ibm/brightness echo down >/proc/acpi/ibm/brightness echo 'level ' >/proc/acpi/ibm/brightness -The number range is 0 to 7, although not all of them may be -distinct. The current brightness level is shown in the file. +Sysfs notes: + +The interface is implemented through the backlight sysfs class, which is poorly +documented at this time. + +Locate the thinkpad_screen device under /sys/class/backlight, and inside it +there will be the following attributes: + + max_brightness: + Reads the maximum brightness the hardware can be set to. + The minimum is always zero. + + actual_brightness: + Reads what brightness the screen is set to at this instant. + + brightness: + Writes request the driver to change brightness to the given + value. Reads will tell you what brightness the driver is trying + to set the display to when "power" is set to zero and the display + has not been dimmed by a kernel power management event. + + power: + power management mode, where 0 is "display on", and 1 to 3 will + dim the display backlight to brightness level 0 because + thinkpad-acpi cannot really turn the backlight off. Kernel + power management events can temporarily increase the current + power management level, i.e. they can dim the display. + Volume control -- /proc/acpi/ibm/volume --------------------------------------- diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index ba749df189ab..c0a023cc5ded 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2414,8 +2414,9 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (b < 0) return b; - ibm_backlight_device = backlight_device_register("ibm", NULL, NULL, - &ibm_backlight_data); + ibm_backlight_device = backlight_device_register( + TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, + &ibm_backlight_data); if (IS_ERR(ibm_backlight_device)) { printk(IBM_ERR "Could not register backlight device\n"); return PTR_ERR(ibm_backlight_device); diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 2fe4d61cc27f..8348fc653009 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -296,6 +296,8 @@ static int bluetooth_write(char *buf); * Brightness (backlight) subdriver */ +#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" + static struct backlight_device *ibm_backlight_device; static int brightness_offset = 0x31; -- cgit v1.2.3-59-g8ed1b From ecf2a80a97b3d38ae008fa8a3cb98cd540ac1eae Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Fri, 27 Apr 2007 22:00:09 -0300 Subject: ACPI: thinkpad-acpi: add a fan-control feature master toggle Len Brown considers that an active by default fan control interface in laptops may be too close to giving users enough rope. There is a good chance he is quite correct on this, especially if someone decides to use that interface in applets and users are not aware of its risks. This patch adds a master switch to thinkpad-acpi that enables or disables the entire fan-control feature as a module parameter: "fan_control". It defaults to disabled. Set it to non-zero to enable fan control. Also, the patch removes the expermiental status from fan control, since it is stable enough to not be called experimental, and the master switch makes it safe enough to do so. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 15 +++++++-------- drivers/misc/thinkpad_acpi.c | 30 +++++++++++++++++++++++++++++- drivers/misc/thinkpad_acpi.h | 2 ++ 3 files changed, 38 insertions(+), 9 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index eab4997efc0f..bca50d78a425 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -38,7 +38,7 @@ detailed description): - Experimental: embedded controller register dump - LCD brightness control - Volume control - - Experimental: fan speed, fan enable/disable + - Fan control and monitoring: fan speed, fan enable/disable - Experimental: WAN enable and disable A compatibility table by model and feature is maintained on the web @@ -681,21 +681,20 @@ distinct. The unmute the volume after the mute command, use either the up or down command (the level command will not unmute the volume). The current volume level and mute state is shown in the file. -EXPERIMENTAL: fan speed, fan enable/disable -------------------------------------------- +Fan control and monitoring: fan speed, fan enable/disable +--------------------------------------------------------- procfs: /proc/acpi/ibm/fan sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable -This feature is marked EXPERIMENTAL because the implementation -directly accesses hardware registers and may not work as expected. USE -WITH CAUTION! To use this feature, you need to supply the -experimental=1 parameter when loading the module. +NOTE NOTE NOTE: fan control operations are disabled by default for +safety reasons. To enable them, the module parameter "fan_control=1" +must be given to thinkpad-acpi. This feature attempts to show the current fan speed, control mode and other fan data that might be available. The speed is read directly from the hardware registers of the embedded controller. This is known -to work on later R, T and X series ThinkPads but may show a bogus +to work on later R, T, X and Z series ThinkPads but may show a bogus value on other models. Fan levels: diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index c0a023cc5ded..7dc3a2206195 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -2935,6 +2935,9 @@ static ssize_t fan_fan_watchdog_store(struct device_driver *drv, if (parse_strtoul(buf, 120, &t)) return -EINVAL; + if (!fan_control_allowed) + return -EPERM; + fan_watchdog_maxinterval = t; fan_watchdog_reset(); @@ -3046,6 +3049,14 @@ static int __init fan_init(struct ibm_init_struct *iibm) fan_control_access_mode != TPACPI_FAN_WR_NONE), fan_status_access_mode, fan_control_access_mode); + /* fan control master switch */ + if (!fan_control_allowed) { + fan_control_access_mode = TPACPI_FAN_WR_NONE; + fan_control_commands = 0; + dbg_printk(TPACPI_DBG_INIT, + "fan control features disabled by parameter\n"); + } + /* update fan_control_desired_level */ if (fan_status_access_mode != TPACPI_FAN_NONE) fan_get_status_safe(NULL); @@ -3203,6 +3214,9 @@ static void fan_watchdog_reset(void) static int fan_set_level(int level) { + if (!fan_control_allowed) + return -EPERM; + switch (fan_control_access_mode) { case TPACPI_FAN_WR_ACPI_SFAN: if (level >= 0 && level <= 7) { @@ -3242,6 +3256,9 @@ static int fan_set_level_safe(int level) { int rc; + if (!fan_control_allowed) + return -EPERM; + rc = mutex_lock_interruptible(&fan_mutex); if (rc < 0) return rc; @@ -3262,6 +3279,9 @@ static int fan_set_enable(void) u8 s; int rc; + if (!fan_control_allowed) + return -EPERM; + rc = mutex_lock_interruptible(&fan_mutex); if (rc < 0) return rc; @@ -3315,6 +3335,9 @@ static int fan_set_disable(void) { int rc; + if (!fan_control_allowed) + return -EPERM; + rc = mutex_lock_interruptible(&fan_mutex); if (rc < 0) return rc; @@ -3351,6 +3374,9 @@ static int fan_set_speed(int speed) { int rc; + if (!fan_control_allowed) + return -EPERM; + rc = mutex_lock_interruptible(&fan_mutex); if (rc < 0) return rc; @@ -3558,7 +3584,6 @@ static struct ibm_struct fan_driver_data = { .read = fan_read, .write = fan_write, .exit = fan_exit, - .flags.experimental = 1, }; /**************************************************************************** @@ -3879,6 +3904,9 @@ module_param_named(debug, dbg_level, uint, 0); static int force_load; module_param(force_load, int, 0); +static int fan_control_allowed; +module_param_named(fan_control, fan_control_allowed, int, 0); + #define IBM_PARAM(feature) \ module_param_call(feature, set_ibm_param, NULL, NULL, 0) diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 8348fc653009..a9e709368256 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -375,6 +375,8 @@ enum fan_control_commands { * and also watchdog cmd */ }; +static int fan_control_allowed; + static enum fan_status_access_mode fan_status_access_mode; static enum fan_control_access_mode fan_control_access_mode; static enum fan_control_commands fan_control_commands; -- cgit v1.2.3-59-g8ed1b From a0416420e2c6244792d6f308183ad57c40532078 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Fri, 27 Apr 2007 22:00:16 -0300 Subject: ACPI: thinkpad-acpi: add sysfs support to hotkey subdriver Add the hotkey sysfs support. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 58 ++++++++++++++---- drivers/misc/thinkpad_acpi.c | 127 ++++++++++++++++++++++++++++++++++++++++ drivers/misc/thinkpad_acpi.h | 2 + 3 files changed, 176 insertions(+), 11 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index e3ad7a4f7402..ebeed589f6d7 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -134,8 +134,11 @@ end of this document. Changes to the sysfs interface done by the kernel subsystems are not documented here, nor are they tracked by this attribute. -Hot keys -- /proc/acpi/ibm/hotkey ---------------------------------- +Hot keys +-------- + +procfs: /proc/acpi/ibm/hotkey +sysfs device attribute: hotkey/* Without this driver, only the Fn-F4 key (sleep button) generates an ACPI event. With the driver loaded, the hotkey feature enabled and the @@ -149,15 +152,6 @@ All labeled Fn-Fx key combinations generate distinct events. In addition, the lid microswitch and some docking station buttons may also generate such events. -The following commands can be written to this file: - - echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature - echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature - echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys - echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys - ... any other 4-hex-digit mask ... - echo reset > /proc/acpi/ibm/hotkey -- restore the original mask - The bit mask allows some control over which hot keys generate ACPI events. Not all bits in the mask can be modified. Not all bits that can be modified do anything. Not all hot keys can be individually @@ -189,6 +183,48 @@ buttons do not generate ACPI events even with this driver. They *can* be used through the "ThinkPad Buttons" utility, see http://www.nongnu.org/tpb/ +procfs notes: + +The following commands can be written to the /proc/acpi/ibm/hotkey file: + + echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature + echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature + echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys + echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys + ... any other 4-hex-digit mask ... + echo reset > /proc/acpi/ibm/hotkey -- restore the original mask + +sysfs notes: + + The hot keys attributes are in a hotkey/ subdirectory off the + thinkpad device. + + bios_enabled: + Returns the status of the hot keys feature when + thinkpad-acpi was loaded. Upon module unload, the hot + key feature status will be restored to this value. + + 0: hot keys were disabled + 1: hot keys were enabled + + bios_mask: + Returns the hot keys mask when thinkpad-acpi was loaded. + Upon module unload, the hot keys mask will be restored + to this value. + + enable: + Enables/disables the hot keys feature, and reports + current status of the hot keys feature. + + 0: disables the hot keys feature / feature disabled + 1: enables the hot keys feature / feature enabled + + mask: + bit mask to enable ACPI event generation for each hot + key (see above). Returns the current status of the hot + keys mask, and allows one to modify it. + + Bluetooth -- /proc/acpi/ibm/bluetooth ------------------------------------- diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index a56526500c18..83a8d984e709 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -706,6 +706,108 @@ static struct ibm_struct thinkpad_acpi_driver_data = { static int hotkey_orig_status; static int hotkey_orig_mask; +static struct attribute_set *hotkey_dev_attributes = NULL; + +/* sysfs hotkey enable ------------------------------------------------- */ +static ssize_t hotkey_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int res, status, mask; + + res = hotkey_get(&status, &mask); + if (res) + return res; + + return snprintf(buf, PAGE_SIZE, "%d\n", status); +} + +static ssize_t hotkey_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + int res, status, mask; + + if (parse_strtoul(buf, 1, &t)) + return -EINVAL; + + res = hotkey_get(&status, &mask); + if (!res) + res = hotkey_set(t, mask); + + return (res) ? res : count; +} + +static struct device_attribute dev_attr_hotkey_enable = + __ATTR(enable, S_IWUSR | S_IRUGO, + hotkey_enable_show, hotkey_enable_store); + +/* sysfs hotkey mask --------------------------------------------------- */ +static ssize_t hotkey_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int res, status, mask; + + res = hotkey_get(&status, &mask); + if (res) + return res; + + return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask); +} + +static ssize_t hotkey_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + int res, status, mask; + + if (parse_strtoul(buf, 0xffff, &t)) + return -EINVAL; + + res = hotkey_get(&status, &mask); + if (!res) + hotkey_set(status, t); + + return (res) ? res : count; +} + +static struct device_attribute dev_attr_hotkey_mask = + __ATTR(mask, S_IWUSR | S_IRUGO, + hotkey_mask_show, hotkey_mask_store); + +/* sysfs hotkey bios_enabled ------------------------------------------- */ +static ssize_t hotkey_bios_enabled_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status); +} + +static struct device_attribute dev_attr_hotkey_bios_enabled = + __ATTR(bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL); + +/* sysfs hotkey bios_mask ---------------------------------------------- */ +static ssize_t hotkey_bios_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask); +} + +static struct device_attribute dev_attr_hotkey_bios_mask = + __ATTR(bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); + +/* --------------------------------------------------------------------- */ + +static struct attribute *hotkey_mask_attributes[] = { + &dev_attr_hotkey_mask.attr, + &dev_attr_hotkey_bios_enabled.attr, + &dev_attr_hotkey_bios_mask.attr, +}; + static int __init hotkey_init(struct ibm_init_struct *iibm) { int res; @@ -722,6 +824,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) str_supported(tp_features.hotkey)); if (tp_features.hotkey) { + hotkey_dev_attributes = create_attr_set(4, + TPACPI_HOTKEY_SYSFS_GROUP); + if (!hotkey_dev_attributes) + return -ENOMEM; + res = add_to_attr_set(hotkey_dev_attributes, + &dev_attr_hotkey_enable.attr); + if (res) + 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 = @@ -731,6 +842,16 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) str_supported(tp_features.hotkey_mask)); res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); + if (!res && tp_features.hotkey_mask) { + res = add_many_to_attr_set(hotkey_dev_attributes, + hotkey_mask_attributes, + ARRAY_SIZE(hotkey_mask_attributes)); + } + if (!res) + res = register_attr_set_with_sysfs( + hotkey_dev_attributes, + &tpacpi_pdev->dev.kobj); + if (res) return res; } @@ -748,6 +869,11 @@ static void hotkey_exit(void) if (res) printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n"); } + + if (hotkey_dev_attributes) { + delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); + hotkey_dev_attributes = NULL; + } } static void hotkey_notify(struct ibm_struct *ibm, u32 event) @@ -798,6 +924,7 @@ static int hotkey_set(int status, int mask) return 0; } +/* procfs -------------------------------------------------------------- */ static int hotkey_read(char *p) { int res, status, mask; diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index a9e709368256..7615adb381c8 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -414,6 +414,8 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc); * Hotkey subdriver */ +#define TPACPI_HOTKEY_SYSFS_GROUP "hotkey" + static int hotkey_orig_status; static int hotkey_orig_mask; -- cgit v1.2.3-59-g8ed1b From d3a6ade4f84416d774c3e5db5faae1840d55bd97 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Fri, 27 Apr 2007 22:00:17 -0300 Subject: ACPI: thinkpad-acpi: add sysfs support to wan and bluetooth subdrivers Add support to sysfs to the wan and bluetooth subdrivers. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/thinkpad-acpi.txt | 61 ++++++++++++++--- drivers/misc/thinkpad_acpi.c | 144 ++++++++++++++++++++++++++++++++++++---- drivers/misc/thinkpad_acpi.h | 4 ++ 3 files changed, 186 insertions(+), 23 deletions(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt index ebeed589f6d7..2d4803359a04 100644 --- a/Documentation/thinkpad-acpi.txt +++ b/Documentation/thinkpad-acpi.txt @@ -225,15 +225,35 @@ sysfs notes: keys mask, and allows one to modify it. -Bluetooth -- /proc/acpi/ibm/bluetooth -------------------------------------- +Bluetooth +--------- -This feature shows the presence and current state of a Bluetooth -device. If Bluetooth is installed, the following commands can be used: +procfs: /proc/acpi/ibm/bluetooth +sysfs device attribute: bluetooth/enable + +This feature shows the presence and current state of a ThinkPad +Bluetooth device in the internal ThinkPad CDC slot. + +Procfs notes: + +If Bluetooth is installed, the following commands can be used: echo enable > /proc/acpi/ibm/bluetooth echo disable > /proc/acpi/ibm/bluetooth +Sysfs notes: + + If the Bluetooth CDC card is installed, it can be enabled / + disabled through the "bluetooth/enable" thinkpad-acpi device + attribute, and its current status can also be queried. + + enable: + 0: disables Bluetooth / Bluetooth is disabled + 1: enables Bluetooth / Bluetooth is enabled. + + Note: this interface will be probably be superseeded by the + generic rfkill class. + Video output control -- /proc/acpi/ibm/video -------------------------------------------- @@ -874,23 +894,42 @@ with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255 would be the safest choice, though). -EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan ---------------------------------------- +EXPERIMENTAL: WAN +----------------- + +procfs: /proc/acpi/ibm/wan +sysfs device attribute: wwan/enable This feature is marked EXPERIMENTAL because the implementation directly accesses hardware registers and may not work as expected. USE WITH CAUTION! To use this feature, you need to supply the experimental=1 parameter when loading the module. -This feature shows the presence and current state of a WAN (Sierra -Wireless EV-DO) device. If WAN is installed, the following commands can -be used: +This feature shows the presence and current state of a W-WAN (Sierra +Wireless EV-DO) device. + +It was tested on a Lenovo Thinkpad X60. It should probably work on other +Thinkpad models which come with this module installed. + +Procfs notes: + +If the W-WAN card is installed, the following commands can be used: echo enable > /proc/acpi/ibm/wan echo disable > /proc/acpi/ibm/wan -It was tested on a Lenovo Thinkpad X60. It should probably work on other -Thinkpad models which come with this module installed. +Sysfs notes: + + If the W-WAN card is installed, it can be enabled / + disabled through the "wwan/enable" thinkpad-acpi device + attribute, and its current status can also be queried. + + enable: + 0: disables WWAN card / WWAN card is disabled + 1: enables WWAN card / WWAN card is enabled. + + Note: this interface will be probably be superseeded by the + generic rfkill class. Multiple Commands, Module Parameters ------------------------------------ diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 83a8d984e709..6c36a55cb3d1 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1020,8 +1020,54 @@ static struct ibm_struct hotkey_driver_data = { * Bluetooth subdriver */ +/* sysfs bluetooth enable ---------------------------------------------- */ +static ssize_t bluetooth_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int status; + + status = bluetooth_get_radiosw(); + if (status < 0) + return status; + + return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); +} + +static ssize_t bluetooth_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + int res; + + if (parse_strtoul(buf, 1, &t)) + return -EINVAL; + + res = bluetooth_set_radiosw(t); + + return (res) ? res : count; +} + +static struct device_attribute dev_attr_bluetooth_enable = + __ATTR(enable, S_IWUSR | S_IRUGO, + bluetooth_enable_show, bluetooth_enable_store); + +/* --------------------------------------------------------------------- */ + +static struct attribute *bluetooth_attributes[] = { + &dev_attr_bluetooth_enable.attr, + NULL +}; + +static const struct attribute_group bluetooth_attr_group = { + .name = TPACPI_BLUETH_SYSFS_GROUP, + .attrs = bluetooth_attributes, +}; + static int __init bluetooth_init(struct ibm_init_struct *iibm) { + int res; int status = 0; vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); @@ -1037,17 +1083,29 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) str_supported(tp_features.bluetooth), status); - if (tp_features.bluetooth && - !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { - /* no bluetooth hardware present in system */ - tp_features.bluetooth = 0; - dbg_printk(TPACPI_DBG_INIT, - "bluetooth hardware not installed\n"); + if (tp_features.bluetooth) { + if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { + /* no bluetooth hardware present in system */ + tp_features.bluetooth = 0; + dbg_printk(TPACPI_DBG_INIT, + "bluetooth hardware not installed\n"); + } else { + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &bluetooth_attr_group); + if (res) + return res; + } } return (tp_features.bluetooth)? 0 : 1; } +static void bluetooth_exit(void) +{ + sysfs_remove_group(&tpacpi_pdev->dev.kobj, + &bluetooth_attr_group); +} + static int bluetooth_get_radiosw(void) { int status; @@ -1080,6 +1138,7 @@ static int bluetooth_set_radiosw(int radio_on) return 0; } +/* procfs -------------------------------------------------------------- */ static int bluetooth_read(char *p) { int len = 0; @@ -1119,14 +1178,61 @@ static struct ibm_struct bluetooth_driver_data = { .name = "bluetooth", .read = bluetooth_read, .write = bluetooth_write, + .exit = bluetooth_exit, }; /************************************************************************* * Wan subdriver */ +/* sysfs wan enable ---------------------------------------------------- */ +static ssize_t wan_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int status; + + status = wan_get_radiosw(); + if (status < 0) + return status; + + return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0); +} + +static ssize_t wan_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long t; + int res; + + if (parse_strtoul(buf, 1, &t)) + return -EINVAL; + + res = wan_set_radiosw(t); + + return (res) ? res : count; +} + +static struct device_attribute dev_attr_wan_enable = + __ATTR(enable, S_IWUSR | S_IRUGO, + wan_enable_show, wan_enable_store); + +/* --------------------------------------------------------------------- */ + +static struct attribute *wan_attributes[] = { + &dev_attr_wan_enable.attr, + NULL +}; + +static const struct attribute_group wan_attr_group = { + .name = TPACPI_WAN_SYSFS_GROUP, + .attrs = wan_attributes, +}; + static int __init wan_init(struct ibm_init_struct *iibm) { + int res; int status = 0; vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); @@ -1140,17 +1246,29 @@ static int __init wan_init(struct ibm_init_struct *iibm) str_supported(tp_features.wan), status); - if (tp_features.wan && - !(status & TP_ACPI_WANCARD_HWPRESENT)) { - /* no wan hardware present in system */ - tp_features.wan = 0; - dbg_printk(TPACPI_DBG_INIT, - "wan hardware not installed\n"); + if (tp_features.wan) { + if (!(status & TP_ACPI_WANCARD_HWPRESENT)) { + /* no wan hardware present in system */ + tp_features.wan = 0; + dbg_printk(TPACPI_DBG_INIT, + "wan hardware not installed\n"); + } else { + res = sysfs_create_group(&tpacpi_pdev->dev.kobj, + &wan_attr_group); + if (res) + return res; + } } return (tp_features.wan)? 0 : 1; } +static void wan_exit(void) +{ + sysfs_remove_group(&tpacpi_pdev->dev.kobj, + &wan_attr_group); +} + static int wan_get_radiosw(void) { int status; @@ -1183,6 +1301,7 @@ static int wan_set_radiosw(int radio_on) return 0; } +/* procfs -------------------------------------------------------------- */ static int wan_read(char *p) { int len = 0; @@ -1222,6 +1341,7 @@ static struct ibm_struct wan_driver_data = { .name = "wan", .read = wan_read, .write = wan_write, + .exit = wan_exit, .flags.experimental = 1, }; diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 7615adb381c8..a6c285585863 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -278,6 +278,8 @@ static int beep_write(char *buf); * Bluetooth subdriver */ +#define TPACPI_BLUETH_SYSFS_GROUP "bluetooth" + enum { /* ACPI GBDC/SBDC bits */ TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */ @@ -551,6 +553,8 @@ static int volume_write(char *buf); * Wan subdriver */ +#define TPACPI_WAN_SYSFS_GROUP "wwan" + enum { /* ACPI GWAN/SWAN bits */ TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */ -- cgit v1.2.3-59-g8ed1b From 836a53f42f3b5d5cb3a0751587ea33801e4b120d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 28 Apr 2007 21:19:38 +0200 Subject: thinkpad-acpi: make drivers/misc/thinkpad_acpi:fan_mutex static This patch makes the needlessly global fan_mutex static. Signed-off-by: Adrian Bunk Acked-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc/thinkpad_acpi.h') diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index a6c285585863..440145a02617 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h @@ -386,7 +386,7 @@ static u8 fan_control_initial_status; static u8 fan_control_desired_level; static int fan_watchdog_maxinterval; -struct mutex fan_mutex; +static struct mutex fan_mutex; static acpi_handle fans_handle, gfan_handle, sfan_handle; -- cgit v1.2.3-59-g8ed1b