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