thinkpad-acpi: rework brightness support
Refactor and redesign the brightness control backend... In order to fix bugzilla #11750... Add a new brightness control mode: support direct NVRAM checkpointing of the backlight level (i.e. store directly to NVRAM without the need for UCMS calls), and use that together with the EC-based control. Disallow UCMS+EC, thus avoiding races with the SMM firmware. Switch the models that define HBRV (EC Brightness Value) in the DSDT to the new mode. These are: T40-T43, R50-R52, R50e, R51e, X31-X41. Change the default for all other IBM ThinkPads to UCMS-only. The Lenovo models already default to UCMS-only. Reported-by: Alexey Fisher <bug-track@fisher-privat.net> Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
committed by
Len Brown
parent
74a60c0f82
commit
0e501834f8
@@ -1157,10 +1157,15 @@ display backlight brightness control methods have 16 levels, ranging
|
|||||||
from 0 to 15.
|
from 0 to 15.
|
||||||
|
|
||||||
There are two interfaces to the firmware for direct brightness control,
|
There are two interfaces to the firmware for direct brightness control,
|
||||||
EC and CMOS. To select which one should be used, use the
|
EC and UCMS (or CMOS). To select which one should be used, use the
|
||||||
brightness_mode module parameter: brightness_mode=1 selects EC mode,
|
brightness_mode module parameter: brightness_mode=1 selects EC mode,
|
||||||
brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC
|
brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC
|
||||||
and CMOS. The driver tries to auto-detect which interface to use.
|
mode with NVRAM backing (so that brightness changes are remembered
|
||||||
|
across shutdown/reboot).
|
||||||
|
|
||||||
|
The driver tries to select which interface to use from a table of
|
||||||
|
defaults for each ThinkPad model. If it makes a wrong choice, please
|
||||||
|
report this as a bug, so that we can fix it.
|
||||||
|
|
||||||
When display backlight brightness controls are available through the
|
When display backlight brightness controls are available through the
|
||||||
standard ACPI interface, it is best to use it instead of this direct
|
standard ACPI interface, it is best to use it instead of this direct
|
||||||
@@ -1498,6 +1503,7 @@ to enable more than one output class, just add their values.
|
|||||||
(bluetooth, WWAN, UWB...)
|
(bluetooth, WWAN, UWB...)
|
||||||
0x0008 HKEY event interface, hotkeys
|
0x0008 HKEY event interface, hotkeys
|
||||||
0x0010 Fan control
|
0x0010 Fan control
|
||||||
|
0x0020 Backlight brightness
|
||||||
|
|
||||||
There is also a kernel build option to enable more debugging
|
There is also a kernel build option to enable more debugging
|
||||||
information, which may be necessary to debug driver problems.
|
information, which may be necessary to debug driver problems.
|
||||||
|
@@ -192,6 +192,7 @@ enum {
|
|||||||
#define TPACPI_DBG_RFKILL 0x0004
|
#define TPACPI_DBG_RFKILL 0x0004
|
||||||
#define TPACPI_DBG_HKEY 0x0008
|
#define TPACPI_DBG_HKEY 0x0008
|
||||||
#define TPACPI_DBG_FAN 0x0010
|
#define TPACPI_DBG_FAN 0x0010
|
||||||
|
#define TPACPI_DBG_BRGHT 0x0020
|
||||||
|
|
||||||
#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off")
|
#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off")
|
||||||
#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
|
#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
|
||||||
@@ -274,7 +275,6 @@ static struct {
|
|||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
u16 hotkey_mask_ff:1;
|
u16 hotkey_mask_ff:1;
|
||||||
u16 bright_cmos_ec_unsync:1;
|
|
||||||
} tp_warned;
|
} tp_warned;
|
||||||
|
|
||||||
struct thinkpad_id_data {
|
struct thinkpad_id_data {
|
||||||
@@ -5526,6 +5526,20 @@ static struct ibm_struct ecdump_driver_data = {
|
|||||||
|
|
||||||
#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
|
#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ThinkPads can read brightness from two places: EC HBRV (0x31), or
|
||||||
|
* CMOS NVRAM byte 0x5E, bits 0-3.
|
||||||
|
*
|
||||||
|
* EC HBRV (0x31) has the following layout
|
||||||
|
* Bit 7: unknown function
|
||||||
|
* Bit 6: unknown function
|
||||||
|
* Bit 5: Z: honour scale changes, NZ: ignore scale changes
|
||||||
|
* Bit 4: must be set to zero to avoid problems
|
||||||
|
* Bit 3-0: backlight brightness level
|
||||||
|
*
|
||||||
|
* brightness_get_raw returns status data in the HBRV layout
|
||||||
|
*/
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TP_EC_BACKLIGHT = 0x31,
|
TP_EC_BACKLIGHT = 0x31,
|
||||||
|
|
||||||
@@ -5535,108 +5549,164 @@ enum {
|
|||||||
TP_EC_BACKLIGHT_MAPSW = 0x20,
|
TP_EC_BACKLIGHT_MAPSW = 0x20,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum tpacpi_brightness_access_mode {
|
||||||
|
TPACPI_BRGHT_MODE_AUTO = 0, /* Not implemented yet */
|
||||||
|
TPACPI_BRGHT_MODE_EC, /* EC control */
|
||||||
|
TPACPI_BRGHT_MODE_UCMS_STEP, /* UCMS step-based control */
|
||||||
|
TPACPI_BRGHT_MODE_ECNVRAM, /* EC control w/ NVRAM store */
|
||||||
|
TPACPI_BRGHT_MODE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
static struct backlight_device *ibm_backlight_device;
|
static struct backlight_device *ibm_backlight_device;
|
||||||
static int brightness_mode;
|
|
||||||
|
static enum tpacpi_brightness_access_mode brightness_mode =
|
||||||
|
TPACPI_BRGHT_MODE_MAX;
|
||||||
|
|
||||||
static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
|
static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
|
||||||
|
|
||||||
static struct mutex brightness_mutex;
|
static struct mutex brightness_mutex;
|
||||||
|
|
||||||
/*
|
/* NVRAM brightness access,
|
||||||
* ThinkPads can read brightness from two places: EC 0x31, or
|
* call with brightness_mutex held! */
|
||||||
* CMOS NVRAM byte 0x5E, bits 0-3.
|
static unsigned int tpacpi_brightness_nvram_get(void)
|
||||||
*
|
|
||||||
* EC 0x31 has the following layout
|
|
||||||
* Bit 7: unknown function
|
|
||||||
* Bit 6: unknown function
|
|
||||||
* Bit 5: Z: honour scale changes, NZ: ignore scale changes
|
|
||||||
* Bit 4: must be set to zero to avoid problems
|
|
||||||
* Bit 3-0: backlight brightness level
|
|
||||||
*
|
|
||||||
* brightness_get_raw returns status data in the EC 0x31 layout
|
|
||||||
*/
|
|
||||||
static int brightness_get_raw(int *status)
|
|
||||||
{
|
{
|
||||||
u8 lec = 0, lcmos = 0, level = 0;
|
u8 lnvram;
|
||||||
|
|
||||||
if (brightness_mode & 1) {
|
lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
|
||||||
if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec))
|
& TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
|
||||||
return -EIO;
|
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
|
||||||
level = lec & TP_EC_BACKLIGHT_LVLMSK;
|
lnvram &= (tp_features.bright_16levels) ? 0x0f : 0x07;
|
||||||
};
|
|
||||||
if (brightness_mode & 2) {
|
|
||||||
lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
|
|
||||||
& TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
|
|
||||||
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
|
|
||||||
lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07;
|
|
||||||
level = lcmos;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (brightness_mode == 3) {
|
return lnvram;
|
||||||
*status = lec; /* Prefer EC, CMOS is just a backing store */
|
}
|
||||||
lec &= TP_EC_BACKLIGHT_LVLMSK;
|
|
||||||
if (lec == lcmos)
|
static void tpacpi_brightness_checkpoint_nvram(void)
|
||||||
tp_warned.bright_cmos_ec_unsync = 0;
|
{
|
||||||
else {
|
u8 lec = 0;
|
||||||
if (!tp_warned.bright_cmos_ec_unsync) {
|
u8 b_nvram;
|
||||||
printk(TPACPI_ERR
|
|
||||||
"CMOS NVRAM (%u) and EC (%u) do not "
|
if (brightness_mode != TPACPI_BRGHT_MODE_ECNVRAM)
|
||||||
"agree on display brightness level\n",
|
return;
|
||||||
(unsigned int) lcmos,
|
|
||||||
(unsigned int) lec);
|
vdbg_printk(TPACPI_DBG_BRGHT,
|
||||||
tp_warned.bright_cmos_ec_unsync = 1;
|
"trying to checkpoint backlight level to NVRAM...\n");
|
||||||
}
|
|
||||||
|
if (mutex_lock_killable(&brightness_mutex) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec)))
|
||||||
|
goto unlock;
|
||||||
|
lec &= TP_EC_BACKLIGHT_LVLMSK;
|
||||||
|
b_nvram = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS);
|
||||||
|
|
||||||
|
if (lec != ((b_nvram & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
|
||||||
|
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS)) {
|
||||||
|
/* NVRAM needs update */
|
||||||
|
b_nvram &= ~(TP_NVRAM_MASK_LEVEL_BRIGHTNESS <<
|
||||||
|
TP_NVRAM_POS_LEVEL_BRIGHTNESS);
|
||||||
|
b_nvram |= lec;
|
||||||
|
nvram_write_byte(b_nvram, TP_NVRAM_ADDR_BRIGHTNESS);
|
||||||
|
dbg_printk(TPACPI_DBG_BRGHT,
|
||||||
|
"updated NVRAM backlight level to %u (0x%02x)\n",
|
||||||
|
(unsigned int) lec, (unsigned int) b_nvram);
|
||||||
|
} else
|
||||||
|
vdbg_printk(TPACPI_DBG_BRGHT,
|
||||||
|
"NVRAM backlight level already is %u (0x%02x)\n",
|
||||||
|
(unsigned int) lec, (unsigned int) b_nvram);
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&brightness_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* call with brightness_mutex held! */
|
||||||
|
static int tpacpi_brightness_get_raw(int *status)
|
||||||
|
{
|
||||||
|
u8 lec = 0;
|
||||||
|
|
||||||
|
switch (brightness_mode) {
|
||||||
|
case TPACPI_BRGHT_MODE_UCMS_STEP:
|
||||||
|
*status = tpacpi_brightness_nvram_get();
|
||||||
|
return 0;
|
||||||
|
case TPACPI_BRGHT_MODE_EC:
|
||||||
|
case TPACPI_BRGHT_MODE_ECNVRAM:
|
||||||
|
if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec)))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
*status = lec;
|
||||||
} else {
|
return 0;
|
||||||
*status = level;
|
default:
|
||||||
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call with brightness_mutex held! */
|
||||||
|
/* do NOT call with illegal backlight level value */
|
||||||
|
static int tpacpi_brightness_set_ec(unsigned int value)
|
||||||
|
{
|
||||||
|
u8 lec = 0;
|
||||||
|
|
||||||
|
if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec)))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (unlikely(!acpi_ec_write(TP_EC_BACKLIGHT,
|
||||||
|
(lec & TP_EC_BACKLIGHT_CMDMSK) |
|
||||||
|
(value & TP_EC_BACKLIGHT_LVLMSK))))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call with brightness_mutex held! */
|
||||||
|
static int tpacpi_brightness_set_ucmsstep(unsigned int value)
|
||||||
|
{
|
||||||
|
int cmos_cmd, inc;
|
||||||
|
unsigned int current_value, i;
|
||||||
|
|
||||||
|
current_value = tpacpi_brightness_nvram_get();
|
||||||
|
|
||||||
|
if (value == current_value)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
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 (issue_thinkpad_cmos_command(cmos_cmd))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* May return EINTR which can always be mapped to ERESTARTSYS */
|
/* May return EINTR which can always be mapped to ERESTARTSYS */
|
||||||
static int brightness_set(int value)
|
static int brightness_set(unsigned int value)
|
||||||
{
|
{
|
||||||
int cmos_cmd, inc, i, res;
|
int res;
|
||||||
int current_value;
|
|
||||||
int command_bits;
|
|
||||||
|
|
||||||
if (value > ((tp_features.bright_16levels)? 15 : 7) ||
|
if (value > ((tp_features.bright_16levels)? 15 : 7) ||
|
||||||
value < 0)
|
value < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
vdbg_printk(TPACPI_DBG_BRGHT,
|
||||||
|
"set backlight level to %d\n", value);
|
||||||
|
|
||||||
res = mutex_lock_killable(&brightness_mutex);
|
res = mutex_lock_killable(&brightness_mutex);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
res = brightness_get_raw(¤t_value);
|
switch (brightness_mode) {
|
||||||
if (res < 0)
|
case TPACPI_BRGHT_MODE_EC:
|
||||||
goto errout;
|
case TPACPI_BRGHT_MODE_ECNVRAM:
|
||||||
|
res = tpacpi_brightness_set_ec(value);
|
||||||
command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK;
|
break;
|
||||||
current_value &= TP_EC_BACKLIGHT_LVLMSK;
|
case TPACPI_BRGHT_MODE_UCMS_STEP:
|
||||||
|
res = tpacpi_brightness_set_ucmsstep(value);
|
||||||
cmos_cmd = value > current_value ?
|
break;
|
||||||
TP_CMOS_BRIGHTNESS_UP :
|
default:
|
||||||
TP_CMOS_BRIGHTNESS_DOWN;
|
res = -ENXIO;
|
||||||
inc = (value > current_value)? 1 : -1;
|
|
||||||
|
|
||||||
res = 0;
|
|
||||||
for (i = current_value; i != value; i += inc) {
|
|
||||||
if ((brightness_mode & 2) &&
|
|
||||||
issue_thinkpad_cmos_command(cmos_cmd)) {
|
|
||||||
res = -EIO;
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
if ((brightness_mode & 1) &&
|
|
||||||
!acpi_ec_write(TP_EC_BACKLIGHT,
|
|
||||||
(i + inc) | command_bits)) {
|
|
||||||
res = -EIO;
|
|
||||||
goto errout;;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errout:
|
|
||||||
mutex_unlock(&brightness_mutex);
|
mutex_unlock(&brightness_mutex);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -5645,21 +5715,34 @@ errout:
|
|||||||
|
|
||||||
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
|
unsigned int level =
|
||||||
* EINTR and other errors properly */
|
|
||||||
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) ?
|
||||||
bd->props.brightness : 0);
|
bd->props.brightness : 0;
|
||||||
|
|
||||||
|
dbg_printk(TPACPI_DBG_BRGHT,
|
||||||
|
"backlight: attempt to set level to %d\n",
|
||||||
|
level);
|
||||||
|
|
||||||
|
/* it is the backlight class's job (caller) to handle
|
||||||
|
* EINTR and other errors properly */
|
||||||
|
return brightness_set(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brightness_get(struct backlight_device *bd)
|
static int brightness_get(struct backlight_device *bd)
|
||||||
{
|
{
|
||||||
int status, res;
|
int status, res;
|
||||||
|
|
||||||
res = brightness_get_raw(&status);
|
res = mutex_lock_killable(&brightness_mutex);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return 0; /* FIXME: teach backlight about error handling */
|
return 0;
|
||||||
|
|
||||||
|
res = tpacpi_brightness_get_raw(&status);
|
||||||
|
|
||||||
|
mutex_unlock(&brightness_mutex);
|
||||||
|
|
||||||
|
if (res < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return status & TP_EC_BACKLIGHT_LVLMSK;
|
return status & TP_EC_BACKLIGHT_LVLMSK;
|
||||||
}
|
}
|
||||||
@@ -5709,7 +5792,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!brightness_enable) {
|
if (!brightness_enable) {
|
||||||
dbg_printk(TPACPI_DBG_INIT,
|
dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
|
||||||
"brightness support disabled by "
|
"brightness support disabled by "
|
||||||
"module parameter\n");
|
"module parameter\n");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -5724,20 +5807,38 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||||||
if (b == 16)
|
if (b == 16)
|
||||||
tp_features.bright_16levels = 1;
|
tp_features.bright_16levels = 1;
|
||||||
|
|
||||||
if (!brightness_mode) {
|
/*
|
||||||
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
|
* Check for module parameter bogosity, note that we
|
||||||
brightness_mode = 2;
|
* init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be
|
||||||
else
|
* able to detect "unspecified"
|
||||||
brightness_mode = 3;
|
*/
|
||||||
|
if (brightness_mode > TPACPI_BRGHT_MODE_MAX)
|
||||||
dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
|
|
||||||
brightness_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (brightness_mode > 3)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (brightness_get_raw(&b) < 0)
|
/* TPACPI_BRGHT_MODE_AUTO not implemented yet, just use default */
|
||||||
|
if (brightness_mode == TPACPI_BRGHT_MODE_AUTO ||
|
||||||
|
brightness_mode == TPACPI_BRGHT_MODE_MAX) {
|
||||||
|
if (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) {
|
||||||
|
/*
|
||||||
|
* IBM models that define HBRV probably have
|
||||||
|
* EC-based backlight level control
|
||||||
|
*/
|
||||||
|
if (acpi_evalf(ec_handle, NULL, "HBRV", "qd"))
|
||||||
|
/* T40-T43, R50-R52, R50e, R51e, X31-X41 */
|
||||||
|
brightness_mode = TPACPI_BRGHT_MODE_ECNVRAM;
|
||||||
|
else
|
||||||
|
/* all other IBM ThinkPads */
|
||||||
|
brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP;
|
||||||
|
} else
|
||||||
|
/* All Lenovo ThinkPads */
|
||||||
|
brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP;
|
||||||
|
|
||||||
|
dbg_printk(TPACPI_DBG_BRGHT,
|
||||||
|
"selected brightness_mode=%d\n",
|
||||||
|
brightness_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tpacpi_brightness_get_raw(&b) < 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (tp_features.bright_16levels)
|
if (tp_features.bright_16levels)
|
||||||
@@ -5751,7 +5852,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||||||
printk(TPACPI_ERR "Could not register backlight device\n");
|
printk(TPACPI_ERR "Could not register backlight device\n");
|
||||||
return PTR_ERR(ibm_backlight_device);
|
return PTR_ERR(ibm_backlight_device);
|
||||||
}
|
}
|
||||||
vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
|
vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT,
|
||||||
|
"brightness is supported\n");
|
||||||
|
|
||||||
ibm_backlight_device->props.max_brightness =
|
ibm_backlight_device->props.max_brightness =
|
||||||
(tp_features.bright_16levels)? 15 : 7;
|
(tp_features.bright_16levels)? 15 : 7;
|
||||||
@@ -5761,13 +5863,25 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void brightness_suspend(pm_message_t state)
|
||||||
|
{
|
||||||
|
tpacpi_brightness_checkpoint_nvram();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void brightness_shutdown(void)
|
||||||
|
{
|
||||||
|
tpacpi_brightness_checkpoint_nvram();
|
||||||
|
}
|
||||||
|
|
||||||
static void brightness_exit(void)
|
static void brightness_exit(void)
|
||||||
{
|
{
|
||||||
if (ibm_backlight_device) {
|
if (ibm_backlight_device) {
|
||||||
vdbg_printk(TPACPI_DBG_EXIT,
|
vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_BRGHT,
|
||||||
"calling backlight_device_unregister()\n");
|
"calling backlight_device_unregister()\n");
|
||||||
backlight_device_unregister(ibm_backlight_device);
|
backlight_device_unregister(ibm_backlight_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tpacpi_brightness_checkpoint_nvram();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brightness_read(char *p)
|
static int brightness_read(char *p)
|
||||||
@@ -5814,6 +5928,9 @@ static int brightness_write(char *buf)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tpacpi_disclose_usertask("procfs brightness",
|
||||||
|
"set level to %d\n", level);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we know what the final level should be, so we try to set it.
|
* 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
|
* Doing it this way makes the syscall restartable in case of EINTR
|
||||||
@@ -5827,6 +5944,8 @@ static struct ibm_struct brightness_driver_data = {
|
|||||||
.read = brightness_read,
|
.read = brightness_read,
|
||||||
.write = brightness_write,
|
.write = brightness_write,
|
||||||
.exit = brightness_exit,
|
.exit = brightness_exit,
|
||||||
|
.suspend = brightness_suspend,
|
||||||
|
.shutdown = brightness_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
@@ -7465,10 +7584,10 @@ module_param_named(fan_control, fan_control_allowed, bool, 0);
|
|||||||
MODULE_PARM_DESC(fan_control,
|
MODULE_PARM_DESC(fan_control,
|
||||||
"Enables setting fan parameters features when true");
|
"Enables setting fan parameters features when true");
|
||||||
|
|
||||||
module_param_named(brightness_mode, brightness_mode, int, 0);
|
module_param_named(brightness_mode, brightness_mode, uint, 0);
|
||||||
MODULE_PARM_DESC(brightness_mode,
|
MODULE_PARM_DESC(brightness_mode,
|
||||||
"Selects brightness control strategy: "
|
"Selects brightness control strategy: "
|
||||||
"0=auto, 1=EC, 2=CMOS, 3=both");
|
"0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM");
|
||||||
|
|
||||||
module_param(brightness_enable, uint, 0);
|
module_param(brightness_enable, uint, 0);
|
||||||
MODULE_PARM_DESC(brightness_enable,
|
MODULE_PARM_DESC(brightness_enable,
|
||||||
|
Reference in New Issue
Block a user