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  * 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                                 /*
 194                                  * Normalise the palette registers, to point
 195                                  * the 16 screen colours to the first 16
 196                                  * DAC entries.
 197                                  */
 198 
 199                                 for (i=0; i<16; i++) {
 200                                         inb_p (0x3da) ;
 201                                         outb_p (i, 0x3c0) ;
 202                                         outb_p (i, 0x3c0) ;
 203                                 }
 204                                 outb_p (0x20, 0x3c0) ;
 205 
 206                                 /* now set the DAC registers back to their
 207                                  * default values */
 208 
 209                                 for (i=0; i<16; i++) {
 210                                         outb_p (color_table[i], 0x3c8) ;
 211                                         outb_p (default_red[i], 0x3c9) ;
 212                                         outb_p (default_grn[i], 0x3c9) ;
 213                                         outb_p (default_blu[i], 0x3c9) ;
 214                                 }
 215                         }
 216                 }
 217                 else
 218                 {
 219                         video_type = VIDEO_TYPE_CGA;
 220                         video_mem_term = 0xba000;
 221                         *display_desc = "*CGA";
 222                         request_region(0x3d4,2,"cga");
 223                 }
 224         }
 225         return kmem_start;
 226 }
 227 
 228 void
 229 get_scrmem(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 230 {
 231         memcpyw((unsigned short *)vc_scrbuf[currcons],
 232                 (unsigned short *)origin, video_screen_size);
 233         origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
 234         scr_end = video_mem_end = video_mem_start + video_screen_size;
 235         pos = origin + y*video_size_row + (x<<1);
 236 }
 237 
 238 void
 239 set_scrmem(int currcons, long offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {
 241 #ifdef CONFIG_HGA
 242   /* This works with XFree86 1.2, 1.3 and 2.0
 243      This code could be extended and made more generally useful if we could
 244      determine the actual video mode. It appears that this should be
 245      possible on a genuine Hercules card, but I (WM) haven't been able to
 246      read from any of the required registers on my clone card.
 247      */
 248         /* This code should work with Hercules and MDA cards. */
 249         if (video_type == VIDEO_TYPE_MDA)
 250           {
 251             if (vcmode == KD_TEXT)
 252               {
 253                 /* Ensure that the card is in text mode. */
 254                 int     i;
 255                 static char herc_txt_tbl[12] = {
 256                   0x61,0x50,0x52,0x0f,0x19,6,0x19,0x19,2,0x0d,0x0b,0x0c };
 257                 outb_p(0, 0x3bf);  /* Back to power-on defaults */
 258                 outb_p(0, 0x3b8);  /* Blank the screen, select page 0, etc */
 259                 for ( i = 0 ; i < 12 ; i++ )
 260                   {
 261                     outb_p(i, 0x3b4);
 262                     outb_p(herc_txt_tbl[i], 0x3b5);
 263                   }
 264               }
 265 #define HGA_BLINKER_ON 0x20
 266 #define HGA_SCREEN_ON  8
 267             /* Make sure that the hardware is not blanked */
 268             outb_p(HGA_BLINKER_ON | HGA_SCREEN_ON, 0x3b8);
 269           }
 270 #endif CONFIG_HGA
 271 
 272         if (video_mem_term - video_mem_base < offset + video_screen_size)
 273           offset = 0;   /* strange ... */
 274         memcpyw((unsigned short *)(video_mem_base + offset),
 275                 (unsigned short *) origin, video_screen_size);
 276         video_mem_start = video_mem_base;
 277         video_mem_end = video_mem_term;
 278         origin = video_mem_base + offset;
 279         scr_end = origin + video_screen_size;
 280         pos = origin + y*video_size_row + (x<<1);
 281         has_wrapped = 0;
 282 }
 283 
 284 /*
 285  * PIO_FONT support.
 286  *
 287  * The font loading code goes back to the codepage package by
 288  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
 289  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
 290  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
 291  *
 292  * Change for certain monochrome monitors by Yury Shevchuck
 293  * (sizif@botik.yaroslavl.su).
 294  */
 295 
 296 #define colourmap ((char *)0xa0000)
 297 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
 298    should use 0xA0000 for the bwmap as well.. */
 299 #define blackwmap ((char *)0xa0000)
 300 #define cmapsz 8192
 301 #define attrib_port (0x3c0)
 302 #define seq_port_reg (0x3c4)
 303 #define seq_port_val (0x3c5)
 304 #define gr_port_reg (0x3ce)
 305 #define gr_port_val (0x3cf)
 306 
 307 int
 308 set_get_font(char * arg, int set, int ch512)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310 #ifdef CAN_LOAD_EGA_FONTS
 311         int i;
 312         char *charmap;
 313         int beg;
 314         unsigned short video_port_status = video_port_reg + 6;
 315         int font_select = 0x00;
 316 
 317         /* no use to "load" CGA... */
 318 
 319         if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_VGAC) {
 320                 charmap = colourmap;
 321                 beg = 0x0e;
 322 #ifdef VGA_CAN_DO_64KB
 323                 if (video_type == VIDEO_TYPE_VGAC)
 324                         beg = 0x06;
 325 #endif
 326         } else if (video_type == VIDEO_TYPE_EGAM) {
 327                 charmap = blackwmap;
 328                 beg = 0x0a;
 329         } else
 330                 return -EINVAL;
 331         
 332         if (arg)
 333           {
 334             i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg,
 335                             ch512 ? 2*cmapsz : cmapsz);
 336             if (i)
 337               return i;
 338           }
 339         else
 340           ch512 = 0;            /* Default font is always 256 */
 341 
 342 #ifdef BROKEN_GRAPHICS_PROGRAMS
 343         /*
 344          * All fonts are loaded in slot 0 (0:1 for 512 ch)
 345          */
 346 
 347         if (!arg)
 348           return -EINVAL;       /* Return to default font not supported */
 349 
 350         video_font_is_default = 0;
 351         font_select = ch512 ? 0x04 : 0x00;
 352 #else   
 353         /*
 354          * The default font is kept in slot 0 and is never touched.
 355          * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
 356          */
 357 
 358         if (set)
 359           {
 360             video_font_is_default = !arg;
 361             font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
 362           }
 363 
 364         if ( !video_font_is_default )
 365           charmap += 4*cmapsz;
 366 #endif
 367 
 368         cli();
 369         outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
 370         outb_p( 0x01, seq_port_val );   /* Synchronous reset */
 371         outb_p( 0x02, seq_port_reg );
 372         outb_p( 0x04, seq_port_val );   /* CPU writes only to map 2 */
 373         outb_p( 0x04, seq_port_reg );
 374         outb_p( 0x07, seq_port_val );   /* Sequential addressing */
 375         outb_p( 0x00, seq_port_reg );
 376         outb_p( 0x03, seq_port_val );   /* Clear synchronous reset */
 377 
 378         outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
 379         outb_p( 0x02, gr_port_val );    /* select map 2 */
 380         outb_p( 0x05, gr_port_reg );
 381         outb_p( 0x00, gr_port_val );    /* disable odd-even addressing */
 382         outb_p( 0x06, gr_port_reg );
 383         outb_p( 0x00, gr_port_val );    /* map start at A000:0000 */
 384         sti();
 385         
 386         if (arg)
 387           {
 388             if (set)
 389               for (i=0; i<cmapsz ; i++)
 390                 scr_writeb(get_user(arg + i), charmap + i);
 391             else
 392               for (i=0; i<cmapsz ; i++)
 393                 put_user(scr_readb(charmap + i), arg + i);
 394             
 395             
 396         /*
 397          * In 512-character mode, the character map is not contiguous if
 398          * we want to remain EGA compatible -- which we do
 399          */
 400 
 401             if (ch512)
 402               {
 403                 charmap += 2*cmapsz;
 404                 arg += cmapsz;
 405                 if (set)
 406                   for (i=0; i<cmapsz ; i++)
 407                     *(charmap+i) = get_user(arg+i);
 408                 else
 409                   for (i=0; i<cmapsz ; i++)
 410                     put_user(*(charmap+i), arg+i);
 411               }
 412           }
 413         
 414         cli();
 415         outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
 416         outb_p( 0x01, seq_port_val );   /* Synchronous reset */
 417         outb_p( 0x02, seq_port_reg );
 418         outb_p( 0x03, seq_port_val );   /* CPU writes to maps 0 and 1 */
 419         outb_p( 0x04, seq_port_reg );
 420         outb_p( 0x03, seq_port_val );   /* odd-even addressing */
 421         if (set)
 422           {
 423             outb_p( 0x03, seq_port_reg ); /* Character Map Select */
 424             outb_p( font_select, seq_port_val );
 425           }
 426         outb_p( 0x00, seq_port_reg );
 427         outb_p( 0x03, seq_port_val );   /* clear synchronous reset */
 428 
 429         outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
 430         outb_p( 0x00, gr_port_val );    /* select map 0 for CPU */
 431         outb_p( 0x05, gr_port_reg );
 432         outb_p( 0x10, gr_port_val );    /* enable even-odd addressing */
 433         outb_p( 0x06, gr_port_reg );
 434         outb_p( beg, gr_port_val );     /* map starts at b800:0 or b000:0 */
 435         if (set)                        /* attribute controller */
 436           {
 437             /* 256-char: enable intensity bit
 438                512-char: disable intensity bit */
 439             inb_p( video_port_status ); /* clear address flip-flop */
 440             outb_p ( 0x12, attrib_port ); /* color plane enable register */
 441             outb_p ( ch512 ? 0x07 : 0x0f, attrib_port );
 442             /* Wilton (1987) mentions the following; I don't know what
 443                it means, but it works, and it appears necessary */
 444             inb_p( video_port_status );
 445             outb_p ( 0x20, attrib_port );
 446           }
 447         sti();
 448 
 449         return 0;
 450 #else
 451         return -EINVAL;
 452 #endif
 453 }
 454 
 455 /*
 456  * Adjust the screen to fit a font of a certain height
 457  *
 458  * Returns < 0 for error, 0 if nothing changed, and the number
 459  * of lines on the adjusted console if changed.
 460  */
 461 int
 462 con_adjust_height(unsigned long fontheight)
     /* [previous][next][first][last][top][bottom][index][help] */
 463 {
 464         int rows, maxscan;
 465         unsigned char ovr, vde, fsr, curs, cure;
 466 
 467         if (fontheight > 32 || (video_type != VIDEO_TYPE_VGAC &&
 468             video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM))
 469                 return -EINVAL;
 470 
 471         if ( fontheight == video_font_height || fontheight == 0 )
 472                 return 0;
 473 
 474         video_font_height = fontheight;
 475 
 476         rows = video_scan_lines/fontheight;     /* Number of video rows we end up with */
 477         maxscan = rows*fontheight - 1;          /* Scan lines to actually display-1 */
 478 
 479         /* Reprogram the CRTC for the new font size
 480            Note: the attempt to read the overflow register will fail
 481            on an EGA, but using 0xff for the previous value appears to
 482            be OK for EGA text modes in the range 257-512 scan lines, so I
 483            guess we don't need to worry about it.
 484 
 485            The same applies for the spill bits in the font size and cursor
 486            registers; they are write-only on EGA, but it appears that they
 487            are all don't care bits on EGA, so I guess it doesn't matter. */
 488 
 489         cli();
 490         outb_p( 0x07, video_port_reg );         /* CRTC overflow register */
 491         ovr = inb_p(video_port_val);
 492         outb_p( 0x09, video_port_reg );         /* Font size register */
 493         fsr = inb_p(video_port_val);
 494         outb_p( 0x0a, video_port_reg );         /* Cursor start */
 495         curs = inb_p(video_port_val);
 496         outb_p( 0x0b, video_port_reg );         /* Cursor end */
 497         cure = inb_p(video_port_val);
 498         sti();
 499 
 500         vde = maxscan & 0xff;                   /* Vertical display end reg */
 501         ovr = (ovr & 0xbd) +                    /* Overflow register */
 502               ((maxscan & 0x100) >> 7) +
 503               ((maxscan & 0x200) >> 3);
 504         fsr = (fsr & 0xe0) + (fontheight-1);    /*  Font size register */
 505         curs = (curs & 0xc0) + fontheight - (fontheight < 10 ? 2 : 3);
 506         cure = (cure & 0xe0) + fontheight - (fontheight < 10 ? 1 : 2);
 507 
 508         cli();
 509         outb_p( 0x07, video_port_reg );         /* CRTC overflow register */
 510         outb_p( ovr, video_port_val );
 511         outb_p( 0x09, video_port_reg );         /* Font size */
 512         outb_p( fsr, video_port_val );
 513         outb_p( 0x0a, video_port_reg );         /* Cursor start */
 514         outb_p( curs, video_port_val );
 515         outb_p( 0x0b, video_port_reg );         /* Cursor end */
 516         outb_p( cure, video_port_val );
 517         outb_p( 0x12, video_port_reg );         /* Vertical display limit */
 518         outb_p( vde, video_port_val );
 519         sti();
 520 
 521         if ( rows == video_num_lines ) {
 522           /* Change didn't affect number of lines -- no need to scare
 523              the rest of the world */
 524           return 0;
 525         }
 526 
 527         vc_resize(rows, 0);                     /* Adjust console size */
 528 
 529         return rows;
 530 }
 531 
 532 int
 533 set_get_cmap(unsigned char * arg, int set) {
     /* [previous][next][first][last][top][bottom][index][help] */
 534 #ifdef CAN_LOAD_PALETTE
 535         int i;
 536 
 537         /* no use to set colourmaps in less than colour VGA */
 538 
 539         if (video_type != VIDEO_TYPE_VGAC)
 540                 return -EINVAL;
 541 
 542         i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
 543         if (i)
 544                 return i;
 545 
 546         for (i=0; i<16; i++) {
 547                 if (set) {
 548                         default_red[i] = get_user(arg++) ;
 549                         default_grn[i] = get_user(arg++) ;
 550                         default_blu[i] = get_user(arg++) ;
 551                 } else {
 552                         put_user (default_red[i], arg++) ;
 553                         put_user (default_grn[i], arg++) ;
 554                         put_user (default_blu[i], arg++) ;
 555                 }
 556         }
 557         if (set) {
 558                 for (i=0; i<MAX_NR_CONSOLES; i++)
 559                         if (vc_cons_allocated(i)) {
 560                                 int j, k ;
 561                                 for (j=k=0; j<16; j++) {
 562                                         vc_cons[i].d->vc_palette[k++] = default_red[j];
 563                                         vc_cons[i].d->vc_palette[k++] = default_grn[j];
 564                                         vc_cons[i].d->vc_palette[k++] = default_blu[j];
 565                                 }
 566                         }
 567                 set_palette() ;
 568         }
 569 
 570         return 0;
 571 #else
 572         return -EINVAL;
 573 #endif
 574 }

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