Subject: linux.1.0.1.power-save patch
From: lilo <[email-masked]>
Date: Mon, 24 Oct 1994 18:00:11 GMT
Newsgroups: comp.os.linux.announce

===================================================
        +=+=+=+=+= linux.1.0.1.power-save.patch +=+=+=+=+=+
        ===================================================

	There is some change in v1.1.54, and the original 
  "linux.1.0.power-save.patch" by Christoph Rimek <[email-masked]>
  will no longer patch correctly, I finally got a little time to hacked
  it a little. It should now patch cleanly with v1.1.54 and later...

  Note: All honor goes to Christoph Rimek.

						  -- James Zhu
						<[email-masked]>

Change Log:

  * memsetw() is needed in the new kernel, because it is used in vc_resize
    which is called in vt.c -- a change in patch v1.1.54

  * Patch cleanly with new kernel (v1.1.54 or later ..) .

The Following is readme in the original patch from Christoph Rimek:

********

"In my last posting (of 30-apr-94) I published the raw code to support the
new generation of monitors that know the VESA Power Saving Protocol (PSP).
Recently I found the time to code and can now present:

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-adresses), although tested only on two different VGA-cards: a  
cheap Cirrus Logic (5428) and a miro Crystal 8S (S3-805).

The only affected module is driver/char/console.c and within this the
two functions blank_screen and unblank_screen and a few new variable  
definitions. If activated, the function memsetw is no longer needed.

(memsetw() is needed in the new kernel, because it is used in vc_resize()
which is called in vt.c -- a change in patch v1.1.54    -- James Zhu )

The file config.in in the main kernel source directory has got two new
variables to define: CONFIG_VESA_PSPM (Power Saving Protocol Monitor)
and CONFIG_PSPM_FORCE_OFF. I have placed these lines into the character
device section right after the SELECTION part. You can choose from two
options:

(1) CONFIG_VESA_PSPM YES to activate these patches.
    The code will save the current setting of your video adapters'
    register settings and then program the controller to turn off
    the vertical sycnchronisation pulse. For details how this is
    achived refer to the code fragments following.

(2) CONFIG_PSPM_FORCE_OFF
    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 chose this option.

On the other hand I'd recommend to not chose 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 :-)) .

Another advantage of leaving the power down handling to the monitor is
that your always can use the same kernel and change the OFF timeout
locally at your monitor. My model lets me chose the timeout in steps
of five minutes: 0-5-10-15-...

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.

After all blah-blah now the diff-outputs for the patches.

I'm not sure whether it is necessary to encapsule the saving of the video
adapter registers in a cli/sti-pair, while this code comes to execution
only when the machine (keyboard) is idle. When setting the registers I
think it is better not to allow any interruption of the sequences.

Please let me know about your experiences with this code.

-cr

--
Christoph Rimek, Kiel, Germany  (+49 431 18307)      [email-masked]

***********************************************************************"

Good Luck ...

James Zhu
[email-masked] (temp. addr)

UCF Linux User Group
[email-masked]

* Save the following into two file and patch against:

linux/arch/i386/config.in
linux/drivers/char/console.c

------------------------- cut here ---------------------
*** config.in.orig	Sun Jul 24 16:35:21 1994
--- config.in	Sun Jul 24 16:36:11 1994
***************
*** 170,175 ****
--- 170,184 ----
  bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
  bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
  bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n
+  
+ comment 'VESA PSP Power Saving. (Answer yes, only if you have a Green Monitor)'
+  
+ bool 'VESA Power Saving Protocol Monitor support' CONFIG_VESA_PSPM n
+ if [ "$CONFIG_VESA_PSPM" = "y" ]; then
+ bool 'Force OFF signal to be sent to VESA PSP Monitor' CONFIG_PSPM_FORCE_OFF y
+ fi
+ 
+ comment 'Tape Backup Support'
  
  bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
  if [ "$CONFIG_QIC02_TAPE" = "y" ]; then

------------------------------- cut here ------------------------------
*** console.c.orig	Sat Oct 22 18:19:41 1994
--- console.c	Sun Oct 23 13:30:11 1994
***************
*** 123,128 ****
--- 123,172 ----
  static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' };
  #endif /* CONFIG_SELECTION */
  
+ #ifdef CONFIG_VESA_PSPM
+ /*
+  * This section(s) handles the VESA Power Saving Protocol that let a  *
+  * monitor be powered down whenever not needed for a longer time.     *
+  * VESA protocol defines:                                             *
+  *                                                                    *
+  *  Mode/Status               HSync   VSync   Video                           
+  *  ----------------------------------------------                    *
+  *  "On"              on      on      active                          *
+  *  "Suspend" {either}        on      off     blank                           
+  *            {  or  }        off     on      blank                           
+  *  "Off"               off   off     blank   <<  PSPM_FORCE_OFF      *
+  *                                                                    *
+  * 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 ([email-masked])  15-may-94       
+  */
+ 
+ #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 */
+ #ifdef CONFIG_PSPM_FORCE_OFF
+       unsigned char   HorizontalTotal;        /* CRT-Controller:00h */
+       unsigned char   HorizDisplayEnd;        /* CRT-Controller:01h */
+       unsigned char   StartHorizRetrace;      /* CRT-Controller:04h */
+       unsigned char   EndHorizRetrace;        /* CRT-Controller:05h */
+ #endif
+       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;
+ #endif /* CONFIG_VESA_PSPM */
+  
+ 
  #define NPAR 16
  
  static void con_setsize(unsigned long rows, unsigned long cols);
***************
*** 287,292 ****
--- 331,346 ----
  #define vcmode		(vt_cons[currcons]->vc_mode)
  #define structsize	(sizeof(struct vc_data) + sizeof(struct vt_struct))
  
+ 
+ /* #ifndef CONFIG_VESA_PSPM */
+ /* This function only needed for fast screen buffer filling in        */
+ /* blank_screen, may be spared if hardware blanks screen.  /CR        */
+ 
+ /**************************************************************************\
+  * Note: This function is NEEDED since v1.1.54, it is used in vt_resize() *
+  *       -- a change since v1.1.54                     ---- James Zhu     *
+ \**************************************************************************/
+ 
  static void * memsetw(void * s, unsigned short c, unsigned int count)
  {
  __asm__("cld\n\t"
***************
*** 297,302 ****
--- 351,357 ----
  	:"cx","di");
  return s;
  }
+ /*  #endif */
  
  int vc_cons_allocated(unsigned int i)
  {
***************
*** 2025,2031 ****
--- 2080,2088 ----
  
  void blank_screen(void)
  {
+ #ifndef CONFIG_VESA_PSPM
  	int currcons;
+ #endif
  
  	if (console_blanked)
  		return;
***************
*** 2036,2041 ****
--- 2093,2135 ----
  	}
  	timer_table[BLANK_TIMER].fn = unblank_screen;
  
+ 
+ #ifdef CONFIG_VESA_PSPM
+       /* 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();
+ #ifdef CONFIG_PSPM_FORCE_OFF
+       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);
+ #endif
+       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);
+       sti();
+ #else
+ 
  	/* try not to lose information by blanking, and not to waste memory */
  	currcons = fg_console;
  	has_scrolled = 0;
***************
*** 2044,2052 ****
  	set_origin(fg_console);
  	get_scrmem(fg_console);
  	unblank_origin = origin;
- 	memsetw((void *)blank_origin, BLANK, video_mem_term-blank_origin);
  	hide_cursor();
  	console_blanked = fg_console + 1;
  }
  
  void unblank_screen(void)
--- 2138,2183 ----
  	set_origin(fg_console);
  	get_scrmem(fg_console);
  	unblank_origin = origin;
  	hide_cursor();
+ 
+ #endif /* CONFIG_VESA_PSPM */
+ 
  	console_blanked = fg_console + 1;
+ 
+ #ifdef CONFIG_VESA_PSPM
+       cli();
+       /* 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 */
+ #ifdef CONFIG_PSPM_FORCE_OFF
+       /*  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) */
+ #endif
+       /* restore both index registers */
+       outb_p(vga.SeqCtrlIndex,seq_port_reg);
+       outb_p(vga.CrtCtrlIndex,video_port_reg);
+       sti();
+ #else
+ 	memsetw((void *)blank_origin, BLANK, video_mem_term-blank_origin);
+ 
+ #endif /* CONFIG_VESA_PSPM */
+ 
  }
  
  void unblank_screen(void)
***************
*** 2079,2087 ****
--- 2210,2253 ----
  	}
  
  	console_blanked = 0;
+ 
+ #ifdef CONFIG_VESA_PSPM
+       /* restore original values of VGA controller registers */
+       cli();
+       outb_p(vga.CrtMiscIO,video_misc_wr);
+ #ifdef CONFIG_PSPM_FORCE_OFF
+       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);
+ #endif
+       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();
+ #else
+ 
  	set_scrmem(fg_console, offset);
  	set_origin(fg_console);
  	set_cursor(fg_console);
+ 
+ #endif /* CONFIG_VESA_PSPM */
+ 
  	if (resetorg)
  		__set_origin(blank__origin);
  }
***************
*** 2458,2465 ****
--- 2624,2633 ----
  /* Pauline Middelink reports that we should use 0xA0000 for the bwmap as well.. */
  #define blackwmap ((char *)0xa0000)
  #define cmapsz 8192
+ #ifndef seq_port_reg  /* avoid re-definition */
  #define seq_port_reg (0x3c4)
  #define seq_port_val (0x3c5)
+ #endif
  #define gr_port_reg (0x3ce)
  #define gr_port_val (0x3cf)

--
Send submissions for comp.os.linux.announce to: [email-masked]
Be sure to include Keywords: and a short description of your software.