diff options
-rw-r--r-- | Documentation/laptops/thinkpad-acpi.txt | 12 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 317 |
2 files changed, 227 insertions, 102 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 25ed43d0a21f..3d7650768bb5 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt | |||
@@ -1157,10 +1157,15 @@ display backlight brightness control methods have 16 levels, ranging | |||
1157 | from 0 to 15. | 1157 | from 0 to 15. |
1158 | 1158 | ||
1159 | There are two interfaces to the firmware for direct brightness control, | 1159 | There are two interfaces to the firmware for direct brightness control, |
1160 | EC and CMOS. To select which one should be used, use the | 1160 | EC and UCMS (or CMOS). To select which one should be used, use the |
1161 | brightness_mode module parameter: brightness_mode=1 selects EC mode, | 1161 | brightness_mode module parameter: brightness_mode=1 selects EC mode, |
1162 | brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC | 1162 | brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC |
1163 | and CMOS. The driver tries to auto-detect which interface to use. | 1163 | mode with NVRAM backing (so that brightness changes are remembered |
1164 | across shutdown/reboot). | ||
1165 | |||
1166 | The driver tries to select which interface to use from a table of | ||
1167 | defaults for each ThinkPad model. If it makes a wrong choice, please | ||
1168 | report this as a bug, so that we can fix it. | ||
1164 | 1169 | ||
1165 | When display backlight brightness controls are available through the | 1170 | When display backlight brightness controls are available through the |
1166 | standard ACPI interface, it is best to use it instead of this direct | 1171 | 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. | |||
1498 | (bluetooth, WWAN, UWB...) | 1503 | (bluetooth, WWAN, UWB...) |
1499 | 0x0008 HKEY event interface, hotkeys | 1504 | 0x0008 HKEY event interface, hotkeys |
1500 | 0x0010 Fan control | 1505 | 0x0010 Fan control |
1506 | 0x0020 Backlight brightness | ||
1501 | 1507 | ||
1502 | There is also a kernel build option to enable more debugging | 1508 | There is also a kernel build option to enable more debugging |
1503 | information, which may be necessary to debug driver problems. | 1509 | information, which may be necessary to debug driver problems. |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 4eec77032a71..ba3682c5cde0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -192,6 +192,7 @@ enum { | |||
192 | #define TPACPI_DBG_RFKILL 0x0004 | 192 | #define TPACPI_DBG_RFKILL 0x0004 |
193 | #define TPACPI_DBG_HKEY 0x0008 | 193 | #define TPACPI_DBG_HKEY 0x0008 |
194 | #define TPACPI_DBG_FAN 0x0010 | 194 | #define TPACPI_DBG_FAN 0x0010 |
195 | #define TPACPI_DBG_BRGHT 0x0020 | ||
195 | 196 | ||
196 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") | 197 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") |
197 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") | 198 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") |
@@ -274,7 +275,6 @@ static struct { | |||
274 | 275 | ||
275 | static struct { | 276 | static struct { |
276 | u16 hotkey_mask_ff:1; | 277 | u16 hotkey_mask_ff:1; |
277 | u16 bright_cmos_ec_unsync:1; | ||
278 | } tp_warned; | 278 | } tp_warned; |
279 | 279 | ||
280 | struct thinkpad_id_data { | 280 | struct thinkpad_id_data { |
@@ -5526,6 +5526,20 @@ static struct ibm_struct ecdump_driver_data = { | |||
5526 | 5526 | ||
5527 | #define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" | 5527 | #define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" |
5528 | 5528 | ||
5529 | /* | ||
5530 | * ThinkPads can read brightness from two places: EC HBRV (0x31), or | ||
5531 | * CMOS NVRAM byte 0x5E, bits 0-3. | ||
5532 | * | ||
5533 | * EC HBRV (0x31) has the following layout | ||
5534 | * Bit 7: unknown function | ||
5535 | * Bit 6: unknown function | ||
5536 | * Bit 5: Z: honour scale changes, NZ: ignore scale changes | ||
5537 | * Bit 4: must be set to zero to avoid problems | ||
5538 | * Bit 3-0: backlight brightness level | ||
5539 | * | ||
5540 | * brightness_get_raw returns status data in the HBRV layout | ||
5541 | */ | ||
5542 | |||
5529 | enum { | 5543 | enum { |
5530 | TP_EC_BACKLIGHT = 0x31, | 5544 | TP_EC_BACKLIGHT = 0x31, |
5531 | 5545 | ||
@@ -5535,108 +5549,164 @@ enum { | |||
5535 | TP_EC_BACKLIGHT_MAPSW = 0x20, | 5549 | TP_EC_BACKLIGHT_MAPSW = 0x20, |
5536 | }; | 5550 | }; |
5537 | 5551 | ||
5552 | enum tpacpi_brightness_access_mode { | ||
5553 | TPACPI_BRGHT_MODE_AUTO = 0, /* Not implemented yet */ | ||
5554 | TPACPI_BRGHT_MODE_EC, /* EC control */ | ||
5555 | TPACPI_BRGHT_MODE_UCMS_STEP, /* UCMS step-based control */ | ||
5556 | TPACPI_BRGHT_MODE_ECNVRAM, /* EC control w/ NVRAM store */ | ||
5557 | TPACPI_BRGHT_MODE_MAX | ||
5558 | }; | ||
5559 | |||
5538 | static struct backlight_device *ibm_backlight_device; | 5560 | static struct backlight_device *ibm_backlight_device; |
5539 | static int brightness_mode; | 5561 | |
5562 | static enum tpacpi_brightness_access_mode brightness_mode = | ||
5563 | TPACPI_BRGHT_MODE_MAX; | ||
5564 | |||
5540 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ | 5565 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ |
5541 | 5566 | ||
5542 | static struct mutex brightness_mutex; | 5567 | static struct mutex brightness_mutex; |
5543 | 5568 | ||
5544 | /* | 5569 | /* NVRAM brightness access, |
5545 | * ThinkPads can read brightness from two places: EC 0x31, or | 5570 | * call with brightness_mutex held! */ |
5546 | * CMOS NVRAM byte 0x5E, bits 0-3. | 5571 | static unsigned int tpacpi_brightness_nvram_get(void) |
5547 | * | ||
5548 | * EC 0x31 has the following layout | ||
5549 | * Bit 7: unknown function | ||
5550 | * Bit 6: unknown function | ||
5551 | * Bit 5: Z: honour scale changes, NZ: ignore scale changes | ||
5552 | * Bit 4: must be set to zero to avoid problems | ||
5553 | * Bit 3-0: backlight brightness level | ||
5554 | * | ||
5555 | * brightness_get_raw returns status data in the EC 0x31 layout | ||
5556 | */ | ||
5557 | static int brightness_get_raw(int *status) | ||
5558 | { | 5572 | { |
5559 | u8 lec = 0, lcmos = 0, level = 0; | 5573 | u8 lnvram; |
5560 | 5574 | ||
5561 | if (brightness_mode & 1) { | 5575 | lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) |
5562 | if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec)) | 5576 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) |
5563 | return -EIO; | 5577 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; |
5564 | level = lec & TP_EC_BACKLIGHT_LVLMSK; | 5578 | lnvram &= (tp_features.bright_16levels) ? 0x0f : 0x07; |
5565 | }; | 5579 | |
5566 | if (brightness_mode & 2) { | 5580 | return lnvram; |
5567 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) | 5581 | } |
5568 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | 5582 | |
5569 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | 5583 | static void tpacpi_brightness_checkpoint_nvram(void) |
5570 | lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; | 5584 | { |
5571 | level = lcmos; | 5585 | u8 lec = 0; |
5572 | } | 5586 | u8 b_nvram; |
5573 | 5587 | ||
5574 | if (brightness_mode == 3) { | 5588 | if (brightness_mode != TPACPI_BRGHT_MODE_ECNVRAM) |
5575 | *status = lec; /* Prefer EC, CMOS is just a backing store */ | 5589 | return; |
5576 | lec &= TP_EC_BACKLIGHT_LVLMSK; | 5590 | |
5577 | if (lec == lcmos) | 5591 | vdbg_printk(TPACPI_DBG_BRGHT, |
5578 | tp_warned.bright_cmos_ec_unsync = 0; | 5592 | "trying to checkpoint backlight level to NVRAM...\n"); |
5579 | else { | 5593 | |
5580 | if (!tp_warned.bright_cmos_ec_unsync) { | 5594 | if (mutex_lock_killable(&brightness_mutex) < 0) |
5581 | printk(TPACPI_ERR | 5595 | return; |
5582 | "CMOS NVRAM (%u) and EC (%u) do not " | 5596 | |
5583 | "agree on display brightness level\n", | 5597 | if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec))) |
5584 | (unsigned int) lcmos, | 5598 | goto unlock; |
5585 | (unsigned int) lec); | 5599 | lec &= TP_EC_BACKLIGHT_LVLMSK; |
5586 | tp_warned.bright_cmos_ec_unsync = 1; | 5600 | b_nvram = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS); |
5587 | } | 5601 | |
5602 | if (lec != ((b_nvram & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | ||
5603 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS)) { | ||
5604 | /* NVRAM needs update */ | ||
5605 | b_nvram &= ~(TP_NVRAM_MASK_LEVEL_BRIGHTNESS << | ||
5606 | TP_NVRAM_POS_LEVEL_BRIGHTNESS); | ||
5607 | b_nvram |= lec; | ||
5608 | nvram_write_byte(b_nvram, TP_NVRAM_ADDR_BRIGHTNESS); | ||
5609 | dbg_printk(TPACPI_DBG_BRGHT, | ||
5610 | "updated NVRAM backlight level to %u (0x%02x)\n", | ||
5611 | (unsigned int) lec, (unsigned int) b_nvram); | ||
5612 | } else | ||
5613 | vdbg_printk(TPACPI_DBG_BRGHT, | ||
5614 | "NVRAM backlight level already is %u (0x%02x)\n", | ||
5615 | (unsigned int) lec, (unsigned int) b_nvram); | ||
5616 | |||
5617 | unlock: | ||
5618 | mutex_unlock(&brightness_mutex); | ||
5619 | } | ||
5620 | |||
5621 | |||
5622 | /* call with brightness_mutex held! */ | ||
5623 | static int tpacpi_brightness_get_raw(int *status) | ||
5624 | { | ||
5625 | u8 lec = 0; | ||
5626 | |||
5627 | switch (brightness_mode) { | ||
5628 | case TPACPI_BRGHT_MODE_UCMS_STEP: | ||
5629 | *status = tpacpi_brightness_nvram_get(); | ||
5630 | return 0; | ||
5631 | case TPACPI_BRGHT_MODE_EC: | ||
5632 | case TPACPI_BRGHT_MODE_ECNVRAM: | ||
5633 | if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec))) | ||
5588 | return -EIO; | 5634 | return -EIO; |
5589 | } | 5635 | *status = lec; |
5590 | } else { | 5636 | return 0; |
5591 | *status = level; | 5637 | default: |
5638 | return -ENXIO; | ||
5592 | } | 5639 | } |
5640 | } | ||
5641 | |||
5642 | /* call with brightness_mutex held! */ | ||
5643 | /* do NOT call with illegal backlight level value */ | ||
5644 | static int tpacpi_brightness_set_ec(unsigned int value) | ||
5645 | { | ||
5646 | u8 lec = 0; | ||
5647 | |||
5648 | if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec))) | ||
5649 | return -EIO; | ||
5650 | |||
5651 | if (unlikely(!acpi_ec_write(TP_EC_BACKLIGHT, | ||
5652 | (lec & TP_EC_BACKLIGHT_CMDMSK) | | ||
5653 | (value & TP_EC_BACKLIGHT_LVLMSK)))) | ||
5654 | return -EIO; | ||
5655 | |||
5656 | return 0; | ||
5657 | } | ||
5658 | |||
5659 | /* call with brightness_mutex held! */ | ||
5660 | static int tpacpi_brightness_set_ucmsstep(unsigned int value) | ||
5661 | { | ||
5662 | int cmos_cmd, inc; | ||
5663 | unsigned int current_value, i; | ||
5664 | |||
5665 | current_value = tpacpi_brightness_nvram_get(); | ||
5666 | |||
5667 | if (value == current_value) | ||
5668 | return 0; | ||
5669 | |||
5670 | cmos_cmd = (value > current_value) ? | ||
5671 | TP_CMOS_BRIGHTNESS_UP : | ||
5672 | TP_CMOS_BRIGHTNESS_DOWN; | ||
5673 | inc = (value > current_value) ? 1 : -1; | ||
5674 | |||
5675 | for (i = current_value; i != value; i += inc) | ||
5676 | if (issue_thinkpad_cmos_command(cmos_cmd)) | ||
5677 | return -EIO; | ||
5593 | 5678 | ||
5594 | return 0; | 5679 | return 0; |
5595 | } | 5680 | } |
5596 | 5681 | ||
5597 | /* May return EINTR which can always be mapped to ERESTARTSYS */ | 5682 | /* May return EINTR which can always be mapped to ERESTARTSYS */ |
5598 | static int brightness_set(int value) | 5683 | static int brightness_set(unsigned int value) |
5599 | { | 5684 | { |
5600 | int cmos_cmd, inc, i, res; | 5685 | int res; |
5601 | int current_value; | ||
5602 | int command_bits; | ||
5603 | 5686 | ||
5604 | if (value > ((tp_features.bright_16levels)? 15 : 7) || | 5687 | if (value > ((tp_features.bright_16levels)? 15 : 7) || |
5605 | value < 0) | 5688 | value < 0) |
5606 | return -EINVAL; | 5689 | return -EINVAL; |
5607 | 5690 | ||
5691 | vdbg_printk(TPACPI_DBG_BRGHT, | ||
5692 | "set backlight level to %d\n", value); | ||
5693 | |||
5608 | res = mutex_lock_killable(&brightness_mutex); | 5694 | res = mutex_lock_killable(&brightness_mutex); |
5609 | if (res < 0) | 5695 | if (res < 0) |
5610 | return res; | 5696 | return res; |
5611 | 5697 | ||
5612 | res = brightness_get_raw(¤t_value); | 5698 | switch (brightness_mode) { |
5613 | if (res < 0) | 5699 | case TPACPI_BRGHT_MODE_EC: |
5614 | goto errout; | 5700 | case TPACPI_BRGHT_MODE_ECNVRAM: |
5615 | 5701 | res = tpacpi_brightness_set_ec(value); | |
5616 | command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK; | 5702 | break; |
5617 | current_value &= TP_EC_BACKLIGHT_LVLMSK; | 5703 | case TPACPI_BRGHT_MODE_UCMS_STEP: |
5618 | 5704 | res = tpacpi_brightness_set_ucmsstep(value); | |
5619 | cmos_cmd = value > current_value ? | 5705 | break; |
5620 | TP_CMOS_BRIGHTNESS_UP : | 5706 | default: |
5621 | TP_CMOS_BRIGHTNESS_DOWN; | 5707 | res = -ENXIO; |
5622 | inc = (value > current_value)? 1 : -1; | ||
5623 | |||
5624 | res = 0; | ||
5625 | for (i = current_value; i != value; i += inc) { | ||
5626 | if ((brightness_mode & 2) && | ||
5627 | issue_thinkpad_cmos_command(cmos_cmd)) { | ||
5628 | res = -EIO; | ||
5629 | goto errout; | ||
5630 | } | ||
5631 | if ((brightness_mode & 1) && | ||
5632 | !acpi_ec_write(TP_EC_BACKLIGHT, | ||
5633 | (i + inc) | command_bits)) { | ||
5634 | res = -EIO; | ||
5635 | goto errout;; | ||
5636 | } | ||
5637 | } | 5708 | } |
5638 | 5709 | ||
5639 | errout: | ||
5640 | mutex_unlock(&brightness_mutex); | 5710 | mutex_unlock(&brightness_mutex); |
5641 | return res; | 5711 | return res; |
5642 | } | 5712 | } |
@@ -5645,21 +5715,34 @@ errout: | |||
5645 | 5715 | ||
5646 | static int brightness_update_status(struct backlight_device *bd) | 5716 | static int brightness_update_status(struct backlight_device *bd) |
5647 | { | 5717 | { |
5648 | /* it is the backlight class's job (caller) to handle | 5718 | unsigned int level = |
5649 | * EINTR and other errors properly */ | ||
5650 | return brightness_set( | ||
5651 | (bd->props.fb_blank == FB_BLANK_UNBLANK && | 5719 | (bd->props.fb_blank == FB_BLANK_UNBLANK && |
5652 | bd->props.power == FB_BLANK_UNBLANK) ? | 5720 | bd->props.power == FB_BLANK_UNBLANK) ? |
5653 | bd->props.brightness : 0); | 5721 | bd->props.brightness : 0; |
5722 | |||
5723 | dbg_printk(TPACPI_DBG_BRGHT, | ||
5724 | "backlight: attempt to set level to %d\n", | ||
5725 | level); | ||
5726 | |||
5727 | /* it is the backlight class's job (caller) to handle | ||
5728 | * EINTR and other errors properly */ | ||
5729 | return brightness_set(level); | ||
5654 | } | 5730 | } |
5655 | 5731 | ||
5656 | static int brightness_get(struct backlight_device *bd) | 5732 | static int brightness_get(struct backlight_device *bd) |
5657 | { | 5733 | { |
5658 | int status, res; | 5734 | int status, res; |
5659 | 5735 | ||
5660 | res = brightness_get_raw(&status); | 5736 | res = mutex_lock_killable(&brightness_mutex); |
5661 | if (res < 0) | 5737 | if (res < 0) |
5662 | return 0; /* FIXME: teach backlight about error handling */ | 5738 | return 0; |
5739 | |||
5740 | res = tpacpi_brightness_get_raw(&status); | ||
5741 | |||
5742 | mutex_unlock(&brightness_mutex); | ||
5743 | |||
5744 | if (res < 0) | ||
5745 | return 0; | ||
5663 | 5746 | ||
5664 | return status & TP_EC_BACKLIGHT_LVLMSK; | 5747 | return status & TP_EC_BACKLIGHT_LVLMSK; |
5665 | } | 5748 | } |
@@ -5709,7 +5792,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
5709 | } | 5792 | } |
5710 | 5793 | ||
5711 | if (!brightness_enable) { | 5794 | if (!brightness_enable) { |
5712 | dbg_printk(TPACPI_DBG_INIT, | 5795 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, |
5713 | "brightness support disabled by " | 5796 | "brightness support disabled by " |
5714 | "module parameter\n"); | 5797 | "module parameter\n"); |
5715 | return 1; | 5798 | return 1; |
@@ -5724,20 +5807,38 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
5724 | if (b == 16) | 5807 | if (b == 16) |
5725 | tp_features.bright_16levels = 1; | 5808 | tp_features.bright_16levels = 1; |
5726 | 5809 | ||
5727 | if (!brightness_mode) { | 5810 | /* |
5728 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) | 5811 | * Check for module parameter bogosity, note that we |
5729 | brightness_mode = 2; | 5812 | * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be |
5730 | else | 5813 | * able to detect "unspecified" |
5731 | brightness_mode = 3; | 5814 | */ |
5815 | if (brightness_mode > TPACPI_BRGHT_MODE_MAX) | ||
5816 | return -EINVAL; | ||
5732 | 5817 | ||
5733 | dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n", | 5818 | /* TPACPI_BRGHT_MODE_AUTO not implemented yet, just use default */ |
5734 | brightness_mode); | 5819 | if (brightness_mode == TPACPI_BRGHT_MODE_AUTO || |
5735 | } | 5820 | brightness_mode == TPACPI_BRGHT_MODE_MAX) { |
5821 | if (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) { | ||
5822 | /* | ||
5823 | * IBM models that define HBRV probably have | ||
5824 | * EC-based backlight level control | ||
5825 | */ | ||
5826 | if (acpi_evalf(ec_handle, NULL, "HBRV", "qd")) | ||
5827 | /* T40-T43, R50-R52, R50e, R51e, X31-X41 */ | ||
5828 | brightness_mode = TPACPI_BRGHT_MODE_ECNVRAM; | ||
5829 | else | ||
5830 | /* all other IBM ThinkPads */ | ||
5831 | brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP; | ||
5832 | } else | ||
5833 | /* All Lenovo ThinkPads */ | ||
5834 | brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP; | ||
5736 | 5835 | ||
5737 | if (brightness_mode > 3) | 5836 | dbg_printk(TPACPI_DBG_BRGHT, |
5738 | return -EINVAL; | 5837 | "selected brightness_mode=%d\n", |
5838 | brightness_mode); | ||
5839 | } | ||
5739 | 5840 | ||
5740 | if (brightness_get_raw(&b) < 0) | 5841 | if (tpacpi_brightness_get_raw(&b) < 0) |
5741 | return 1; | 5842 | return 1; |
5742 | 5843 | ||
5743 | if (tp_features.bright_16levels) | 5844 | if (tp_features.bright_16levels) |
@@ -5751,7 +5852,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
5751 | printk(TPACPI_ERR "Could not register backlight device\n"); | 5852 | printk(TPACPI_ERR "Could not register backlight device\n"); |
5752 | return PTR_ERR(ibm_backlight_device); | 5853 | return PTR_ERR(ibm_backlight_device); |
5753 | } | 5854 | } |
5754 | vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); | 5855 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, |
5856 | "brightness is supported\n"); | ||
5755 | 5857 | ||
5756 | ibm_backlight_device->props.max_brightness = | 5858 | ibm_backlight_device->props.max_brightness = |
5757 | (tp_features.bright_16levels)? 15 : 7; | 5859 | (tp_features.bright_16levels)? 15 : 7; |
@@ -5761,13 +5863,25 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
5761 | return 0; | 5863 | return 0; |
5762 | } | 5864 | } |
5763 | 5865 | ||
5866 | static void brightness_suspend(pm_message_t state) | ||
5867 | { | ||
5868 | tpacpi_brightness_checkpoint_nvram(); | ||
5869 | } | ||
5870 | |||
5871 | static void brightness_shutdown(void) | ||
5872 | { | ||
5873 | tpacpi_brightness_checkpoint_nvram(); | ||
5874 | } | ||
5875 | |||
5764 | static void brightness_exit(void) | 5876 | static void brightness_exit(void) |
5765 | { | 5877 | { |
5766 | if (ibm_backlight_device) { | 5878 | if (ibm_backlight_device) { |
5767 | vdbg_printk(TPACPI_DBG_EXIT, | 5879 | vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_BRGHT, |
5768 | "calling backlight_device_unregister()\n"); | 5880 | "calling backlight_device_unregister()\n"); |
5769 | backlight_device_unregister(ibm_backlight_device); | 5881 | backlight_device_unregister(ibm_backlight_device); |
5770 | } | 5882 | } |
5883 | |||
5884 | tpacpi_brightness_checkpoint_nvram(); | ||
5771 | } | 5885 | } |
5772 | 5886 | ||
5773 | static int brightness_read(char *p) | 5887 | static int brightness_read(char *p) |
@@ -5814,6 +5928,9 @@ static int brightness_write(char *buf) | |||
5814 | return -EINVAL; | 5928 | return -EINVAL; |
5815 | } | 5929 | } |
5816 | 5930 | ||
5931 | tpacpi_disclose_usertask("procfs brightness", | ||
5932 | "set level to %d\n", level); | ||
5933 | |||
5817 | /* | 5934 | /* |
5818 | * Now we know what the final level should be, so we try to set it. | 5935 | * Now we know what the final level should be, so we try to set it. |
5819 | * Doing it this way makes the syscall restartable in case of EINTR | 5936 | * Doing it this way makes the syscall restartable in case of EINTR |
@@ -5827,6 +5944,8 @@ static struct ibm_struct brightness_driver_data = { | |||
5827 | .read = brightness_read, | 5944 | .read = brightness_read, |
5828 | .write = brightness_write, | 5945 | .write = brightness_write, |
5829 | .exit = brightness_exit, | 5946 | .exit = brightness_exit, |
5947 | .suspend = brightness_suspend, | ||
5948 | .shutdown = brightness_shutdown, | ||
5830 | }; | 5949 | }; |
5831 | 5950 | ||
5832 | /************************************************************************* | 5951 | /************************************************************************* |
@@ -7465,10 +7584,10 @@ module_param_named(fan_control, fan_control_allowed, bool, 0); | |||
7465 | MODULE_PARM_DESC(fan_control, | 7584 | MODULE_PARM_DESC(fan_control, |
7466 | "Enables setting fan parameters features when true"); | 7585 | "Enables setting fan parameters features when true"); |
7467 | 7586 | ||
7468 | module_param_named(brightness_mode, brightness_mode, int, 0); | 7587 | module_param_named(brightness_mode, brightness_mode, uint, 0); |
7469 | MODULE_PARM_DESC(brightness_mode, | 7588 | MODULE_PARM_DESC(brightness_mode, |
7470 | "Selects brightness control strategy: " | 7589 | "Selects brightness control strategy: " |
7471 | "0=auto, 1=EC, 2=CMOS, 3=both"); | 7590 | "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); |
7472 | 7591 | ||
7473 | module_param(brightness_enable, uint, 0); | 7592 | module_param(brightness_enable, uint, 0); |
7474 | MODULE_PARM_DESC(brightness_enable, | 7593 | MODULE_PARM_DESC(brightness_enable, |