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