Commit d12dbbfe authored by Len Brown's avatar Len Brown

Pull thinkpad-2.6.24 into release branch

parents 614a6bbe 59f91ff1
ThinkPad ACPI Extras Driver ThinkPad ACPI Extras Driver
Version 0.16 Version 0.17
August 2nd, 2007 October 04th, 2007
Borislav Deianov <borislav@users.sf.net> Borislav Deianov <borislav@users.sf.net>
Henrique de Moraes Holschuh <hmh@hmh.eng.br> Henrique de Moraes Holschuh <hmh@hmh.eng.br>
...@@ -923,19 +923,34 @@ sysfs backlight device "thinkpad_screen" ...@@ -923,19 +923,34 @@ sysfs backlight device "thinkpad_screen"
This feature allows software control of the LCD brightness on ThinkPad This feature allows software control of the LCD brightness on ThinkPad
models which don't have a hardware brightness slider. models which don't have a hardware brightness slider.
It has some limitations: the LCD backlight cannot be actually turned on or off It has some limitations: the LCD backlight cannot be actually turned on or
by this interface, and in many ThinkPad models, the "dim while on battery" off by this interface, and in many ThinkPad models, the "dim while on
functionality will be enabled by the BIOS when this interface is used, and battery" functionality will be enabled by the BIOS when this interface is
cannot be controlled. used, and cannot be controlled.
The backlight control has eight levels, ranging from 0 to 7. Some of the On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control
levels may not be distinct. has eight brightness levels, ranging from 0 to 7. Some of the levels
may not be distinct. Later Lenovo models that implement the ACPI
There are two interfaces to the firmware for brightness control, EC and CMOS. display backlight brightness control methods have 16 levels, ranging
To select which one should be used, use the brightness_mode module parameter: from 0 to 15.
brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode,
brightness_mode=3 selects both EC and CMOS. The driver tries to autodetect There are two interfaces to the firmware for direct brightness control,
which interface to use. EC and CMOS. To select which one should be used, use the
brightness_mode module parameter: brightness_mode=1 selects EC mode,
brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC
and CMOS. The driver tries to autodetect which interface to use.
When display backlight brightness controls are available through the
standard ACPI interface, it is best to use it instead of this direct
ThinkPad-specific interface. The driver will disable its native
backlight brightness control interface if it detects that the standard
ACPI interface is available in the ThinkPad.
The brightness_enable module parameter can be used to control whether
the LCD brightness control feature will be enabled when available.
brightness_enable=0 forces it to be disabled. brightness_enable=1
forces it to be enabled when available, even if the standard ACPI
interface is also available.
Procfs notes: Procfs notes:
...@@ -947,11 +962,11 @@ Procfs notes: ...@@ -947,11 +962,11 @@ Procfs notes:
Sysfs notes: Sysfs notes:
The interface is implemented through the backlight sysfs class, which is poorly The interface is implemented through the backlight sysfs class, which is
documented at this time. poorly documented at this time.
Locate the thinkpad_screen device under /sys/class/backlight, and inside it Locate the thinkpad_screen device under /sys/class/backlight, and inside
there will be the following attributes: it there will be the following attributes:
max_brightness: max_brightness:
Reads the maximum brightness the hardware can be set to. Reads the maximum brightness the hardware can be set to.
...@@ -961,17 +976,19 @@ there will be the following attributes: ...@@ -961,17 +976,19 @@ there will be the following attributes:
Reads what brightness the screen is set to at this instant. Reads what brightness the screen is set to at this instant.
brightness: brightness:
Writes request the driver to change brightness to the given Writes request the driver to change brightness to the
value. Reads will tell you what brightness the driver is trying given value. Reads will tell you what brightness the
to set the display to when "power" is set to zero and the display driver is trying to set the display to when "power" is set
has not been dimmed by a kernel power management event. to zero and the display has not been dimmed by a kernel
power management event.
power: power:
power management mode, where 0 is "display on", and 1 to 3 will power management mode, where 0 is "display on", and 1 to 3
dim the display backlight to brightness level 0 because will dim the display backlight to brightness level 0
thinkpad-acpi cannot really turn the backlight off. Kernel because thinkpad-acpi cannot really turn the backlight
power management events can temporarily increase the current off. Kernel power management events can temporarily
power management level, i.e. they can dim the display. increase the current power management level, i.e. they can
dim the display.
Volume control -- /proc/acpi/ibm/volume Volume control -- /proc/acpi/ibm/volume
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* 02110-1301, USA. * 02110-1301, USA.
*/ */
#define IBM_VERSION "0.16" #define IBM_VERSION "0.17"
#define TPACPI_SYSFS_VERSION 0x020000 #define TPACPI_SYSFS_VERSION 0x020000
/* /*
...@@ -964,15 +964,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) ...@@ -964,15 +964,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
KEY_UNKNOWN, /* 0x0D: FN+INSERT */ KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */ KEY_UNKNOWN, /* 0x0E: FN+DELETE */
KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ KEY_RESERVED, /* 0x10: FN+END (brightness down) */
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
KEY_VOLUMEUP, /* 0x14: VOLUME UP */ KEY_RESERVED, /* 0x14: VOLUME UP */
KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */ KEY_RESERVED, /* 0x15: VOLUME DOWN */
KEY_MUTE, /* 0x16: MUTE */ KEY_RESERVED, /* 0x16: MUTE */
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
/* (assignments unknown, please report if found) */ /* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
...@@ -993,9 +993,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) ...@@ -993,9 +993,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
KEY_VOLUMEUP, /* 0x14: VOLUME UP */ KEY_RESERVED, /* 0x14: VOLUME UP */
KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */ KEY_RESERVED, /* 0x15: VOLUME DOWN */
KEY_MUTE, /* 0x16: MUTE */ KEY_RESERVED, /* 0x16: MUTE */
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
/* (assignments unknown, please report if found) */ /* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
...@@ -1342,9 +1342,8 @@ static int hotkey_read(char *p) ...@@ -1342,9 +1342,8 @@ static int hotkey_read(char *p)
return len; return len;
} }
res = mutex_lock_interruptible(&hotkey_mutex); if (mutex_lock_interruptible(&hotkey_mutex))
if (res < 0) return -ERESTARTSYS;
return res;
res = hotkey_get(&status, &mask); res = hotkey_get(&status, &mask);
mutex_unlock(&hotkey_mutex); mutex_unlock(&hotkey_mutex);
if (res) if (res)
...@@ -1373,9 +1372,8 @@ static int hotkey_write(char *buf) ...@@ -1373,9 +1372,8 @@ static int hotkey_write(char *buf)
if (!tp_features.hotkey) if (!tp_features.hotkey)
return -ENODEV; return -ENODEV;
res = mutex_lock_interruptible(&hotkey_mutex); if (mutex_lock_interruptible(&hotkey_mutex))
if (res < 0) return -ERESTARTSYS;
return res;
res = hotkey_get(&status, &mask); res = hotkey_get(&status, &mask);
if (res) if (res)
...@@ -3114,6 +3112,99 @@ static struct backlight_ops ibm_backlight_data = { ...@@ -3114,6 +3112,99 @@ static struct backlight_ops ibm_backlight_data = {
static struct mutex brightness_mutex; static struct mutex brightness_mutex;
static int __init tpacpi_query_bcll_levels(acpi_handle handle)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
int rc;
if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
obj = (union acpi_object *)buffer.pointer;
if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
printk(IBM_ERR "Unknown BCLL data, "
"please report this to %s\n", IBM_MAIL);
rc = 0;
} else {
rc = obj->package.count;
}
} else {
return 0;
}
kfree(buffer.pointer);
return rc;
}
static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
void *context, void **rv)
{
char name[ACPI_PATH_SEGMENT_LENGTH];
struct acpi_buffer buffer = { sizeof(name), &name };
if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
!strncmp("BCLL", name, sizeof(name) - 1)) {
if (tpacpi_query_bcll_levels(handle) == 16) {
*rv = handle;
return AE_CTRL_TERMINATE;
} else {
return AE_OK;
}
} else {
return AE_OK;
}
}
static int __init brightness_check_levels(void)
{
int status;
void *found_node = NULL;
if (!vid_handle) {
IBM_ACPIHANDLE_INIT(vid);
}
if (!vid_handle)
return 0;
/* Search for a BCLL package with 16 levels */
status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
brightness_find_bcll, NULL, &found_node);
return (ACPI_SUCCESS(status) && found_node != NULL);
}
static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
void *context, void **rv)
{
char name[ACPI_PATH_SEGMENT_LENGTH];
struct acpi_buffer buffer = { sizeof(name), &name };
if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
!strncmp("_BCL", name, sizeof(name) - 1)) {
*rv = handle;
return AE_CTRL_TERMINATE;
} else {
return AE_OK;
}
}
static int __init brightness_check_std_acpi_support(void)
{
int status;
void *found_node = NULL;
if (!vid_handle) {
IBM_ACPIHANDLE_INIT(vid);
}
if (!vid_handle)
return 0;
/* Search for a _BCL method, but don't execute it */
status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
brightness_find_bcl, NULL, &found_node);
return (ACPI_SUCCESS(status) && found_node != NULL);
}
static int __init brightness_init(struct ibm_init_struct *iibm) static int __init brightness_init(struct ibm_init_struct *iibm)
{ {
int b; int b;
...@@ -3122,6 +3213,18 @@ static int __init brightness_init(struct ibm_init_struct *iibm) ...@@ -3122,6 +3213,18 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
mutex_init(&brightness_mutex); mutex_init(&brightness_mutex);
if (!brightness_enable) {
dbg_printk(TPACPI_DBG_INIT,
"brightness support disabled by module parameter\n");
return 1;
} else if (brightness_enable > 1) {
if (brightness_check_std_acpi_support()) {
printk(IBM_NOTICE
"standard ACPI backlight interface available, not loading native one...\n");
return 1;
}
}
if (!brightness_mode) { if (!brightness_mode) {
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
brightness_mode = 2; brightness_mode = 2;
...@@ -3135,10 +3238,17 @@ static int __init brightness_init(struct ibm_init_struct *iibm) ...@@ -3135,10 +3238,17 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
if (brightness_mode > 3) if (brightness_mode > 3)
return -EINVAL; return -EINVAL;
tp_features.bright_16levels =
thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
brightness_check_levels();
b = brightness_get(NULL); b = brightness_get(NULL);
if (b < 0) if (b < 0)
return 1; return 1;
if (tp_features.bright_16levels)
printk(IBM_INFO "detected a 16-level brightness capable ThinkPad\n");
ibm_backlight_device = backlight_device_register( ibm_backlight_device = backlight_device_register(
TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
&ibm_backlight_data); &ibm_backlight_data);
...@@ -3148,7 +3258,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm) ...@@ -3148,7 +3258,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
} }
vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
ibm_backlight_device->props.max_brightness = 7; ibm_backlight_device->props.max_brightness =
(tp_features.bright_16levels)? 15 : 7;
ibm_backlight_device->props.brightness = b; ibm_backlight_device->props.brightness = b;
backlight_update_status(ibm_backlight_device); backlight_update_status(ibm_backlight_device);
...@@ -3167,6 +3278,8 @@ static void brightness_exit(void) ...@@ -3167,6 +3278,8 @@ static void brightness_exit(void)
static int brightness_update_status(struct backlight_device *bd) static int brightness_update_status(struct backlight_device *bd)
{ {
/* it is the backlight class's job (caller) to handle
* EINTR and other errors properly */
return brightness_set( return brightness_set(
(bd->props.fb_blank == FB_BLANK_UNBLANK && (bd->props.fb_blank == FB_BLANK_UNBLANK &&
bd->props.power == FB_BLANK_UNBLANK) ? bd->props.power == FB_BLANK_UNBLANK) ?
...@@ -3184,13 +3297,14 @@ static int brightness_get(struct backlight_device *bd) ...@@ -3184,13 +3297,14 @@ static int brightness_get(struct backlight_device *bd)
if (brightness_mode & 1) { if (brightness_mode & 1) {
if (!acpi_ec_read(brightness_offset, &lec)) if (!acpi_ec_read(brightness_offset, &lec))
return -EIO; return -EIO;
lec &= 7; lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
level = lec; level = lec;
}; };
if (brightness_mode & 2) { if (brightness_mode & 2) {
lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
& TP_NVRAM_MASK_LEVEL_BRIGHTNESS) & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS; >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
level = lcmos; level = lcmos;
} }
...@@ -3206,12 +3320,13 @@ static int brightness_get(struct backlight_device *bd) ...@@ -3206,12 +3320,13 @@ static int brightness_get(struct backlight_device *bd)
return level; return level;
} }
/* May return EINTR which can always be mapped to ERESTARTSYS */
static int brightness_set(int value) static int brightness_set(int value)
{ {
int cmos_cmd, inc, i, res; int cmos_cmd, inc, i, res;
int current_value; int current_value;
if (value > 7) if (value > ((tp_features.bright_16levels)? 15 : 7))
return -EINVAL; return -EINVAL;
res = mutex_lock_interruptible(&brightness_mutex); res = mutex_lock_interruptible(&brightness_mutex);
...@@ -3227,7 +3342,7 @@ static int brightness_set(int value) ...@@ -3227,7 +3342,7 @@ static int brightness_set(int value)
cmos_cmd = value > current_value ? cmos_cmd = value > current_value ?
TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_UP :
TP_CMOS_BRIGHTNESS_DOWN; TP_CMOS_BRIGHTNESS_DOWN;
inc = value > current_value ? 1 : -1; inc = (value > current_value)? 1 : -1;
res = 0; res = 0;
for (i = current_value; i != value; i += inc) { for (i = current_value; i != value; i += inc) {
...@@ -3256,10 +3371,11 @@ static int brightness_read(char *p) ...@@ -3256,10 +3371,11 @@ static int brightness_read(char *p)
if ((level = brightness_get(NULL)) < 0) { if ((level = brightness_get(NULL)) < 0) {
len += sprintf(p + len, "level:\t\tunreadable\n"); len += sprintf(p + len, "level:\t\tunreadable\n");
} else { } else {
len += sprintf(p + len, "level:\t\t%d\n", level & 0x7); len += sprintf(p + len, "level:\t\t%d\n", level);
len += sprintf(p + len, "commands:\tup, down\n"); len += sprintf(p + len, "commands:\tup, down\n");
len += sprintf(p + len, "commands:\tlevel <level>" len += sprintf(p + len, "commands:\tlevel <level>"
" (<level> is 0-7)\n"); " (<level> is 0-%d)\n",
(tp_features.bright_16levels) ? 15 : 7);
} }
return len; return len;
...@@ -3268,28 +3384,34 @@ static int brightness_read(char *p) ...@@ -3268,28 +3384,34 @@ static int brightness_read(char *p)
static int brightness_write(char *buf) static int brightness_write(char *buf)
{ {
int level; int level;
int new_level; int rc;
char *cmd; char *cmd;
int max_level = (tp_features.bright_16levels) ? 15 : 7;
while ((cmd = next_cmd(&buf))) { level = brightness_get(NULL);
if ((level = brightness_get(NULL)) < 0) if (level < 0)
return level; return level;
level &= 7;
while ((cmd = next_cmd(&buf))) {
if (strlencmp(cmd, "up") == 0) { if (strlencmp(cmd, "up") == 0) {
new_level = level == 7 ? 7 : level + 1; if (level < max_level)
level++;
} else if (strlencmp(cmd, "down") == 0) { } else if (strlencmp(cmd, "down") == 0) {
new_level = level == 0 ? 0 : level - 1; if (level > 0)
} else if (sscanf(cmd, "level %d", &new_level) == 1 && level--;
new_level >= 0 && new_level <= 7) { } else if (sscanf(cmd, "level %d", &level) == 1 &&
/* new_level set */ level >= 0 && level <= max_level) {
/* new level set */
} else } else
return -EINVAL; return -EINVAL;
brightness_set(new_level);
} }
return 0; /*
* Now we know what the final level should be, so we try to set it.
* Doing it this way makes the syscall restartable in case of EINTR
*/
rc = brightness_set(level);
return (rc == -EINTR)? ERESTARTSYS : rc;
} }
static struct ibm_struct brightness_driver_data = { static struct ibm_struct brightness_driver_data = {
...@@ -3652,9 +3774,8 @@ static ssize_t fan_pwm1_store(struct device *dev, ...@@ -3652,9 +3774,8 @@ static ssize_t fan_pwm1_store(struct device *dev,
/* scale down from 0-255 to 0-7 */ /* scale down from 0-255 to 0-7 */
newlevel = (s >> 5) & 0x07; newlevel = (s >> 5) & 0x07;
rc = mutex_lock_interruptible(&fan_mutex); if (mutex_lock_interruptible(&fan_mutex))
if (rc < 0) return -ERESTARTSYS;
return rc;
rc = fan_get_status(&status); rc = fan_get_status(&status);
if (!rc && (status & if (!rc && (status &
...@@ -3904,9 +4025,8 @@ static int fan_get_status_safe(u8 *status) ...@@ -3904,9 +4025,8 @@ static int fan_get_status_safe(u8 *status)
int rc; int rc;
u8 s; u8 s;
rc = mutex_lock_interruptible(&fan_mutex); if (mutex_lock_interruptible(&fan_mutex))
if (rc < 0) return -ERESTARTSYS;
return rc;
rc = fan_get_status(&s); rc = fan_get_status(&s);
if (!rc) if (!rc)
fan_update_desired_level(s); fan_update_desired_level(s);
...@@ -4040,9 +4160,8 @@ static int fan_set_level_safe(int level) ...@@ -4040,9 +4160,8 @@ static int fan_set_level_safe(int level)
if (!fan_control_allowed) if (!fan_control_allowed)
return -EPERM; return -EPERM;
rc = mutex_lock_interruptible(&fan_mutex); if (mutex_lock_interruptible(&fan_mutex))
if (rc < 0) return -ERESTARTSYS;
return rc;
if (level == TPACPI_FAN_LAST_LEVEL) if (level == TPACPI_FAN_LAST_LEVEL)
level = fan_control_desired_level; level = fan_control_desired_level;
...@@ -4063,9 +4182,8 @@ static int fan_set_enable(void) ...@@ -4063,9 +4182,8 @@ static int fan_set_enable(void)
if (!fan_control_allowed) if (!fan_control_allowed)
return -EPERM; return -EPERM;
rc = mutex_lock_interruptible(&fan_mutex); if (mutex_lock_interruptible(&fan_mutex))
if (rc < 0) return -ERESTARTSYS;
return rc;
switch (fan_control_access_mode) { switch (fan_control_access_mode) {
case TPACPI_FAN_WR_ACPI_FANS: case TPACPI_FAN_WR_ACPI_FANS:
...@@ -4119,9 +4237,8 @@ static int fan_set_disable(void) ...@@ -4119,9 +4237,8 @@ static int fan_set_disable(void)
if (!fan_control_allowed) if (!fan_control_allowed)
return -EPERM; return -EPERM;
rc = mutex_lock_interruptible(&fan_mutex); if (mutex_lock_interruptible(&fan_mutex))
if (rc < 0) return -ERESTARTSYS;
return rc;
rc = 0; rc = 0;
switch (fan_control_access_mode) { switch (fan_control_access_mode) {
...@@ -4158,9 +4275,8 @@ static int fan_set_speed(int speed) ...@@ -4158,9 +4275,8 @@ static int fan_set_speed(int speed)
if (!fan_control_allowed) if (!fan_control_allowed)
return -EPERM; return -EPERM;
rc = mutex_lock_interruptible(&fan_mutex); if (mutex_lock_interruptible(&fan_mutex))
if (rc < 0) return -ERESTARTSYS;
return rc;
rc = 0; rc = 0;
switch (fan_control_access_mode) { switch (fan_control_access_mode) {
...@@ -4701,9 +4817,15 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp) ...@@ -4701,9 +4817,15 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp)
unsigned int i; unsigned int i;
struct ibm_struct *ibm; struct ibm_struct *ibm;
if (!kp || !kp->name || !val)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
ibm = ibms_init[i].data; ibm = ibms_init[i].data;
BUG_ON(ibm == NULL); WARN_ON(ibm == NULL);
if (!ibm || !ibm->name)
continue;
if (strcmp(ibm->name, kp->name) == 0 && ibm->write) { if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
if (strlen(val) > sizeof(ibms_init[i].param) - 2) if (strlen(val) > sizeof(ibms_init[i].param) - 2)
...@@ -4732,6 +4854,9 @@ module_param_named(fan_control, fan_control_allowed, bool, 0); ...@@ -4732,6 +4854,9 @@ module_param_named(fan_control, fan_control_allowed, bool, 0);
static int brightness_mode; static int brightness_mode;
module_param_named(brightness_mode, brightness_mode, int, 0); module_param_named(brightness_mode, brightness_mode, int, 0);
static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
module_param(brightness_enable, uint, 0);
static unsigned int hotkey_report_mode; static unsigned int hotkey_report_mode;
module_param(hotkey_report_mode, uint, 0); module_param(hotkey_report_mode, uint, 0);
......
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
/* ThinkPad CMOS NVRAM constants */ /* ThinkPad CMOS NVRAM constants */
#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e #define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07 #define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x0f
#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0 #define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
...@@ -246,6 +246,7 @@ static struct { ...@@ -246,6 +246,7 @@ static struct {
u32 hotkey_wlsw:1; u32 hotkey_wlsw:1;
u32 light:1; u32 light:1;
u32 light_status:1; u32 light_status:1;
u32 bright_16levels:1;
u32 wan:1; u32 wan:1;
u32 fan_ctrl_status_undef:1; u32 fan_ctrl_status_undef:1;
u32 input_device_registered:1; u32 input_device_registered:1;
...@@ -338,6 +339,7 @@ static int bluetooth_write(char *buf); ...@@ -338,6 +339,7 @@ static int bluetooth_write(char *buf);
static struct backlight_device *ibm_backlight_device; static struct backlight_device *ibm_backlight_device;
static int brightness_offset = 0x31; static int brightness_offset = 0x31;
static int brightness_mode; static int brightness_mode;
static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */
static int brightness_init(struct ibm_init_struct *iibm); static int brightness_init(struct ibm_init_struct *iibm);
static void brightness_exit(void); static void brightness_exit(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment