1 /*
2 * vesa_blank.c
3 *
4 * Exported functions:
5 * void vesa_blank(void);
6 * void vesa_unblank(void);
7 * void vesa_powerdown(void);
8 * void set_vesa_blanking(const unsigned long arg);
9 *
10 * Not all hardware reacts well to this code - activate at your own risk.
11 * Activation is done using a sufficiently recent version of setterm
12 * or using a tiny C program like the following.
13 *
14 -----------------------------------------------------------------------
15 |#include <stdio.h>
16 |#include <linux/termios.h>
17 |main(int argc, char *argv[]) {
18 | int fd;
19 | struct { char ten, onoff; } arg;
20 |
21 | if (argc != 2) {
22 | fprintf(stderr, "usage: setvesablank on|vsync|hsync|powerdown|off\n");
23 | exit(1);
24 | }
25 | if ((fd = open("/dev/console", 0)) < 0)
26 | fd = 0;
27 | arg.ten = 10;
28 | arg.onoff = 0;
29 | if (!strcmp(argv[1], "on") || !strcmp(argv[1], "vsync"))
30 | arg.onoff = 1;
31 | else if (!strcmp(argv[1], "hsync"))
32 | arg.onoff = 2;
33 | else if (!strcmp(argv[1], "powerdown"))
34 | arg.onoff = 3;
35 | if (ioctl(fd, TIOCLINUX, &arg)) {
36 | perror("setvesablank: TIOCLINUX");
37 | exit(1);
38 | }
39 | exit(0);
40 |}
41 -----------------------------------------------------------------------
42 */
43
44 #include <asm/io.h>
45 #include <asm/system.h>
46 #include <asm/segment.h>
47
48 extern unsigned short video_port_reg, video_port_val;
49
50 /*
51 * This file handles the VESA Power Saving Protocol that lets a
52 * monitor be powered down whenever not needed for a longer time.
53 * The VESA protocol defines:
54 *
55 * Mode/Status HSync VSync Video
56 * -------------------------------------------
57 * "On" on on active (mode 0)
58 * "Suspend" {either} on off blank (mode 1)
59 * { or } off on blank (mode 2)
60 * "Off" off off blank (mode 3)
61 *
62 * Original code taken from the Power Management Utility (PMU) of
63 * Huang shi chao, delivered together with many new monitor models
64 * capable of the VESA Power Saving Protocol.
65 *
66 * Adapted to Linux by Christoph Rimek (chrimek@toppoint.de) 15-may-94.
67 * A slightly adapted fragment of his README follows.
68 *
69 * Two-stage blanking by todd j. derr (tjd@barefoot.org) 10-oct-95.
70
71 Patch (based on Linux Kernel revision 1.0) for handling the Power Saving
72 feature of the new monitor generation. The code works on all these monitors
73 (mine is a Smile 1506) and should run on *all* video adapter cards (change
74 some i/o-addresses), although tested only on two different VGA-cards: a
75 cheap Cirrus Logic (5428) and a miro Crystal 8S (S3-805).
76
77 You can choose from two options:
78
79 (1) Setting vesa_blanking_mode to 1 or 2.
80 The code will save the current setting of your video adapters'
81 register settings and then program the controller to turn off
82 the vertical synchronization pulse (mode 1) or horizontal
83 synchronization pulse (mode 2). Mode 1 should work with most
84 monitors, but the VESA spec allows mode 2, so it's included for
85 completeness. You may set this blanking interval in minutes by
86 echoing the escape sequence 'ESC[9;interval]' to the terminal.
87 By default this interval is set to 10 minutes.
88
89 If you use one of these modes, you can also set a second interval
90 by echoing the escape sequence 'ESC[14;interval]' to the terminal.
91 The monitor will be turned off completely (mode 3) after being in
92 suspend mode for the specified interval. An interval of 0 disables
93 this feature which is the default.
94
95 Both intervals may be set within the range of 0..60 minutes.
96
97 (2) Setting vesa_blanking_mode to 3.
98 If your monitor locally has an Off_Mode timer then you should not
99 force your video card to send the OFF-signal - your monitor will
100 power down by itself.
101 If your monitor cannot handle this and needs the Off-signal directly,
102 or if you like your monitor to power down immediately when the
103 blank_timer times out, then you choose this option.
104
105 On the other hand I'd recommend to not choose this second option unless
106 it is absolutely necessary. Powering down a monitor to the Off_State with
107 an approx. power consumption of 3-5 Watts is a rather strong action for
108 the CRT and it should not be done every now and then. If the software only
109 sends the signal to enter Standby mode, you have the chance to interfere
110 before the monitor powers down. Do not set a too short period, if you love
111 your hardware :-)) .
112
113 By default vesa_blanking_mode is set to 0, thus not using any power saving
114 features.
115 */
116
117 #define seq_port_reg (0x3c4) /* Sequencer register select port */
118 #define seq_port_val (0x3c5) /* Sequencer register value port */
119 #define video_misc_rd (0x3cc) /* Video misc. read port */
120 #define video_misc_wr (0x3c2) /* Video misc. write port */
121
122 /* structure holding original VGA register settings */
123 static struct {
124 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
125 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
126 unsigned char CrtMiscIO; /* Miscellaneous register */
127 unsigned char HorizontalTotal; /* CRT-Controller:00h */
128 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
129 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
130 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
131 unsigned char Overflow; /* CRT-Controller:07h */
132 unsigned char StartVertRetrace; /* CRT-Controller:10h */
133 unsigned char EndVertRetrace; /* CRT-Controller:11h */
134 unsigned char ModeControl; /* CRT-Controller:17h */
135 unsigned char ClockingMode; /* Seq-Controller:01h */
136 } vga;
137
138 #define VESA_NO_BLANKING 0
139 #define VESA_VSYNC_SUSPEND 1
140 #define VESA_HSYNC_SUSPEND 2
141 #define VESA_POWERDOWN (VESA_HSYNC_SUSPEND | VESA_VSYNC_SUSPEND)
142
143 #define DEFAULT_VESA_BLANKING_MODE VESA_NO_BLANKING
144
145 static int vesa_blanking_mode = DEFAULT_VESA_BLANKING_MODE;
146 static int suspend_vesa_blanking_mode = DEFAULT_VESA_BLANKING_MODE;
147 static int vesa_blanked = 0;
148
149 /* routine to blank a vesa screen */
150 void vesa_blank(void)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
151 {
152 int mode;
153
154 if((mode = vesa_blanking_mode) == 0)
155 return;
156
157 /* save original values of VGA controller registers */
158 if(!vesa_blanked) {
159 cli();
160 vga.SeqCtrlIndex = inb_p(seq_port_reg);
161 vga.CrtCtrlIndex = inb_p(video_port_reg);
162 vga.CrtMiscIO = inb_p(video_misc_rd);
163 sti();
164
165 outb_p(0x00,video_port_reg); /* HorizontalTotal */
166 vga.HorizontalTotal = inb_p(video_port_val);
167 outb_p(0x01,video_port_reg); /* HorizDisplayEnd */
168 vga.HorizDisplayEnd = inb_p(video_port_val);
169 outb_p(0x04,video_port_reg); /* StartHorizRetrace */
170 vga.StartHorizRetrace = inb_p(video_port_val);
171 outb_p(0x05,video_port_reg); /* EndHorizRetrace */
172 vga.EndHorizRetrace = inb_p(video_port_val);
173 outb_p(0x07,video_port_reg); /* Overflow */
174 vga.Overflow = inb_p(video_port_val);
175 outb_p(0x10,video_port_reg); /* StartVertRetrace */
176 vga.StartVertRetrace = inb_p(video_port_val);
177 outb_p(0x11,video_port_reg); /* EndVertRetrace */
178 vga.EndVertRetrace = inb_p(video_port_val);
179 outb_p(0x17,video_port_reg); /* ModeControl */
180 vga.ModeControl = inb_p(video_port_val);
181 outb_p(0x01,seq_port_reg); /* ClockingMode */
182 vga.ClockingMode = inb_p(seq_port_val);
183 }
184
185 /* assure that video is enabled */
186 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
187 cli();
188 outb_p(0x01,seq_port_reg);
189 outb_p(vga.ClockingMode | 0x20,seq_port_val);
190
191 /* test for vertical retrace in process.... */
192 if ((vga.CrtMiscIO & 0x80) == 0x80)
193 outb_p(vga.CrtMiscIO & 0xef,video_misc_wr);
194
195 /*
196 * Set <End of vertical retrace> to minimum (0) and
197 * <Start of vertical Retrace> to maximum (incl. overflow)
198 * Result: turn off vertical sync (VSync) pulse.
199 */
200 if (mode & VESA_VSYNC_SUSPEND) {
201 outb_p(0x10,video_port_reg); /* StartVertRetrace */
202 outb_p(0xff,video_port_val); /* maximum value */
203 outb_p(0x11,video_port_reg); /* EndVertRetrace */
204 outb_p(0x40,video_port_val); /* minimum (bits 0..3) */
205 outb_p(0x07,video_port_reg); /* Overflow */
206 outb_p(vga.Overflow | 0x84,video_port_val); /* bits 9,10 of */
207 /* vert. retrace */
208 }
209
210 if (mode & VESA_HSYNC_SUSPEND) {
211 /*
212 * Set <End of horizontal retrace> to minimum (0) and
213 * <Start of horizontal Retrace> to maximum
214 * Result: turn off horizontal sync (HSync) pulse.
215 */
216 outb_p(0x04,video_port_reg); /* StartHorizRetrace */
217 outb_p(0xff,video_port_val); /* maximum */
218 outb_p(0x05,video_port_reg); /* EndHorizRetrace */
219 outb_p(0x00,video_port_val); /* minimum (0) */
220 }
221
222 /* restore both index registers */
223 outb_p(vga.SeqCtrlIndex,seq_port_reg);
224 outb_p(vga.CrtCtrlIndex,video_port_reg);
225 sti();
226
227 vesa_blanked = mode;
228 }
229
230 /* routine to unblank a vesa screen */
231 void vesa_unblank(void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
232 {
233 if (!vesa_blanked)
234 return;
235
236 /* restore original values of VGA controller registers */
237 cli();
238 outb_p(vga.CrtMiscIO,video_misc_wr);
239
240 outb_p(0x00,video_port_reg); /* HorizontalTotal */
241 outb_p(vga.HorizontalTotal,video_port_val);
242 outb_p(0x01,video_port_reg); /* HorizDisplayEnd */
243 outb_p(vga.HorizDisplayEnd,video_port_val);
244 outb_p(0x04,video_port_reg); /* StartHorizRetrace */
245 outb_p(vga.StartHorizRetrace,video_port_val);
246 outb_p(0x05,video_port_reg); /* EndHorizRetrace */
247 outb_p(vga.EndHorizRetrace,video_port_val);
248 outb_p(0x07,video_port_reg); /* Overflow */
249 outb_p(vga.Overflow,video_port_val);
250 outb_p(0x10,video_port_reg); /* StartVertRetrace */
251 outb_p(vga.StartVertRetrace,video_port_val);
252 outb_p(0x11,video_port_reg); /* EndVertRetrace */
253 outb_p(vga.EndVertRetrace,video_port_val);
254 outb_p(0x17,video_port_reg); /* ModeControl */
255 outb_p(vga.ModeControl,video_port_val);
256 outb_p(0x01,seq_port_reg); /* ClockingMode */
257 outb_p(vga.ClockingMode,seq_port_val);
258
259 /* restore index/control registers */
260 outb_p(vga.SeqCtrlIndex,seq_port_reg);
261 outb_p(vga.CrtCtrlIndex,video_port_reg);
262 sti();
263
264 vesa_blanked = 0;
265 }
266
267 void set_vesa_blanking(const unsigned long arg)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
268 {
269 unsigned char *argp = (unsigned char *)(arg + 1);
270 unsigned int mode = get_user(argp);
271 vesa_blanking_mode = suspend_vesa_blanking_mode =
272 ((mode <= VESA_POWERDOWN) ? mode : DEFAULT_VESA_BLANKING_MODE);
273 }
274
275 void vesa_powerdown(void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
276 {
277 if(vesa_blanking_mode == VESA_VSYNC_SUSPEND
278 || vesa_blanking_mode == VESA_HSYNC_SUSPEND)
279 {
280 vesa_blanking_mode = VESA_POWERDOWN;
281 vesa_blank();
282 vesa_blanking_mode = suspend_vesa_blanking_mode;
283 }
284 }