summaryrefslogtreecommitdiffstats
path: root/drivers/char/vesa_blank.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /drivers/char/vesa_blank.c
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'drivers/char/vesa_blank.c')
-rw-r--r--drivers/char/vesa_blank.c246
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);
+}