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