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