patch-1.3.38 linux/drivers/char/vga.c

Next file: linux/drivers/net/3c507.c
Previous file: linux/drivers/char/tga.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.37/linux/drivers/char/vga.c linux/drivers/char/vga.c
@@ -0,0 +1,571 @@
+/*
+ *  linux/drivers/char/vga.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *			1995  Jay Estabrook
+ */
+
+/*
+ *	vga.c
+ *
+ * This module exports the console low-level io support for VGA
+ *
+ *     'int con_get_font(char *data)'
+ *     'int con_set_font(char *data, int ch512)'
+ *     'int con_adjust_height(int fontheight)'
+ *
+ *     'int con_get_cmap(char *)'
+ *     'int con_set_cmap(char *)'
+ *
+ *     'int reset_palette(int currcons)'
+ *     'void set_palette(void)'
+ *
+ * User definable mapping table and font loading by Eugene G. Crosser,
+ * <crosser@pccross.msk.su>
+ *
+ * Improved loadable font/UTF-8 support by H. Peter Anvin 
+ * Feb-Sep 1995 <peter.anvin@linux.org>
+ *
+ * improved scrollback, plus colour palette handling, by Simon Tatham
+ * 17-Jun-95 <sgt20@cam.ac.uk>
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+
+#include "kbd_kern.h"
+#include "vt_kern.h"
+#include "consolemap.h"
+#include "selection.h"
+#include "console_struct.h"
+
+#define CAN_LOAD_EGA_FONTS    /* undefine if the user must not do this */
+#define CAN_LOAD_PALETTE      /* undefine if the user must not do this */
+
+#define dac_reg (0x3c8)
+#define dac_val (0x3c9)
+
+
+void
+set_palette (void)
+{
+	int i, j ;
+
+	if (video_type != VIDEO_TYPE_VGAC || console_blanked ||
+	    vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+		return ;
+
+	for (i=j=0; i<16; i++) {
+		outb_p (color_table[i], dac_reg) ;
+		outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
+		outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
+		outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
+	}
+}
+
+void
+__set_origin(unsigned short offset)
+{
+	unsigned long flags;
+
+	clear_selection();
+
+	save_flags(flags); cli();
+	__origin = offset;
+	outb_p(12, video_port_reg);
+	outb_p(offset >> 8, video_port_val);
+	outb_p(13, video_port_reg);
+	outb_p(offset, video_port_val);
+	restore_flags(flags);
+}
+
+/*
+ * Put the cursor just beyond the end of the display adaptor memory.
+ */
+void
+hide_cursor(void)
+{
+  /* This is inefficient, we could just put the cursor at 0xffff,
+     but perhaps the delays due to the inefficiency are useful for
+     some hardware... */
+	outb_p(14, video_port_reg);
+	outb_p(0xff&((video_mem_term-video_mem_base)>>9), video_port_val);
+	outb_p(15, video_port_reg);
+	outb_p(0xff&((video_mem_term-video_mem_base)>>1), video_port_val);
+}
+
+void
+set_cursor(int currcons)
+{
+	unsigned long flags;
+
+	if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
+		return;
+	if (__real_origin != __origin)
+		__set_origin(__real_origin);
+	save_flags(flags); cli();
+	if (deccm) {
+		outb_p(14, video_port_reg);
+		outb_p(0xff&((pos-video_mem_base)>>9), video_port_val);
+		outb_p(15, video_port_reg);
+		outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
+	} else
+		hide_cursor();
+	restore_flags(flags);
+}
+
+unsigned long
+con_type_init(unsigned long kmem_start, char *display_desc)
+{
+	if (ORIG_VIDEO_MODE == 7)	/* Is this a monochrome display? */
+	{
+		video_mem_base = 0xb0000;
+		video_port_reg = 0x3b4;
+		video_port_val = 0x3b5;
+		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
+		{
+			video_type = VIDEO_TYPE_EGAM;
+			video_mem_term = 0xb8000;
+			display_desc = "EGA+";
+			request_region(0x3b0,16,"ega");
+		}
+		else
+		{
+			video_type = VIDEO_TYPE_MDA;
+			video_mem_term = 0xb2000;
+			display_desc = "*MDA";
+			request_region(0x3b0,12,"mda");
+			request_region(0x3bf, 1,"mda");
+		}
+	}
+	else				/* If not, it is color. */
+	{
+		can_do_color = 1;
+		video_mem_base = 0xb8000;
+		video_port_reg	= 0x3d4;
+		video_port_val	= 0x3d5;
+		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
+		{
+			int i ;
+
+			video_mem_term = 0xc0000;
+
+			if (!ORIG_VIDEO_ISVGA) {
+				video_type = VIDEO_TYPE_EGAC;
+				display_desc = "EGA";
+				request_region(0x3c0,32,"ega");
+			} else {
+				video_type = VIDEO_TYPE_VGAC;
+				display_desc = "VGA+";
+				request_region(0x3c0,32,"vga+");
+
+#ifdef VGA_CAN_DO_64KB
+				/*
+				 * get 64K rather than 32K of video RAM.
+				 * This doesn't actually work on all "VGA"
+				 * controllers (it seems like setting MM=01
+				 * and COE=1 isn't necessarily a good idea)
+				 */
+				video_mem_base = 0xa0000 ;
+				video_mem_term = 0xb0000 ;
+				outb_p (6, 0x3ce) ;
+				outb_p (6, 0x3cf) ;
+#endif
+
+				/* normalise the palette registers, to point the
+				 * 16 screen colours to the first 16 DAC entries */
+
+				for (i=0; i<16; i++) {
+					inb_p (0x3da) ;
+					outb_p (i, 0x3c0) ;
+					outb_p (i, 0x3c0) ;
+				}
+				outb_p (0x20, 0x3c0) ;
+
+				/* now set the DAC registers back to their default
+				 * values */
+
+				for (i=0; i<16; i++) {
+					outb_p (color_table[i], 0x3c8) ;
+					outb_p (default_red[i], 0x3c9) ;
+					outb_p (default_grn[i], 0x3c9) ;
+					outb_p (default_blu[i], 0x3c9) ;
+				}
+			}
+		}
+		else
+		{
+			video_type = VIDEO_TYPE_CGA;
+			video_mem_term = 0xba000;
+			display_desc = "*CGA";
+			request_region(0x3d4,2,"cga");
+		}
+	}
+	return kmem_start;
+}
+
+void
+get_scrmem(int currcons)
+{
+	memcpyw((unsigned short *)vc_scrbuf[currcons],
+		(unsigned short *)origin, video_screen_size);
+	__scrollback_mode = 0 ;
+	origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
+	scr_end = video_mem_end = video_mem_start + video_screen_size;
+	pos = origin + y*video_size_row + (x<<1);
+}
+
+void
+set_scrmem(int currcons, long offset)
+{
+#ifdef CONFIG_HGA
+  /* This works with XFree86 1.2, 1.3 and 2.0
+     This code could be extended and made more generally useful if we could
+     determine the actual video mode. It appears that this should be
+     possible on a genuine Hercules card, but I (WM) haven't been able to
+     read from any of the required registers on my clone card.
+     */
+	/* This code should work with Hercules and MDA cards. */
+	if (video_type == VIDEO_TYPE_MDA)
+	  {
+	    if (vcmode == KD_TEXT)
+	      {
+		/* Ensure that the card is in text mode. */
+		int	i;
+		static char herc_txt_tbl[12] = {
+		  0x61,0x50,0x52,0x0f,0x19,6,0x19,0x19,2,0x0d,0x0b,0x0c };
+		outb_p(0, 0x3bf);  /* Back to power-on defaults */
+		outb_p(0, 0x3b8);  /* Blank the screen, select page 0, etc */
+		for ( i = 0 ; i < 12 ; i++ )
+		  {
+		    outb_p(i, 0x3b4);
+		    outb_p(herc_txt_tbl[i], 0x3b5);
+		  }
+	      }
+#define HGA_BLINKER_ON 0x20
+#define HGA_SCREEN_ON  8
+	    /* Make sure that the hardware is not blanked */
+	    outb_p(HGA_BLINKER_ON | HGA_SCREEN_ON, 0x3b8);
+	  }
+#endif CONFIG_HGA
+
+	if (video_mem_term - video_mem_base < offset + video_screen_size)
+	  offset = 0;	/* strange ... */
+	memcpyw((unsigned short *)(video_mem_base + offset),
+		(unsigned short *) origin, video_screen_size);
+	video_mem_start = video_mem_base;
+	video_mem_end = video_mem_term;
+	origin = video_mem_base + offset;
+	scr_end = origin + video_screen_size;
+	pos = origin + y*video_size_row + (x<<1);
+}
+
+/*
+ * PIO_FONT support.
+ *
+ * The font loading code goes back to the codepage package by
+ * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
+ * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
+ * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
+ *
+ * Change for certain monochrome monitors by Yury Shevchuck
+ * (sizif@botik.yaroslavl.su).
+ */
+
+#define colourmap ((char *)0xa0000)
+/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
+   should use 0xA0000 for the bwmap as well.. */
+#define blackwmap ((char *)0xa0000)
+#define cmapsz 8192
+#define attrib_port (0x3c0)
+#define seq_port_reg (0x3c4)
+#define seq_port_val (0x3c5)
+#define gr_port_reg (0x3ce)
+#define gr_port_val (0x3cf)
+
+int
+set_get_font(char * arg, int set, int ch512)
+{
+#ifdef CAN_LOAD_EGA_FONTS
+	int i;
+	char *charmap;
+	int beg;
+	unsigned short video_port_status = video_port_reg + 6;
+	int font_select = 0x00;
+
+	/* no use to "load" CGA... */
+
+	if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_VGAC) {
+		charmap = colourmap;
+		beg = 0x0e;
+#ifdef VGA_CAN_DO_64KB
+		if (video_type == VIDEO_TYPE_VGAC)
+			beg = 0x06;
+#endif
+	} else if (video_type == VIDEO_TYPE_EGAM) {
+		charmap = blackwmap;
+		beg = 0x0a;
+	} else
+		return -EINVAL;
+	
+	if (arg)
+	  {
+	    i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg,
+			    ch512 ? 2*cmapsz : cmapsz);
+	    if (i)
+	      return i;
+	  }
+	else
+	  ch512 = 0;		/* Default font is always 256 */
+
+#ifdef BROKEN_GRAPHICS_PROGRAMS
+	/*
+	 * All fonts are loaded in slot 0 (0:1 for 512 ch)
+	 */
+
+	if (!arg)
+	  return -EINVAL;	/* Return to default font not supported */
+
+	video_font_is_default = 0;
+	font_select = ch512 ? 0x04 : 0x00;
+#else	
+	/*
+	 * The default font is kept in slot 0 and is never touched.
+	 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
+	 */
+
+	if (set)
+	  {
+	    video_font_is_default = !arg;
+	    font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
+	  }
+
+	if ( !video_font_is_default )
+	  charmap += 4*cmapsz;
+#endif
+
+	cli();
+	outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
+	outb_p( 0x01, seq_port_val );   /* Synchronous reset */
+	outb_p( 0x02, seq_port_reg );
+	outb_p( 0x04, seq_port_val );   /* CPU writes only to map 2 */
+	outb_p( 0x04, seq_port_reg );
+	outb_p( 0x07, seq_port_val );   /* Sequential addressing */
+	outb_p( 0x00, seq_port_reg );
+	outb_p( 0x03, seq_port_val );   /* Clear synchronous reset */
+
+	outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
+	outb_p( 0x02, gr_port_val );    /* select map 2 */
+	outb_p( 0x05, gr_port_reg );
+	outb_p( 0x00, gr_port_val );    /* disable odd-even addressing */
+	outb_p( 0x06, gr_port_reg );
+	outb_p( 0x00, gr_port_val );    /* map start at A000:0000 */
+	sti();
+	
+	if (arg)
+	  {
+	    if (set)
+	      for (i=0; i<cmapsz ; i++)
+		scr_writeb(get_user(arg + i), charmap + i);
+	    else
+	      for (i=0; i<cmapsz ; i++)
+		put_user(scr_readb(charmap + i), arg + i);
+	    
+	    
+	/*
+	 * In 512-character mode, the character map is not contiguous if
+	 * we want to remain EGA compatible -- which we do
+	 */
+
+	    if (ch512)
+	      {
+		charmap += 2*cmapsz;
+		arg += cmapsz;
+		if (set)
+		  for (i=0; i<cmapsz ; i++)
+		    *(charmap+i) = get_user(arg+i);
+		else
+		  for (i=0; i<cmapsz ; i++)
+		    put_user(*(charmap+i), arg+i);
+	      }
+	  }
+	
+	cli();
+	outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
+	outb_p( 0x01, seq_port_val );   /* Synchronous reset */
+	outb_p( 0x02, seq_port_reg );
+	outb_p( 0x03, seq_port_val );   /* CPU writes to maps 0 and 1 */
+	outb_p( 0x04, seq_port_reg );
+	outb_p( 0x03, seq_port_val );   /* odd-even addressing */
+	if (set)
+	  {
+	    outb_p( 0x03, seq_port_reg ); /* Character Map Select */
+	    outb_p( font_select, seq_port_val );
+	  }
+	outb_p( 0x00, seq_port_reg );
+	outb_p( 0x03, seq_port_val );   /* clear synchronous reset */
+
+	outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
+	outb_p( 0x00, gr_port_val );    /* select map 0 for CPU */
+	outb_p( 0x05, gr_port_reg );
+	outb_p( 0x10, gr_port_val );    /* enable even-odd addressing */
+	outb_p( 0x06, gr_port_reg );
+	outb_p( beg, gr_port_val );     /* map starts at b800:0 or b000:0 */
+	if (set)			/* attribute controller */
+	  {
+	    /* 256-char: enable intensity bit
+	       512-char: disable intensity bit */
+	    inb_p( video_port_status );	/* clear address flip-flop */
+	    outb_p ( 0x12, attrib_port ); /* color plane enable register */
+	    outb_p ( ch512 ? 0x07 : 0x0f, attrib_port );
+	    /* Wilton (1987) mentions the following; I don't know what
+	       it means, but it works, and it appears necessary */
+	    inb_p( video_port_status );
+	    outb_p ( 0x20, attrib_port );
+	  }
+	sti();
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+/*
+ * Adjust the screen to fit a font of a certain height
+ *
+ * Returns < 0 for error, 0 if nothing changed, and the number
+ * of lines on the adjusted console if changed.
+ */
+int
+con_adjust_height(unsigned long fontheight)
+{
+	int rows, maxscan;
+	unsigned char ovr, vde, fsr, curs, cure;
+
+	if (fontheight > 32 || (video_type != VIDEO_TYPE_VGAC &&
+	    video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM))
+		return -EINVAL;
+
+	if ( fontheight == video_font_height || fontheight == 0 )
+		return 0;
+
+	video_font_height = fontheight;
+
+	rows = video_scan_lines/fontheight;	/* Number of video rows we end up with */
+	maxscan = rows*fontheight - 1;		/* Scan lines to actually display-1 */
+
+	/* Reprogram the CRTC for the new font size
+	   Note: the attempt to read the overflow register will fail
+	   on an EGA, but using 0xff for the previous value appears to
+	   be OK for EGA text modes in the range 257-512 scan lines, so I
+	   guess we don't need to worry about it.
+
+	   The same applies for the spill bits in the font size and cursor
+	   registers; they are write-only on EGA, but it appears that they
+	   are all don't care bits on EGA, so I guess it doesn't matter. */
+
+	cli();
+	outb_p( 0x07, video_port_reg );		/* CRTC overflow register */
+	ovr = inb_p(video_port_val);
+	outb_p( 0x09, video_port_reg );		/* Font size register */
+	fsr = inb_p(video_port_val);
+	outb_p( 0x0a, video_port_reg );		/* Cursor start */
+	curs = inb_p(video_port_val);
+	outb_p( 0x0b, video_port_reg );		/* Cursor end */
+	cure = inb_p(video_port_val);
+	sti();
+
+	vde = maxscan & 0xff;			/* Vertical display end reg */
+	ovr = (ovr & 0xbd) +			/* Overflow register */
+	      ((maxscan & 0x100) >> 7) +
+	      ((maxscan & 0x200) >> 3);
+	fsr = (fsr & 0xe0) + (fontheight-1);    /*  Font size register */
+	curs = (curs & 0xc0) + fontheight - (fontheight < 10 ? 2 : 3);
+	cure = (cure & 0xe0) + fontheight - (fontheight < 10 ? 1 : 2);
+
+	cli();
+	outb_p( 0x07, video_port_reg );		/* CRTC overflow register */
+	outb_p( ovr, video_port_val );
+	outb_p( 0x09, video_port_reg );		/* Font size */
+	outb_p( fsr, video_port_val );
+	outb_p( 0x0a, video_port_reg );		/* Cursor start */
+	outb_p( curs, video_port_val );
+	outb_p( 0x0b, video_port_reg );		/* Cursor end */
+	outb_p( cure, video_port_val );
+	outb_p( 0x12, video_port_reg );		/* Vertical display limit */
+	outb_p( vde, video_port_val );
+	sti();
+
+	if ( rows == video_num_lines ) {
+	  /* Change didn't affect number of lines -- no need to scare
+	     the rest of the world */
+	  return 0;
+	}
+
+	vc_resize(rows, 0);			/* Adjust console size */
+
+	return rows;
+}
+
+int
+set_get_cmap(unsigned char * arg, int set) {
+#ifdef CAN_LOAD_PALETTE
+	int i;
+
+	/* no use to set colourmaps in less than colour VGA */
+
+	if (video_type != VIDEO_TYPE_VGAC)
+		return -EINVAL;
+
+	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
+	if (i)
+		return i;
+
+	for (i=0; i<16; i++) {
+		if (set) {
+			default_red[i] = get_user(arg++) ;
+			default_grn[i] = get_user(arg++) ;
+			default_blu[i] = get_user(arg++) ;
+		} else {
+			put_user (default_red[i], arg++) ;
+			put_user (default_grn[i], arg++) ;
+			put_user (default_blu[i], arg++) ;
+		}
+	}
+	if (set) {
+		for (i=0; i<MAX_NR_CONSOLES; i++)
+			if (vc_cons_allocated(i)) {
+				int j, k ;
+				for (j=k=0; j<16; j++) {
+					vc_cons[i].d->vc_palette[k++] = default_red[j];
+					vc_cons[i].d->vc_palette[k++] = default_grn[j];
+					vc_cons[i].d->vc_palette[k++] = default_blu[j];
+				}
+			}
+		set_palette() ;
+	}
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this