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. 88 89 If you use one of these modes, you can also set a second interval 90 by echoing the escape sequence ESC[10;interval] to the terminal. 91 The monitor will be turned off completely (mode 3) after being in 92 suspend mode for the specified interval. The interval defaults to 93 60 minutes. An interval of 0 disables this feature. 94 95 (2) Setting vesa_blanking_mode to 3. 96 If your monitor locally has an Off_Mode timer then you should not 97 force your video card to send the OFF-signal - your monitor will 98 power down by itself. 99 If your monitor cannot handle this and needs the Off-signal directly, 100 or if you like your monitor to power down immediately when the 101 blank_timer times out, then you choose this option. 102 103 On the other hand I'd recommend to not choose this second option unless 104 it is absolutely necessary. Powering down a monitor to the Off_State with 105 an approx. power consumption of 3-5 Watts is a rather strong action for 106 the CRT and it should not be done every now and then. If the software only 107 sends the signal to enter Standby mode, you have the chance to interfere 108 before the monitor powers down. Do not set a too short period, if you love 109 your hardware :-)) . 110 111 */ 112 113 #define seq_port_reg (0x3c4) /* Sequencer register select port */ 114 #define seq_port_val (0x3c5) /* Sequencer register value port */ 115 #define video_misc_rd (0x3cc) /* Video misc. read port */ 116 #define video_misc_wr (0x3c2) /* Video misc. write port */ 117 118 /* structure holding original VGA register settings */ 119 static struct { 120 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */ 121 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */ 122 unsigned char CrtMiscIO; /* Miscellaneous register */ 123 unsigned char HorizontalTotal; /* CRT-Controller:00h */ 124 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */ 125 unsigned char StartHorizRetrace; /* CRT-Controller:04h */ 126 unsigned char EndHorizRetrace; /* CRT-Controller:05h */ 127 unsigned char Overflow; /* CRT-Controller:07h */ 128 unsigned char StartVertRetrace; /* CRT-Controller:10h */ 129 unsigned char EndVertRetrace; /* CRT-Controller:11h */ 130 unsigned char ModeControl; /* CRT-Controller:17h */ 131 unsigned char ClockingMode; /* Seq-Controller:01h */ 132 } vga; 133 134 #define VESA_NO_BLANKING 0 135 #define VESA_VSYNC_SUSPEND 1 136 #define VESA_HSYNC_SUSPEND 2 137 #define VESA_POWERDOWN (VESA_HSYNC_SUSPEND | VESA_VSYNC_SUSPEND) 138 139 #define DEFAULT_VESA_BLANKING_MODE VESA_NO_BLANKING 140 141 static int vesa_blanking_mode = DEFAULT_VESA_BLANKING_MODE; 142 static int suspend_vesa_blanking_mode = DEFAULT_VESA_BLANKING_MODE; 143 static int vesa_blanked = 0; 144 145 /* routine to blank a vesa screen */ 146 void vesa_blank(void) /* */ 147 { 148 int mode; 149 150 if((mode = vesa_blanking_mode) == 0) 151 return; 152 153 /* save original values of VGA controller registers */ 154 if(!vesa_blanked) { 155 cli(); 156 vga.SeqCtrlIndex = inb_p(seq_port_reg); 157 vga.CrtCtrlIndex = inb_p(video_port_reg); 158 vga.CrtMiscIO = inb_p(video_misc_rd); 159 sti(); 160 161 outb_p(0x00,video_port_reg); /* HorizontalTotal */ 162 vga.HorizontalTotal = inb_p(video_port_val); 163 outb_p(0x01,video_port_reg); /* HorizDisplayEnd */ 164 vga.HorizDisplayEnd = inb_p(video_port_val); 165 outb_p(0x04,video_port_reg); /* StartHorizRetrace */ 166 vga.StartHorizRetrace = inb_p(video_port_val); 167 outb_p(0x05,video_port_reg); /* EndHorizRetrace */ 168 vga.EndHorizRetrace = inb_p(video_port_val); 169 outb_p(0x07,video_port_reg); /* Overflow */ 170 vga.Overflow = inb_p(video_port_val); 171 outb_p(0x10,video_port_reg); /* StartVertRetrace */ 172 vga.StartVertRetrace = inb_p(video_port_val); 173 outb_p(0x11,video_port_reg); /* EndVertRetrace */ 174 vga.EndVertRetrace = inb_p(video_port_val); 175 outb_p(0x17,video_port_reg); /* ModeControl */ 176 vga.ModeControl = inb_p(video_port_val); 177 outb_p(0x01,seq_port_reg); /* ClockingMode */ 178 vga.ClockingMode = inb_p(seq_port_val); 179 } 180 181 /* assure that video is enabled */ 182 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */ 183 cli(); 184 outb_p(0x01,seq_port_reg); 185 outb_p(vga.ClockingMode | 0x20,seq_port_val); 186 187 /* test for vertical retrace in process.... */ 188 if ((vga.CrtMiscIO & 0x80) == 0x80) 189 outb_p(vga.CrtMiscIO & 0xef,video_misc_wr); 190 191 /* 192 * Set <End of vertical retrace> to minimum (0) and 193 * <Start of vertical Retrace> to maximum (incl. overflow) 194 * Result: turn off vertical sync (VSync) pulse. 195 */ 196 if (mode & VESA_VSYNC_SUSPEND) { 197 outb_p(0x10,video_port_reg); /* StartVertRetrace */ 198 outb_p(0xff,video_port_val); /* maximum value */ 199 outb_p(0x11,video_port_reg); /* EndVertRetrace */ 200 outb_p(0x40,video_port_val); /* minimum (bits 0..3) */ 201 outb_p(0x07,video_port_reg); /* Overflow */ 202 outb_p(vga.Overflow | 0x84,video_port_val); /* bits 9,10 of */ 203 /* vert. retrace */ 204 } 205 206 if (mode & VESA_HSYNC_SUSPEND) { 207 /* 208 * Set <End of horizontal retrace> to minimum (0) and 209 * <Start of horizontal Retrace> to maximum 210 * Result: turn off horizontal sync (HSync) pulse. 211 */ 212 outb_p(0x04,video_port_reg); /* StartHorizRetrace */ 213 outb_p(0xff,video_port_val); /* maximum */ 214 outb_p(0x05,video_port_reg); /* EndHorizRetrace */ 215 outb_p(0x00,video_port_val); /* minimum (0) */ 216 } 217 218 /* restore both index registers */ 219 outb_p(vga.SeqCtrlIndex,seq_port_reg); 220 outb_p(vga.CrtCtrlIndex,video_port_reg); 221 sti(); 222 223 vesa_blanked = mode; 224 } 225 226 /* routine to unblank a vesa screen */ 227 void vesa_unblank(void) /* */ 228 { 229 if (!vesa_blanked) 230 return; 231 232 /* restore original values of VGA controller registers */ 233 cli(); 234 outb_p(vga.CrtMiscIO,video_misc_wr); 235 236 outb_p(0x00,video_port_reg); /* HorizontalTotal */ 237 outb_p(vga.HorizontalTotal,video_port_val); 238 outb_p(0x01,video_port_reg); /* HorizDisplayEnd */ 239 outb_p(vga.HorizDisplayEnd,video_port_val); 240 outb_p(0x04,video_port_reg); /* StartHorizRetrace */ 241 outb_p(vga.StartHorizRetrace,video_port_val); 242 outb_p(0x05,video_port_reg); /* EndHorizRetrace */ 243 outb_p(vga.EndHorizRetrace,video_port_val); 244 outb_p(0x07,video_port_reg); /* Overflow */ 245 outb_p(vga.Overflow,video_port_val); 246 outb_p(0x10,video_port_reg); /* StartVertRetrace */ 247 outb_p(vga.StartVertRetrace,video_port_val); 248 outb_p(0x11,video_port_reg); /* EndVertRetrace */ 249 outb_p(vga.EndVertRetrace,video_port_val); 250 outb_p(0x17,video_port_reg); /* ModeControl */ 251 outb_p(vga.ModeControl,video_port_val); 252 outb_p(0x01,seq_port_reg); /* ClockingMode */ 253 outb_p(vga.ClockingMode,seq_port_val); 254 255 /* restore index/control registers */ 256 outb_p(vga.SeqCtrlIndex,seq_port_reg); 257 outb_p(vga.CrtCtrlIndex,video_port_reg); 258 sti(); 259 260 vesa_blanked = 0; 261 } 262 263 void set_vesa_blanking(const unsigned long arg) /* */ 264 { 265 unsigned char *argp = (unsigned char *)(arg + 1); 266 unsigned int mode = get_user(argp); 267 vesa_blanking_mode = suspend_vesa_blanking_mode = 268 ((mode <= VESA_POWERDOWN) ? mode : DEFAULT_VESA_BLANKING_MODE); 269 } 270 271 void vesa_powerdown(void) /* */ 272 { 273 if(vesa_blanking_mode == VESA_VSYNC_SUSPEND 274 || vesa_blanking_mode == VESA_HSYNC_SUSPEND) 275 { 276 vesa_blanking_mode = VESA_POWERDOWN; 277 vesa_blank(); 278 vesa_blanking_mode = suspend_vesa_blanking_mode; 279 } 280 }