diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
commit | e7c2a72e2680827d6a733931273a93461c0d8d1b (patch) | |
tree | c9abeda78ef7504062bb2e816bcf3e3c9d680112 /drivers/char/vesa_blank.c | |
parent | ec6044459060a8c9ce7f64405c465d141898548c (diff) |
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'drivers/char/vesa_blank.c')
-rw-r--r-- | drivers/char/vesa_blank.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/drivers/char/vesa_blank.c b/drivers/char/vesa_blank.c new file mode 100644 index 000000000..8e5e17d31 --- /dev/null +++ b/drivers/char/vesa_blank.c @@ -0,0 +1,246 @@ +/* + * vesa_blank.c + * + * Exported functions: + * void vesa_blank(void); + * void vesa_unblank(void); + * void set_vesa_blanking(const unsigned long arg); + * + * Not all hardware reacts well to this code - activate at your own risk. + * Activation is done using a sufficiently recent version of setterm + * or using a tiny C program like the following. + * +----------------------------------------------------------------------- +|#include <stdio.h> +|#include <linux/termios.h> +|main(int argc, char *argv[]) { +| int fd; +| struct { char ten, onoff; } arg; +| +| if (argc != 2) { +| fprintf(stderr, "usage: setvesablank ON|on|off\n"); +| exit(1); +| } +| if ((fd = open("/dev/console", 0)) < 0) +| fd = 0; +| arg.ten = 10; +| arg.onoff = 0; +| if (!strcmp(argv[1], "on")) +| arg.onoff = 1; +| else if (!strcmp(argv[1], "ON")) +| arg.onoff = 2; +| if (ioctl(fd, TIOCLINUX, &arg)) { +| perror("setvesablank: TIOCLINUX"); +| exit(1); +| } +| exit(0); +|} +----------------------------------------------------------------------- +*/ + +#include <asm/io.h> +#include <asm/system.h> +#include <asm/segment.h> + +extern unsigned short video_port_reg, video_port_val; + +/* + * This file handles the VESA Power Saving Protocol that lets a + * monitor be powered down whenever not needed for a longer time. + * The VESA protocol defines: + * + * Mode/Status HSync VSync Video + * ------------------------------------------- + * "On" on on active (mode 0) + * "Suspend" {either} on off blank (mode 1) + * { or } off on blank + * "Off" off off blank (mode 2) + * + * Original code taken from the Power Management Utility (PMU) of + * Huang shi chao, delivered together with many new monitor models + * capable of the VESA Power Saving Protocol. + * + * Adapted to Linux by Christoph Rimek (chrimek@toppoint.de) 15-may-94. + * A slightly adapted fragment of his README follows. + * +Patch (based on Linux Kernel revision 1.0) for handling the Power Saving +feature of the new monitor generation. The code works on all these monitors +(mine is a Smile 1506) and should run on *all* video adapter cards (change +some i/o-addresses), although tested only on two different VGA-cards: a +cheap Cirrus Logic (5428) and a miro Crystal 8S (S3-805). + +You can choose from two options: + +(1) Setting vesa_blanking_mode to 1. + The code will save the current setting of your video adapters' + register settings and then program the controller to turn off + the vertical synchronisation pulse. + +(2) Setting vesa_blanking_mode to 2. + If your monitor locally has an Off_Mode timer then you should not + force your video card to send the OFF-signal - your monitor will + power down by itself. + If your monitor cannot handle this and needs the Off-signal directly, + or if you like your monitor to power down immediately when the + blank_timer times out, then you choose this option. + +On the other hand I'd recommend to not choose this second option unless +it is absolutely necessary. Powering down a monitor to the Off_State with +an approx. power consumption of 3-5 Watts is a rather strong action for +the CRT and it should not be done every now and then. If the software only +sends the signal to enter Standby mode, you have the chance to interfere +before the monitor powers down. Do not set a too short period, if you love +your hardware :-)) . + +If requested, in the future it may be possible to install another timer +to provide a configurable delay between the two stages Standby and Off +similar to the "setterm -blank"-feature. +*/ + +#define seq_port_reg (0x3c4) /* Sequencer register select port */ +#define seq_port_val (0x3c5) /* Sequencer register value port */ +#define video_misc_rd (0x3cc) /* Video misc. read port */ +#define video_misc_wr (0x3c2) /* Video misc. write port */ + +/* structure holding original VGA register settings */ +static struct { + unsigned char SeqCtrlIndex; /* Sequencer Index reg. */ + unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */ + unsigned char CrtMiscIO; /* Miscellaneous register */ + unsigned char HorizontalTotal; /* CRT-Controller:00h */ + unsigned char HorizDisplayEnd; /* CRT-Controller:01h */ + unsigned char StartHorizRetrace; /* CRT-Controller:04h */ + unsigned char EndHorizRetrace; /* CRT-Controller:05h */ + unsigned char Overflow; /* CRT-Controller:07h */ + unsigned char StartVertRetrace; /* CRT-Controller:10h */ + unsigned char EndVertRetrace; /* CRT-Controller:11h */ + unsigned char ModeControl; /* CRT-Controller:17h */ + unsigned char ClockingMode; /* Seq-Controller:01h */ +} vga; + +static int vesa_blanking_mode = 0; +static int vesa_blanked = 0; + +/* routine to blank a vesa screen */ +void vesa_blank(void) +{ + int mode; + + if((mode = vesa_blanking_mode) == 0) + return; + + /* save original values of VGA controller registers */ + cli(); + vga.SeqCtrlIndex = inb_p(seq_port_reg); + vga.CrtCtrlIndex = inb_p(video_port_reg); + vga.CrtMiscIO = inb_p(video_misc_rd); + sti(); + + if(mode == 2) { + outb_p(0x00,video_port_reg); /* HorizontalTotal */ + vga.HorizontalTotal = inb_p(video_port_val); + outb_p(0x01,video_port_reg); /* HorizDisplayEnd */ + vga.HorizDisplayEnd = inb_p(video_port_val); + outb_p(0x04,video_port_reg); /* StartHorizRetrace */ + vga.StartHorizRetrace = inb_p(video_port_val); + outb_p(0x05,video_port_reg); /* EndHorizRetrace */ + vga.EndHorizRetrace = inb_p(video_port_val); + } + outb_p(0x07,video_port_reg); /* Overflow */ + vga.Overflow = inb_p(video_port_val); + outb_p(0x10,video_port_reg); /* StartVertRetrace */ + vga.StartVertRetrace = inb_p(video_port_val); + outb_p(0x11,video_port_reg); /* EndVertRetrace */ + vga.EndVertRetrace = inb_p(video_port_val); + outb_p(0x17,video_port_reg); /* ModeControl */ + vga.ModeControl = inb_p(video_port_val); + outb_p(0x01,seq_port_reg); /* ClockingMode */ + vga.ClockingMode = inb_p(seq_port_val); + + /* assure that video is enabled */ + /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */ + cli(); + outb_p(0x01,seq_port_reg); + outb_p(vga.ClockingMode | 0x20,seq_port_val); + + /* test for vertical retrace in process.... */ + if ((vga.CrtMiscIO & 0x80) == 0x80) + outb_p(vga.CrtMiscIO & 0xef,video_misc_wr); + + /* + * Set <End of vertical retrace> to minimum (0) and + * <Start of vertical Retrace> to maximum (incl. overflow) + * Result: turn off vertical sync (VSync) pulse. + */ + outb_p(0x10,video_port_reg); /* StartVertRetrace */ + outb_p(0xff,video_port_val); /* maximum value */ + outb_p(0x11,video_port_reg); /* EndVertRetrace */ + outb_p(0x40,video_port_val); /* minimum (bits 0..3) */ + outb_p(0x07,video_port_reg); /* Overflow */ + outb_p(vga.Overflow | 0x84,video_port_val); /* bits 9,10 of */ + /* vert. retrace */ + if (mode == 2) { + /* + * Set <End of horizontal retrace> to minimum (0) and + * <Start of horizontal Retrace> to maximum + * Result: turn off horizontal sync (HSync) pulse. + */ + outb_p(0x04,video_port_reg); /* StartHorizRetrace */ + outb_p(0xff,video_port_val); /* maximum */ + outb_p(0x05,video_port_reg); /* EndHorizRetrace */ + outb_p(0x00,video_port_val); /* minimum (0) */ + } + + /* restore both index registers */ + outb_p(vga.SeqCtrlIndex,seq_port_reg); + outb_p(vga.CrtCtrlIndex,video_port_reg); + sti(); + + vesa_blanked = mode; +} + +/* routine to unblank a vesa screen */ +void vesa_unblank(void) +{ + if (!vesa_blanked) + return; + + /* restore original values of VGA controller registers */ + cli(); + outb_p(vga.CrtMiscIO,video_misc_wr); + + if (vesa_blanked == 2) { + outb_p(0x00,video_port_reg); /* HorizontalTotal */ + outb_p(vga.HorizontalTotal,video_port_val); + outb_p(0x01,video_port_reg); /* HorizDisplayEnd */ + outb_p(vga.HorizDisplayEnd,video_port_val); + outb_p(0x04,video_port_reg); /* StartHorizRetrace */ + outb_p(vga.StartHorizRetrace,video_port_val); + outb_p(0x05,video_port_reg); /* EndHorizRetrace */ + outb_p(vga.EndHorizRetrace,video_port_val); + } + outb_p(0x07,video_port_reg); /* Overflow */ + outb_p(vga.Overflow,video_port_val); + outb_p(0x10,video_port_reg); /* StartVertRetrace */ + outb_p(vga.StartVertRetrace,video_port_val); + outb_p(0x11,video_port_reg); /* EndVertRetrace */ + outb_p(vga.EndVertRetrace,video_port_val); + outb_p(0x17,video_port_reg); /* ModeControl */ + outb_p(vga.ModeControl,video_port_val); + outb_p(0x01,seq_port_reg); /* ClockingMode */ + outb_p(vga.ClockingMode,seq_port_val); + + /* restore index/control registers */ + outb_p(vga.SeqCtrlIndex,seq_port_reg); + outb_p(vga.CrtCtrlIndex,video_port_reg); + sti(); + + vesa_blanked = 0; +} + +void set_vesa_blanking(const unsigned long arg) +{ + char *argp = (char *)(arg + 1); + unsigned int mode = get_fs_byte(argp); + vesa_blanking_mode = ((mode < 3) ? mode : 0); +} |