diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /Documentation/laptops | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'Documentation/laptops')
-rw-r--r-- | Documentation/laptops/00-INDEX | 6 | ||||
-rw-r--r-- | Documentation/laptops/Makefile | 8 | ||||
-rw-r--r-- | Documentation/laptops/dslm.c | 166 | ||||
-rw-r--r-- | Documentation/laptops/laptop-mode.txt | 170 | ||||
-rw-r--r-- | Documentation/laptops/thinkpad-acpi.txt | 164 |
5 files changed, 293 insertions, 221 deletions
diff --git a/Documentation/laptops/00-INDEX b/Documentation/laptops/00-INDEX index ee5692b26dd4..fa688538e757 100644 --- a/Documentation/laptops/00-INDEX +++ b/Documentation/laptops/00-INDEX | |||
@@ -2,6 +2,12 @@ | |||
2 | - This file | 2 | - This file |
3 | acer-wmi.txt | 3 | acer-wmi.txt |
4 | - information on the Acer Laptop WMI Extras driver. | 4 | - information on the Acer Laptop WMI Extras driver. |
5 | asus-laptop.txt | ||
6 | - information on the Asus Laptop Extras driver. | ||
7 | disk-shock-protection.txt | ||
8 | - information on hard disk shock protection. | ||
9 | dslm.c | ||
10 | - Simple Disk Sleep Monitor program | ||
5 | laptop-mode.txt | 11 | laptop-mode.txt |
6 | - how to conserve battery power using laptop-mode. | 12 | - how to conserve battery power using laptop-mode. |
7 | sony-laptop.txt | 13 | sony-laptop.txt |
diff --git a/Documentation/laptops/Makefile b/Documentation/laptops/Makefile new file mode 100644 index 000000000000..5cb144af3c09 --- /dev/null +++ b/Documentation/laptops/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # kbuild trick to avoid linker error. Can be omitted if a module is built. | ||
2 | obj- := dummy.o | ||
3 | |||
4 | # List of programs to build | ||
5 | hostprogs-y := dslm | ||
6 | |||
7 | # Tell kbuild to always build the programs | ||
8 | always := $(hostprogs-y) | ||
diff --git a/Documentation/laptops/dslm.c b/Documentation/laptops/dslm.c new file mode 100644 index 000000000000..72ff290c5fc6 --- /dev/null +++ b/Documentation/laptops/dslm.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * dslm.c | ||
3 | * Simple Disk Sleep Monitor | ||
4 | * by Bartek Kania | ||
5 | * Licenced under the GPL | ||
6 | */ | ||
7 | #include <unistd.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <stdio.h> | ||
10 | #include <fcntl.h> | ||
11 | #include <errno.h> | ||
12 | #include <time.h> | ||
13 | #include <string.h> | ||
14 | #include <signal.h> | ||
15 | #include <sys/ioctl.h> | ||
16 | #include <linux/hdreg.h> | ||
17 | |||
18 | #ifdef DEBUG | ||
19 | #define D(x) x | ||
20 | #else | ||
21 | #define D(x) | ||
22 | #endif | ||
23 | |||
24 | int endit = 0; | ||
25 | |||
26 | /* Check if the disk is in powersave-mode | ||
27 | * Most of the code is stolen from hdparm. | ||
28 | * 1 = active, 0 = standby/sleep, -1 = unknown */ | ||
29 | static int check_powermode(int fd) | ||
30 | { | ||
31 | unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0}; | ||
32 | int state; | ||
33 | |||
34 | if (ioctl(fd, HDIO_DRIVE_CMD, &args) | ||
35 | && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */ | ||
36 | && ioctl(fd, HDIO_DRIVE_CMD, &args)) { | ||
37 | if (errno != EIO || args[0] != 0 || args[1] != 0) { | ||
38 | state = -1; /* "unknown"; */ | ||
39 | } else | ||
40 | state = 0; /* "sleeping"; */ | ||
41 | } else { | ||
42 | state = (args[2] == 255) ? 1 : 0; | ||
43 | } | ||
44 | D(printf(" drive state is: %d\n", state)); | ||
45 | |||
46 | return state; | ||
47 | } | ||
48 | |||
49 | static char *state_name(int i) | ||
50 | { | ||
51 | if (i == -1) return "unknown"; | ||
52 | if (i == 0) return "sleeping"; | ||
53 | if (i == 1) return "active"; | ||
54 | |||
55 | return "internal error"; | ||
56 | } | ||
57 | |||
58 | static char *myctime(time_t time) | ||
59 | { | ||
60 | char *ts = ctime(&time); | ||
61 | ts[strlen(ts) - 1] = 0; | ||
62 | |||
63 | return ts; | ||
64 | } | ||
65 | |||
66 | static void measure(int fd) | ||
67 | { | ||
68 | time_t start_time; | ||
69 | int last_state; | ||
70 | time_t last_time; | ||
71 | int curr_state; | ||
72 | time_t curr_time = 0; | ||
73 | time_t time_diff; | ||
74 | time_t active_time = 0; | ||
75 | time_t sleep_time = 0; | ||
76 | time_t unknown_time = 0; | ||
77 | time_t total_time = 0; | ||
78 | int changes = 0; | ||
79 | float tmp; | ||
80 | |||
81 | printf("Starting measurements\n"); | ||
82 | |||
83 | last_state = check_powermode(fd); | ||
84 | start_time = last_time = time(0); | ||
85 | printf(" System is in state %s\n\n", state_name(last_state)); | ||
86 | |||
87 | while(!endit) { | ||
88 | sleep(1); | ||
89 | curr_state = check_powermode(fd); | ||
90 | |||
91 | if (curr_state != last_state || endit) { | ||
92 | changes++; | ||
93 | curr_time = time(0); | ||
94 | time_diff = curr_time - last_time; | ||
95 | |||
96 | if (last_state == 1) active_time += time_diff; | ||
97 | else if (last_state == 0) sleep_time += time_diff; | ||
98 | else unknown_time += time_diff; | ||
99 | |||
100 | last_state = curr_state; | ||
101 | last_time = curr_time; | ||
102 | |||
103 | printf("%s: State-change to %s\n", myctime(curr_time), | ||
104 | state_name(curr_state)); | ||
105 | } | ||
106 | } | ||
107 | changes--; /* Compensate for SIGINT */ | ||
108 | |||
109 | total_time = time(0) - start_time; | ||
110 | printf("\nTotal running time: %lus\n", curr_time - start_time); | ||
111 | printf(" State changed %d times\n", changes); | ||
112 | |||
113 | tmp = (float)sleep_time / (float)total_time * 100; | ||
114 | printf(" Time in sleep state: %lus (%.2f%%)\n", sleep_time, tmp); | ||
115 | tmp = (float)active_time / (float)total_time * 100; | ||
116 | printf(" Time in active state: %lus (%.2f%%)\n", active_time, tmp); | ||
117 | tmp = (float)unknown_time / (float)total_time * 100; | ||
118 | printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp); | ||
119 | } | ||
120 | |||
121 | static void ender(int s) | ||
122 | { | ||
123 | endit = 1; | ||
124 | } | ||
125 | |||
126 | static void usage(void) | ||
127 | { | ||
128 | puts("usage: dslm [-w <time>] <disk>"); | ||
129 | exit(0); | ||
130 | } | ||
131 | |||
132 | int main(int argc, char **argv) | ||
133 | { | ||
134 | int fd; | ||
135 | char *disk = 0; | ||
136 | int settle_time = 60; | ||
137 | |||
138 | /* Parse the simple command-line */ | ||
139 | if (argc == 2) | ||
140 | disk = argv[1]; | ||
141 | else if (argc == 4) { | ||
142 | settle_time = atoi(argv[2]); | ||
143 | disk = argv[3]; | ||
144 | } else | ||
145 | usage(); | ||
146 | |||
147 | if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) { | ||
148 | printf("Can't open %s, because: %s\n", disk, strerror(errno)); | ||
149 | exit(-1); | ||
150 | } | ||
151 | |||
152 | if (settle_time) { | ||
153 | printf("Waiting %d seconds for the system to settle down to " | ||
154 | "'normal'\n", settle_time); | ||
155 | sleep(settle_time); | ||
156 | } else | ||
157 | puts("Not waiting for system to settle down"); | ||
158 | |||
159 | signal(SIGINT, ender); | ||
160 | |||
161 | measure(fd); | ||
162 | |||
163 | close(fd); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
diff --git a/Documentation/laptops/laptop-mode.txt b/Documentation/laptops/laptop-mode.txt index eeedee11c8c2..2c3c35093023 100644 --- a/Documentation/laptops/laptop-mode.txt +++ b/Documentation/laptops/laptop-mode.txt | |||
@@ -779,172 +779,4 @@ Monitoring tool | |||
779 | --------------- | 779 | --------------- |
780 | 780 | ||
781 | Bartek Kania submitted this, it can be used to measure how much time your disk | 781 | Bartek Kania submitted this, it can be used to measure how much time your disk |
782 | spends spun up/down. | 782 | spends spun up/down. See Documentation/laptops/dslm.c |
783 | |||
784 | ---------------------------dslm.c BEGIN----------------------------------------- | ||
785 | /* | ||
786 | * Simple Disk Sleep Monitor | ||
787 | * by Bartek Kania | ||
788 | * Licenced under the GPL | ||
789 | */ | ||
790 | #include <unistd.h> | ||
791 | #include <stdlib.h> | ||
792 | #include <stdio.h> | ||
793 | #include <fcntl.h> | ||
794 | #include <errno.h> | ||
795 | #include <time.h> | ||
796 | #include <string.h> | ||
797 | #include <signal.h> | ||
798 | #include <sys/ioctl.h> | ||
799 | #include <linux/hdreg.h> | ||
800 | |||
801 | #ifdef DEBUG | ||
802 | #define D(x) x | ||
803 | #else | ||
804 | #define D(x) | ||
805 | #endif | ||
806 | |||
807 | int endit = 0; | ||
808 | |||
809 | /* Check if the disk is in powersave-mode | ||
810 | * Most of the code is stolen from hdparm. | ||
811 | * 1 = active, 0 = standby/sleep, -1 = unknown */ | ||
812 | int check_powermode(int fd) | ||
813 | { | ||
814 | unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0}; | ||
815 | int state; | ||
816 | |||
817 | if (ioctl(fd, HDIO_DRIVE_CMD, &args) | ||
818 | && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */ | ||
819 | && ioctl(fd, HDIO_DRIVE_CMD, &args)) { | ||
820 | if (errno != EIO || args[0] != 0 || args[1] != 0) { | ||
821 | state = -1; /* "unknown"; */ | ||
822 | } else | ||
823 | state = 0; /* "sleeping"; */ | ||
824 | } else { | ||
825 | state = (args[2] == 255) ? 1 : 0; | ||
826 | } | ||
827 | D(printf(" drive state is: %d\n", state)); | ||
828 | |||
829 | return state; | ||
830 | } | ||
831 | |||
832 | char *state_name(int i) | ||
833 | { | ||
834 | if (i == -1) return "unknown"; | ||
835 | if (i == 0) return "sleeping"; | ||
836 | if (i == 1) return "active"; | ||
837 | |||
838 | return "internal error"; | ||
839 | } | ||
840 | |||
841 | char *myctime(time_t time) | ||
842 | { | ||
843 | char *ts = ctime(&time); | ||
844 | ts[strlen(ts) - 1] = 0; | ||
845 | |||
846 | return ts; | ||
847 | } | ||
848 | |||
849 | void measure(int fd) | ||
850 | { | ||
851 | time_t start_time; | ||
852 | int last_state; | ||
853 | time_t last_time; | ||
854 | int curr_state; | ||
855 | time_t curr_time = 0; | ||
856 | time_t time_diff; | ||
857 | time_t active_time = 0; | ||
858 | time_t sleep_time = 0; | ||
859 | time_t unknown_time = 0; | ||
860 | time_t total_time = 0; | ||
861 | int changes = 0; | ||
862 | float tmp; | ||
863 | |||
864 | printf("Starting measurements\n"); | ||
865 | |||
866 | last_state = check_powermode(fd); | ||
867 | start_time = last_time = time(0); | ||
868 | printf(" System is in state %s\n\n", state_name(last_state)); | ||
869 | |||
870 | while(!endit) { | ||
871 | sleep(1); | ||
872 | curr_state = check_powermode(fd); | ||
873 | |||
874 | if (curr_state != last_state || endit) { | ||
875 | changes++; | ||
876 | curr_time = time(0); | ||
877 | time_diff = curr_time - last_time; | ||
878 | |||
879 | if (last_state == 1) active_time += time_diff; | ||
880 | else if (last_state == 0) sleep_time += time_diff; | ||
881 | else unknown_time += time_diff; | ||
882 | |||
883 | last_state = curr_state; | ||
884 | last_time = curr_time; | ||
885 | |||
886 | printf("%s: State-change to %s\n", myctime(curr_time), | ||
887 | state_name(curr_state)); | ||
888 | } | ||
889 | } | ||
890 | changes--; /* Compensate for SIGINT */ | ||
891 | |||
892 | total_time = time(0) - start_time; | ||
893 | printf("\nTotal running time: %lus\n", curr_time - start_time); | ||
894 | printf(" State changed %d times\n", changes); | ||
895 | |||
896 | tmp = (float)sleep_time / (float)total_time * 100; | ||
897 | printf(" Time in sleep state: %lus (%.2f%%)\n", sleep_time, tmp); | ||
898 | tmp = (float)active_time / (float)total_time * 100; | ||
899 | printf(" Time in active state: %lus (%.2f%%)\n", active_time, tmp); | ||
900 | tmp = (float)unknown_time / (float)total_time * 100; | ||
901 | printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp); | ||
902 | } | ||
903 | |||
904 | void ender(int s) | ||
905 | { | ||
906 | endit = 1; | ||
907 | } | ||
908 | |||
909 | void usage() | ||
910 | { | ||
911 | puts("usage: dslm [-w <time>] <disk>"); | ||
912 | exit(0); | ||
913 | } | ||
914 | |||
915 | int main(int argc, char **argv) | ||
916 | { | ||
917 | int fd; | ||
918 | char *disk = 0; | ||
919 | int settle_time = 60; | ||
920 | |||
921 | /* Parse the simple command-line */ | ||
922 | if (argc == 2) | ||
923 | disk = argv[1]; | ||
924 | else if (argc == 4) { | ||
925 | settle_time = atoi(argv[2]); | ||
926 | disk = argv[3]; | ||
927 | } else | ||
928 | usage(); | ||
929 | |||
930 | if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) { | ||
931 | printf("Can't open %s, because: %s\n", disk, strerror(errno)); | ||
932 | exit(-1); | ||
933 | } | ||
934 | |||
935 | if (settle_time) { | ||
936 | printf("Waiting %d seconds for the system to settle down to " | ||
937 | "'normal'\n", settle_time); | ||
938 | sleep(settle_time); | ||
939 | } else | ||
940 | puts("Not waiting for system to settle down"); | ||
941 | |||
942 | signal(SIGINT, ender); | ||
943 | |||
944 | measure(fd); | ||
945 | |||
946 | close(fd); | ||
947 | |||
948 | return 0; | ||
949 | } | ||
950 | ---------------------------dslm.c END------------------------------------------- | ||
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index aafcaa634191..39c0a09d0105 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt | |||
@@ -1,7 +1,7 @@ | |||
1 | ThinkPad ACPI Extras Driver | 1 | ThinkPad ACPI Extras Driver |
2 | 2 | ||
3 | Version 0.23 | 3 | Version 0.24 |
4 | April 10th, 2009 | 4 | December 11th, 2009 |
5 | 5 | ||
6 | Borislav Deianov <borislav@users.sf.net> | 6 | Borislav Deianov <borislav@users.sf.net> |
7 | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 7 | Henrique de Moraes Holschuh <hmh@hmh.eng.br> |
@@ -460,6 +460,8 @@ event code Key Notes | |||
460 | For Lenovo ThinkPads with a new | 460 | For Lenovo ThinkPads with a new |
461 | BIOS, it has to be handled either | 461 | BIOS, it has to be handled either |
462 | by the ACPI OSI, or by userspace. | 462 | by the ACPI OSI, or by userspace. |
463 | The driver does the right thing, | ||
464 | never mess with this. | ||
463 | 0x1011 0x10 FN+END Brightness down. See brightness | 465 | 0x1011 0x10 FN+END Brightness down. See brightness |
464 | up for details. | 466 | up for details. |
465 | 467 | ||
@@ -582,46 +584,15 @@ with hotkey_report_mode. | |||
582 | 584 | ||
583 | Brightness hotkey notes: | 585 | Brightness hotkey notes: |
584 | 586 | ||
585 | These are the current sane choices for brightness key mapping in | 587 | Don't mess with the brightness hotkeys in a Thinkpad. If you want |
586 | thinkpad-acpi: | 588 | notifications for OSD, use the sysfs backlight class event support. |
587 | 589 | ||
588 | For IBM and Lenovo models *without* ACPI backlight control (the ones on | 590 | The driver will issue KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN events |
589 | which thinkpad-acpi will autoload its backlight interface by default, | 591 | automatically for the cases were userspace has to do something to |
590 | and on which ACPI video does not export a backlight interface): | 592 | implement brightness changes. When you override these events, you will |
591 | 593 | either fail to handle properly the ThinkPads that require explicit | |
592 | 1. Don't enable or map the brightness hotkeys in thinkpad-acpi, as | 594 | action to change backlight brightness, or the ThinkPads that require |
593 | these older firmware versions unfortunately won't respect the hotkey | 595 | that no action be taken to work properly. |
594 | mask for brightness keys anyway, and always reacts to them. This | ||
595 | usually work fine, unless X.org drivers are doing something to block | ||
596 | the BIOS. In that case, use (3) below. This is the default mode of | ||
597 | operation. | ||
598 | |||
599 | 2. Enable the hotkeys, but map them to something else that is NOT | ||
600 | KEY_BRIGHTNESS_UP/DOWN or any other keycode that would cause | ||
601 | userspace to try to change the backlight level, and use that as an | ||
602 | on-screen-display hint. | ||
603 | |||
604 | 3. IF AND ONLY IF X.org drivers find a way to block the firmware from | ||
605 | automatically changing the brightness, enable the hotkeys and map | ||
606 | them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN, and feed that to | ||
607 | something that calls xbacklight. thinkpad-acpi will not be able to | ||
608 | change brightness in that case either, so you should disable its | ||
609 | backlight interface. | ||
610 | |||
611 | For Lenovo models *with* ACPI backlight control: | ||
612 | |||
613 | 1. Load up ACPI video and use that. ACPI video will report ACPI | ||
614 | events for brightness change keys. Do not mess with thinkpad-acpi | ||
615 | defaults in this case. thinkpad-acpi should not have anything to do | ||
616 | with backlight events in a scenario where ACPI video is loaded: | ||
617 | brightness hotkeys must be disabled, and the backlight interface is | ||
618 | to be kept disabled as well. This is the default mode of operation. | ||
619 | |||
620 | 2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi, | ||
621 | and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process | ||
622 | these keys on userspace somehow (e.g. by calling xbacklight). | ||
623 | The driver will do this automatically if it detects that ACPI video | ||
624 | has been disabled. | ||
625 | 596 | ||
626 | 597 | ||
627 | Bluetooth | 598 | Bluetooth |
@@ -679,6 +650,10 @@ LCD, CRT or DVI (if available). The following commands are available: | |||
679 | echo expand_toggle > /proc/acpi/ibm/video | 650 | echo expand_toggle > /proc/acpi/ibm/video |
680 | echo video_switch > /proc/acpi/ibm/video | 651 | echo video_switch > /proc/acpi/ibm/video |
681 | 652 | ||
653 | NOTE: Access to this feature is restricted to processes owning the | ||
654 | CAP_SYS_ADMIN capability for safety reasons, as it can interact badly | ||
655 | enough with some versions of X.org to crash it. | ||
656 | |||
682 | Each video output device can be enabled or disabled individually. | 657 | Each video output device can be enabled or disabled individually. |
683 | Reading /proc/acpi/ibm/video shows the status of each device. | 658 | Reading /proc/acpi/ibm/video shows the status of each device. |
684 | 659 | ||
@@ -1121,25 +1096,103 @@ WARNING: | |||
1121 | its level up and down at every change. | 1096 | its level up and down at every change. |
1122 | 1097 | ||
1123 | 1098 | ||
1124 | Volume control -- /proc/acpi/ibm/volume | 1099 | Volume control (Console Audio control) |
1125 | --------------------------------------- | 1100 | -------------------------------------- |
1101 | |||
1102 | procfs: /proc/acpi/ibm/volume | ||
1103 | ALSA: "ThinkPad Console Audio Control", default ID: "ThinkPadEC" | ||
1104 | |||
1105 | NOTE: by default, the volume control interface operates in read-only | ||
1106 | mode, as it is supposed to be used for on-screen-display purposes. | ||
1107 | The read/write mode can be enabled through the use of the | ||
1108 | "volume_control=1" module parameter. | ||
1109 | |||
1110 | NOTE: distros are urged to not enable volume_control by default, this | ||
1111 | should be done by the local admin only. The ThinkPad UI is for the | ||
1112 | console audio control to be done through the volume keys only, and for | ||
1113 | the desktop environment to just provide on-screen-display feedback. | ||
1114 | Software volume control should be done only in the main AC97/HDA | ||
1115 | mixer. | ||
1116 | |||
1117 | |||
1118 | About the ThinkPad Console Audio control: | ||
1119 | |||
1120 | ThinkPads have a built-in amplifier and muting circuit that drives the | ||
1121 | console headphone and speakers. This circuit is after the main AC97 | ||
1122 | or HDA mixer in the audio path, and under exclusive control of the | ||
1123 | firmware. | ||
1124 | |||
1125 | ThinkPads have three special hotkeys to interact with the console | ||
1126 | audio control: volume up, volume down and mute. | ||
1127 | |||
1128 | It is worth noting that the normal way the mute function works (on | ||
1129 | ThinkPads that do not have a "mute LED") is: | ||
1126 | 1130 | ||
1127 | This feature allows volume control on ThinkPad models which don't have | 1131 | 1. Press mute to mute. It will *always* mute, you can press it as |
1128 | a hardware volume knob. The available commands are: | 1132 | many times as you want, and the sound will remain mute. |
1133 | |||
1134 | 2. Press either volume key to unmute the ThinkPad (it will _not_ | ||
1135 | change the volume, it will just unmute). | ||
1136 | |||
1137 | This is a very superior design when compared to the cheap software-only | ||
1138 | mute-toggle solution found on normal consumer laptops: you can be | ||
1139 | absolutely sure the ThinkPad will not make noise if you press the mute | ||
1140 | button, no matter the previous state. | ||
1141 | |||
1142 | The IBM ThinkPads, and the earlier Lenovo ThinkPads have variable-gain | ||
1143 | amplifiers driving the speakers and headphone output, and the firmware | ||
1144 | also handles volume control for the headphone and speakers on these | ||
1145 | ThinkPads without any help from the operating system (this volume | ||
1146 | control stage exists after the main AC97 or HDA mixer in the audio | ||
1147 | path). | ||
1148 | |||
1149 | The newer Lenovo models only have firmware mute control, and depend on | ||
1150 | the main HDA mixer to do volume control (which is done by the operating | ||
1151 | system). In this case, the volume keys are filtered out for unmute | ||
1152 | key press (there are some firmware bugs in this area) and delivered as | ||
1153 | normal key presses to the operating system (thinkpad-acpi is not | ||
1154 | involved). | ||
1155 | |||
1156 | |||
1157 | The ThinkPad-ACPI volume control: | ||
1158 | |||
1159 | The preferred way to interact with the Console Audio control is the | ||
1160 | ALSA interface. | ||
1161 | |||
1162 | The legacy procfs interface allows one to read the current state, | ||
1163 | and if volume control is enabled, accepts the following commands: | ||
1129 | 1164 | ||
1130 | echo up >/proc/acpi/ibm/volume | 1165 | echo up >/proc/acpi/ibm/volume |
1131 | echo down >/proc/acpi/ibm/volume | 1166 | echo down >/proc/acpi/ibm/volume |
1132 | echo mute >/proc/acpi/ibm/volume | 1167 | echo mute >/proc/acpi/ibm/volume |
1168 | echo unmute >/proc/acpi/ibm/volume | ||
1133 | echo 'level <level>' >/proc/acpi/ibm/volume | 1169 | echo 'level <level>' >/proc/acpi/ibm/volume |
1134 | 1170 | ||
1135 | The <level> number range is 0 to 15 although not all of them may be | 1171 | The <level> number range is 0 to 14 although not all of them may be |
1136 | distinct. The unmute the volume after the mute command, use either the | 1172 | distinct. To unmute the volume after the mute command, use either the |
1137 | up or down command (the level command will not unmute the volume). | 1173 | up or down command (the level command will not unmute the volume), or |
1138 | The current volume level and mute state is shown in the file. | 1174 | the unmute command. |
1175 | |||
1176 | You can use the volume_capabilities parameter to tell the driver | ||
1177 | whether your thinkpad has volume control or mute-only control: | ||
1178 | volume_capabilities=1 for mixers with mute and volume control, | ||
1179 | volume_capabilities=2 for mixers with only mute control. | ||
1180 | |||
1181 | If the driver misdetects the capabilities for your ThinkPad model, | ||
1182 | please report this to ibm-acpi-devel@lists.sourceforge.net, so that we | ||
1183 | can update the driver. | ||
1184 | |||
1185 | There are two strategies for volume control. To select which one | ||
1186 | should be used, use the volume_mode module parameter: volume_mode=1 | ||
1187 | selects EC mode, and volume_mode=3 selects EC mode with NVRAM backing | ||
1188 | (so that volume/mute changes are remembered across shutdown/reboot). | ||
1139 | 1189 | ||
1140 | The ALSA mixer interface to this feature is still missing, but patches | 1190 | The driver will operate in volume_mode=3 by default. If that does not |
1141 | to add it exist. That problem should be addressed in the not so | 1191 | work well on your ThinkPad model, please report this to |
1142 | distant future. | 1192 | ibm-acpi-devel@lists.sourceforge.net. |
1193 | |||
1194 | The driver supports the standard ALSA module parameters. If the ALSA | ||
1195 | mixer is disabled, the driver will disable all volume functionality. | ||
1143 | 1196 | ||
1144 | 1197 | ||
1145 | Fan control and monitoring: fan speed, fan enable/disable | 1198 | Fan control and monitoring: fan speed, fan enable/disable |
@@ -1405,6 +1458,7 @@ to enable more than one output class, just add their values. | |||
1405 | 0x0008 HKEY event interface, hotkeys | 1458 | 0x0008 HKEY event interface, hotkeys |
1406 | 0x0010 Fan control | 1459 | 0x0010 Fan control |
1407 | 0x0020 Backlight brightness | 1460 | 0x0020 Backlight brightness |
1461 | 0x0040 Audio mixer/volume control | ||
1408 | 1462 | ||
1409 | There is also a kernel build option to enable more debugging | 1463 | There is also a kernel build option to enable more debugging |
1410 | information, which may be necessary to debug driver problems. | 1464 | information, which may be necessary to debug driver problems. |
@@ -1465,3 +1519,9 @@ Sysfs interface changelog: | |||
1465 | and it is always able to disable hot keys. Very old | 1519 | and it is always able to disable hot keys. Very old |
1466 | thinkpads are properly supported. hotkey_bios_mask | 1520 | thinkpads are properly supported. hotkey_bios_mask |
1467 | is deprecated and marked for removal. | 1521 | is deprecated and marked for removal. |
1522 | |||
1523 | 0x020600: Marker for backlight change event support. | ||
1524 | |||
1525 | 0x020700: Support for mute-only mixers. | ||
1526 | Volume control in read-only mode by default. | ||
1527 | Marker for ALSA mixer support. | ||