root/drivers/char/vga.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_palette
  2. __set_origin
  3. hide_cursor
  4. set_cursor
  5. con_type_init
  6. get_scrmem
  7. set_scrmem
  8. set_get_font
  9. con_adjust_height
  10. set_get_cmap

   1 /*
   2  *  linux/drivers/char/vga.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  *                      1995  Jay Estabrook
   6  */
   7 
   8 /*
   9  *      vga.c
  10  *
  11  * This module exports the console low-level io support for VGA
  12  *
  13  *     'int con_get_font(char *data)'
  14  *     'int con_set_font(char *data, int ch512)'
  15  *     'int con_adjust_height(int fontheight)'
  16  *
  17  *     'int con_get_cmap(char *)'
  18  *     'int con_set_cmap(char *)'
  19  *
  20  *     'int reset_palette(int currcons)'
  21  *     'void set_palette(void)'
  22  *
  23  * User definable mapping table and font loading by Eugene G. Crosser,
  24  * <crosser@pccross.msk.su>
  25  *
  26  * Improved loadable font/UTF-8 support by H. Peter Anvin 
  27  * Feb-Sep 1995 <peter.anvin@linux.org>
  28  *
  29  * improved scrollback, plus colour palette handling, by Simon Tatham
  30  * 17-Jun-95 <sgt20@cam.ac.uk>
  31  *
  32  */
  33 
  34 #include <linux/sched.h>
  35 #include <linux/timer.h>
  36 #include <linux/interrupt.h>
  37 #include <linux/tty.h>
  38 #include <linux/tty_flip.h>
  39 #include <linux/config.h>
  40 #include <linux/kernel.h>
  41 #include <linux/string.h>
  42 #include <linux/errno.h>
  43 #include <linux/kd.h>
  44 #include <linux/malloc.h>
  45 #include <linux/major.h>
  46 #include <linux/mm.h>
  47 #include <linux/ioport.h>
  48 
  49 #include <asm/io.h>
  50 #include <asm/system.h>
  51 #include <asm/segment.h>
  52 #include <asm/bitops.h>
  53 
  54 #include "kbd_kern.h"
  55 #include "vt_kern.h"
  56 #include "consolemap.h"
  57 #include "selection.h"
  58 #include "console_struct.h"
  59 
  60 #define CAN_LOAD_EGA_FONTS    /* undefine if the user must not do this */
  61 #define CAN_LOAD_PALETTE      /* undefine if the user must not do this */
  62 
  63 #define dac_reg (0x3c8)
  64 #define dac_val (0x3c9)
  65 
  66 
  67 void
  68 set_palette (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70         int i, j ;
  71 
  72         if (video_type != VIDEO_TYPE_VGAC || console_blanked ||
  73             vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
  74                 return ;
  75 
  76         for (i=j=0; i<16; i++) {
  77                 outb_p (color_table[i], dac_reg) ;
  78                 outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
  79                 outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
  80                 outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
  81         }
  82 }
  83 
  84 void
  85 __set_origin(unsigned short offset)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87         unsigned long flags;
  88 
  89         clear_selection();
  90 
  91         save_flags(flags); cli();
  92         __origin = offset;
  93         outb_p(12, video_port_reg);
  94         outb_p(offset >> 8, video_port_val);
  95         outb_p(13, video_port_reg);
  96         outb_p(offset, video_port_val);
  97         restore_flags(flags);
  98 }
  99 
 100 /*
 101  * Put the cursor just beyond the end of the display adaptor memory.
 102  */
 103 void
 104 hide_cursor(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106   /* This is inefficient, we could just put the cursor at 0xffff,
 107      but perhaps the delays due to the inefficiency are useful for
 108      some hardware... */
 109         outb_p(14, video_port_reg);
 110         outb_p(0xff&((video_mem_term-video_mem_base)>>9), video_port_val);
 111         outb_p(15, video_port_reg);
 112         outb_p(0xff&((video_mem_term-video_mem_base)>>1), video_port_val);
 113 }
 114 
 115 void
 116 set_cursor(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 117 {
 118         unsigned long flags;
 119 
 120         if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
 121                 return;
 122         if (__real_origin != __origin)
 123                 __set_origin(__real_origin);
 124         save_flags(flags); cli();
 125         if (deccm) {
 126                 outb_p(14, video_port_reg);
 127                 outb_p(0xff&((pos-video_mem_base)>>9), video_port_val);
 128                 outb_p(15, video_port_reg);
 129                 outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
 130         } else
 131                 hide_cursor();
 132         restore_flags(flags);
 133 }
 134 
 135 unsigned long
 136 con_type_init(unsigned long kmem_start, const char **display_desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138         if (ORIG_VIDEO_MODE == 7)       /* Is this a monochrome display? */
 139         {
 140                 video_mem_base = 0xb0000;
 141                 video_port_reg = 0x3b4;
 142                 video_port_val = 0x3b5;
 143                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
 144                 {
 145                         video_type = VIDEO_TYPE_EGAM;
 146                         video_mem_term = 0xb8000;
 147                         *display_desc = "EGA+";
 148                         request_region(0x3b0,16,"ega");
 149                 }
 150                 else
 151                 {
 152                         video_type = VIDEO_TYPE_MDA;
 153                         video_mem_term = 0xb2000;
 154                         *display_desc = "*MDA";
 155                         request_region(0x3b0,12,"mda");
 156                         request_region(0x3bf, 1,"mda");
 157                 }
 158         }
 159         else                            /* If not, it is color. */
 160         {
 161                 can_do_color = 1;
 162                 video_mem_base = 0xb8000;
 163                 video_port_reg  = 0x3d4;
 164                 video_port_val  = 0x3d5;
 165                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
 166                 {
 167                         int i ;
 168 
 169                         video_mem_term = 0xc0000;
 170 
 171                         if (!ORIG_VIDEO_ISVGA) {
 172                                 video_type = VIDEO_TYPE_EGAC;
 173                                 *display_desc = "EGA";
 174                                 request_region(0x3c0,32,"ega");
 175                         } else {
 176                                 video_type = VIDEO_TYPE_VGAC;
 177                                 *display_desc = "VGA+";
 178                                 request_region(0x3c0,32,"vga+");
 179 
 180 #ifdef VGA_CAN_DO_64KB
 181                                 /*
 182                                  * get 64K rather than 32K of video RAM.
 183                                  * This doesn't actually work on all "VGA"
 184                                  * controllers (it seems like setting MM=01
 185                                  * and COE=1 isn't necessarily a good idea)
 186                                  */
 187                                 video_mem_base = 0xa0000 ;
 188                                 video_mem_term = 0xb0000 ;
 189                                 outb_p (6, 0x3ce) ;
 190                                 outb_p (6, 0x3cf) ;
 191 #endif
 192 
 193                                 /* normalise the palette registers, to point the
 194                                  * 16 screen colours to the first 16 DAC entries */
 195 
 196                                 for (i=0; i<16; i++) {
 197                                         inb_p (0x3da) ;
 198                                         outb_p (i, 0x3c0) ;
 199                                         outb_p (i, 0x3c0) ;
 200                                 }
 201                                 outb_p (0x20, 0x3c0) ;
 202 
 203                                 /* now set the DAC registers back to their default
 204                                  * values */
 205 
 206                                 for (i=0; i<16; i++) {
 207                                         outb_p (color_table[i], 0x3c8) ;
 208                                         outb_p (default_red[i], 0x3c9) ;
 209                                         outb_p (default_grn[i], 0x3c9) ;
 210                                         outb_p (default_blu[i], 0x3c9) ;
 211                                 }
 212                         }
 213                 }
 214                 else
 215                 {
 216                         video_type = VIDEO_TYPE_CGA;
 217                         video_mem_term = 0xba000;
 218                         *display_desc = "*CGA";
 219                         request_region(0x3d4,2,"cga");
 220                 }
 221         }
 222         return kmem_start;
 223 }
 224 
 225 void
 226 get_scrmem(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228         memcpyw((unsigned short *)vc_scrbuf[currcons],
 229                 (unsigned short *)origin, video_screen_size);
 230         __scrollback_mode = 0 ;
 231         origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
 232         scr_end = video_mem_end = video_mem_start + video_screen_size;
 233         pos = origin + y*video_size_row + (x<<1);
 234 }
 235 
 236 void
 237 set_scrmem(int currcons, long offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 238 {
 239 #ifdef CONFIG_HGA
 240   /* This works with XFree86 1.2, 1.3 and 2.0
 241      This code could be extended and made more generally useful if we could
 242      determine the actual video mode. It appears that this should be
 243      possible on a genuine Hercules card, but I (WM) haven't been able to
 244      read from any of the required registers on my clone card.
 245      */
 246         /* This code should work with Hercules and MDA cards. */
 247         if (video_type == VIDEO_TYPE_MDA)
 248           {
 249             if (vcmode == KD_TEXT)
 250               {
 251                 /* Ensure that the card is in text mode. */
 252                 int     i;
 253                 static char herc_txt_tbl[12] = {
 254                   0x61,0x50,0x52,0x0f,0x19,6,0x19,0x19,2,0x0d,0x0b,0x0c };
 255                 outb_p(0, 0x3bf);  /* Back to power-on defaults */
 256                 outb_p(0, 0x3b8);  /* Blank the screen, select page 0, etc */
 257                 for ( i = 0 ; i < 12 ; i++ )
 258                   {
 259                     outb_p(i, 0x3b4);
 260                     outb_p(herc_txt_tbl[i], 0x3b5);
 261                   }
 262               }
 263 #define HGA_BLINKER_ON 0x20
 264 #define HGA_SCREEN_ON  8
 265             /* Make sure that the hardware is not blanked */
 266             outb_p(HGA_BLINKER_ON | HGA_SCREEN_ON, 0x3b8);
 267           }
 268 #endif CONFIG_HGA
 269 
 270         if (video_mem_term - video_mem_base < offset + video_screen_size)
 271           offset = 0;   /* strange ... */
 272         memcpyw((unsigned short *)(video_mem_base + offset),
 273                 (unsigned short *) origin, video_screen_size);
 274         video_mem_start = video_mem_base;
 275         video_mem_end = video_mem_term;
 276         origin = video_mem_base + offset;
 277         scr_end = origin + video_screen_size;
 278         pos = origin + y*video_size_row + (x<<1);
 279 }
 280 
 281 /*
 282  * PIO_FONT support.
 283  *
 284  * The font loading code goes back to the codepage package by
 285  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
 286  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
 287  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
 288  *
 289  * Change for certain monochrome monitors by Yury Shevchuck
 290  * (sizif@botik.yaroslavl.su).
 291  */
 292 
 293 #define colourmap ((char *)0xa0000)
 294 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
 295    should use 0xA0000 for the bwmap as well.. */
 296 #define blackwmap ((char *)0xa0000)
 297 #define cmapsz 8192
 298 #define attrib_port (0x3c0)
 299 #define seq_port_reg (0x3c4)
 300 #define seq_port_val (0x3c5)
 301 #define gr_port_reg (0x3ce)
 302 #define gr_port_val (0x3cf)
 303 
 304 int
 305 set_get_font(char * arg, int set, int ch512)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307 #ifdef CAN_LOAD_EGA_FONTS
 308         int i;
 309         char *charmap;
 310         int beg;
 311         unsigned short video_port_status = video_port_reg + 6;
 312         int font_select = 0x00;
 313 
 314         /* no use to "load" CGA... */
 315 
 316         if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_VGAC) {
 317                 charmap = colourmap;
 318                 beg = 0x0e;
 319 #ifdef VGA_CAN_DO_64KB
 320                 if (video_type == VIDEO_TYPE_VGAC)
 321                         beg = 0x06;
 322 #endif
 323         } else if (video_type == VIDEO_TYPE_EGAM) {
 324                 charmap = blackwmap;
 325                 beg = 0x0a;
 326         } else
 327                 return -EINVAL;
 328         
 329         if (arg)
 330           {
 331             i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg,
 332                             ch512 ? 2*cmapsz : cmapsz);
 333             if (i)
 334               return i;
 335           }
 336         else
 337           ch512 = 0;            /* Default font is always 256 */
 338 
 339 #ifdef BROKEN_GRAPHICS_PROGRAMS
 340         /*
 341          * All fonts are loaded in slot 0 (0:1 for 512 ch)
 342          */
 343 
 344         if (!arg)
 345           return -EINVAL;       /* Return to default font not supported */
 346 
 347         video_font_is_default = 0;
 348         font_select = ch512 ? 0x04 : 0x00;
 349 #else   
 350         /*
 351          * The default font is kept in slot 0 and is never touched.
 352          * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
 353          */
 354 
 355         if (set)
 356           {
 357             video_font_is_default = !arg;
 358             font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
 359           }
 360 
 361         if ( !video_font_is_default )
 362           charmap += 4*cmapsz;
 363 #endif
 364 
 365         cli();
 366         outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
 367         outb_p( 0x01, seq_port_val );   /* Synchronous reset */
 368         outb_p( 0x02, seq_port_reg );
 369         outb_p( 0x04, seq_port_val );   /* CPU writes only to map 2 */
 370         outb_p( 0x04, seq_port_reg );
 371         outb_p( 0x07, seq_port_val );   /* Sequential addressing */
 372         outb_p( 0x00, seq_port_reg );
 373         outb_p( 0x03, seq_port_val );   /* Clear synchronous reset */
 374 
 375         outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
 376         outb_p( 0x02, gr_port_val );    /* select map 2 */
 377         outb_p( 0x05, gr_port_reg );
 378         outb_p( 0x00, gr_port_val );    /* disable odd-even addressing */
 379         outb_p( 0x06, gr_port_reg );
 380         outb_p( 0x00, gr_port_val );    /* map start at A000:0000 */
 381         sti();
 382         
 383         if (arg)
 384           {
 385             if (set)
 386               for (i=0; i<cmapsz ; i++)
 387                 scr_writeb(get_user(arg + i), charmap + i);
 388             else
 389               for (i=0; i<cmapsz ; i++)
 390                 put_user(scr_readb(charmap + i), arg + i);
 391             
 392             
 393         /*
 394          * In 512-character mode, the character map is not contiguous if
 395          * we want to remain EGA compatible -- which we do
 396          */
 397 
 398             if (ch512)
 399               {
 400                 charmap += 2*cmapsz;
 401                 arg += cmapsz;
 402                 if (set)
 403                   for (i=0; i<cmapsz ; i++)
 404                     *(charmap+i) = get_user(arg+i);
 405                 else
 406                   for (i=0; i<cmapsz ; i++)
 407                     put_user(*(charmap+i), arg+i);
 408               }
 409           }
 410         
 411         cli();
 412         outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
 413         outb_p( 0x01, seq_port_val );   /* Synchronous reset */
 414         outb_p( 0x02, seq_port_reg );
 415         outb_p( 0x03, seq_port_val );   /* CPU writes to maps 0 and 1 */
 416         outb_p( 0x04, seq_port_reg );
 417         outb_p( 0x03, seq_port_val );   /* odd-even addressing */
 418         if (set)
 419           {
 420             outb_p( 0x03, seq_port_reg ); /* Character Map Select */
 421             outb_p( font_select, seq_port_val );
 422           }
 423         outb_p( 0x00, seq_port_reg );
 424         outb_p( 0x03, seq_port_val );   /* clear synchronous reset */
 425 
 426         outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
 427         outb_p( 0x00, gr_port_val );    /* select map 0 for CPU */
 428         outb_p( 0x05, gr_port_reg );
 429         outb_p( 0x10, gr_port_val );    /* enable even-odd addressing */
 430         outb_p( 0x06, gr_port_reg );
 431         outb_p( beg, gr_port_val );     /* map starts at b800:0 or b000:0 */
 432         if (set)                        /* attribute controller */
 433           {
 434             /* 256-char: enable intensity bit
 435                512-char: disable intensity bit */
 436             inb_p( video_port_status ); /* clear address flip-flop */
 437             outb_p ( 0x12, attrib_port ); /* color plane enable register */
 438             outb_p ( ch512 ? 0x07 : 0x0f, attrib_port );
 439             /* Wilton (1987) mentions the following; I don't know what
 440                it means, but it works, and it appears necessary */
 441             inb_p( video_port_status );
 442             outb_p ( 0x20, attrib_port );
 443           }
 444         sti();
 445 
 446         return 0;
 447 #else
 448         return -EINVAL;
 449 #endif
 450 }
 451 
 452 /*
 453  * Adjust the screen to fit a font of a certain height
 454  *
 455  * Returns < 0 for error, 0 if nothing changed, and the number
 456  * of lines on the adjusted console if changed.
 457  */
 458 int
 459 con_adjust_height(unsigned long fontheight)
     /* [previous][next][first][last][top][bottom][index][help] */
 460 {
 461         int rows, maxscan;
 462         unsigned char ovr, vde, fsr, curs, cure;
 463 
 464         if (fontheight > 32 || (video_type != VIDEO_TYPE_VGAC &&
 465             video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM))
 466                 return -EINVAL;
 467 
 468         if ( fontheight == video_font_height || fontheight == 0 )
 469                 return 0;
 470 
 471         video_font_height = fontheight;
 472 
 473         rows = video_scan_lines/fontheight;     /* Number of video rows we end up with */
 474         maxscan = rows*fontheight - 1;          /* Scan lines to actually display-1 */
 475 
 476         /* Reprogram the CRTC for the new font size
 477            Note: the attempt to read the overflow register will fail
 478            on an EGA, but using 0xff for the previous value appears to
 479            be OK for EGA text modes in the range 257-512 scan lines, so I
 480            guess we don't need to worry about it.
 481 
 482            The same applies for the spill bits in the font size and cursor
 483            registers; they are write-only on EGA, but it appears that they
 484            are all don't care bits on EGA, so I guess it doesn't matter. */
 485 
 486         cli();
 487         outb_p( 0x07, video_port_reg );         /* CRTC overflow register */
 488         ovr = inb_p(video_port_val);
 489         outb_p( 0x09, video_port_reg );         /* Font size register */
 490         fsr = inb_p(video_port_val);
 491         outb_p( 0x0a, video_port_reg );         /* Cursor start */
 492         curs = inb_p(video_port_val);
 493         outb_p( 0x0b, video_port_reg );         /* Cursor end */
 494         cure = inb_p(video_port_val);
 495         sti();
 496 
 497         vde = maxscan & 0xff;                   /* Vertical display end reg */
 498         ovr = (ovr & 0xbd) +                    /* Overflow register */
 499               ((maxscan & 0x100) >> 7) +
 500               ((maxscan & 0x200) >> 3);
 501         fsr = (fsr & 0xe0) + (fontheight-1);    /*  Font size register */
 502         curs = (curs & 0xc0) + fontheight - (fontheight < 10 ? 2 : 3);
 503         cure = (cure & 0xe0) + fontheight - (fontheight < 10 ? 1 : 2);
 504 
 505         cli();
 506         outb_p( 0x07, video_port_reg );         /* CRTC overflow register */
 507         outb_p( ovr, video_port_val );
 508         outb_p( 0x09, video_port_reg );         /* Font size */
 509         outb_p( fsr, video_port_val );
 510         outb_p( 0x0a, video_port_reg );         /* Cursor start */
 511         outb_p( curs, video_port_val );
 512         outb_p( 0x0b, video_port_reg );         /* Cursor end */
 513         outb_p( cure, video_port_val );
 514         outb_p( 0x12, video_port_reg );         /* Vertical display limit */
 515         outb_p( vde, video_port_val );
 516         sti();
 517 
 518         if ( rows == video_num_lines ) {
 519           /* Change didn't affect number of lines -- no need to scare
 520              the rest of the world */
 521           return 0;
 522         }
 523 
 524         vc_resize(rows, 0);                     /* Adjust console size */
 525 
 526         return rows;
 527 }
 528 
 529 int
 530 set_get_cmap(unsigned char * arg, int set) {
     /* [previous][next][first][last][top][bottom][index][help] */
 531 #ifdef CAN_LOAD_PALETTE
 532         int i;
 533 
 534         /* no use to set colourmaps in less than colour VGA */
 535 
 536         if (video_type != VIDEO_TYPE_VGAC)
 537                 return -EINVAL;
 538 
 539         i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
 540         if (i)
 541                 return i;
 542 
 543         for (i=0; i<16; i++) {
 544                 if (set) {
 545                         default_red[i] = get_user(arg++) ;
 546                         default_grn[i] = get_user(arg++) ;
 547                         default_blu[i] = get_user(arg++) ;
 548                 } else {
 549                         put_user (default_red[i], arg++) ;
 550                         put_user (default_grn[i], arg++) ;
 551                         put_user (default_blu[i], arg++) ;
 552                 }
 553         }
 554         if (set) {
 555                 for (i=0; i<MAX_NR_CONSOLES; i++)
 556                         if (vc_cons_allocated(i)) {
 557                                 int j, k ;
 558                                 for (j=k=0; j<16; j++) {
 559                                         vc_cons[i].d->vc_palette[k++] = default_red[j];
 560                                         vc_cons[i].d->vc_palette[k++] = default_grn[j];
 561                                         vc_cons[i].d->vc_palette[k++] = default_blu[j];
 562                                 }
 563                         }
 564                 set_palette() ;
 565         }
 566 
 567         return 0;
 568 #else
 569         return -EINVAL;
 570 #endif
 571 }

/* [previous][next][first][last][top][bottom][index][help] */