1 /* Copyright (C) 1991, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved. 2 3 This file is part of AFPL Ghostscript. 4 5 AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or 6 distributor accepts any responsibility for the consequences of using it, or 7 for whether it serves any particular purpose or works at all, unless he or 8 she says so in writing. Refer to the Aladdin Free Public License (the 9 "License") for full details. 10 11 Every copy of AFPL Ghostscript must include a copy of the License, normally 12 in a plain ASCII text file named PUBLIC. The License grants you the right 13 to copy, modify and redistribute AFPL Ghostscript, but only under certain 14 conditions described in the License. Among other things, the License 15 requires that the copyright notice and this notice be preserved on all 16 copies. 17 */ 18 19 /*$Id: gdevsvga.c,v 1.2 2000/09/19 19:00:23 lpd Exp $ */ 20 /* SuperVGA display drivers */ 21 #include "memory_.h" 22 #include "gconfigv.h" /* for USE_ASM */ 23 #include "gx.h" 24 #include "gserrors.h" 25 #include "gxarith.h" /* for ...log2 */ 26 #include "gxdevice.h" 27 #include "gdevpccm.h" 28 #include "gdevpcfb.h" 29 #include "gdevsvga.h" 30 #include "gsparam.h" 31 32 /* The color map for dynamically assignable colors. */ 33 #define first_dc_index 64 34 private int next_dc_index; 35 36 #define dc_hash_size 293 /* prime, >num_dc */ 37 typedef struct { 38 ushort rgb, index; 39 } dc_entry; 40 private dc_entry dynamic_colors[dc_hash_size + 1]; 41 42 #define num_colors 255 43 44 /* Macro for casting gx_device argument */ 45 #define fb_dev ((gx_device_svga *)dev) 46 47 /* Procedure records */ 48 #define svga_procs(open) {\ 49 open, NULL /*get_initial_matrix*/,\ 50 NULL /*sync_output*/, NULL /*output_page*/, svga_close,\ 51 svga_map_rgb_color, svga_map_color_rgb,\ 52 svga_fill_rectangle, NULL /*tile_rectangle*/,\ 53 svga_copy_mono, svga_copy_color, NULL /*draw_line*/,\ 54 svga_get_bits, NULL /*get_params*/, svga_put_params,\ 55 NULL /*map_cmyk_color*/, NULL /*get_xfont_procs*/,\ 56 NULL /*get_xfont_device*/, NULL /*map_rgb_alpha_color*/,\ 57 gx_page_device_get_page_device, NULL /*get_alpha_bits*/,\ 58 svga_copy_alpha\ 59 } 60 61 /* Save the controller mode */ 62 private int svga_save_mode = -1; 63 64 /* ------ Internal routines ------ */ 65 66 #define regen 0xa000 67 68 /* Construct a pointer for writing a pixel. */ 69 /* Assume 64K pages, 64K granularity. */ 70 /* We know that y is within bounds. */ 71 #define set_pixel_ptr(ptr, fbdev, x, y, wnum)\ 72 { ulong index = (ulong)(y) * fbdev->raster + (uint)(x);\ 73 if ( (uint)(index >> 16) != fbdev->current_page )\ 74 { (*fbdev->set_page)(fbdev, (fbdev->current_page = index >> 16), wnum);\ 75 }\ 76 ptr = (fb_ptr)MK_PTR(regen, (ushort)index);\ 77 } 78 #define set_pixel_write_ptr(ptr, fbdev, x, y)\ 79 set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_write) 80 #define set_pixel_read_ptr(ptr, fbdev, x, y)\ 81 set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_read) 82 83 /* Find the graphics mode for a desired width and height. */ 84 /* Set the mode in the device structure and return 0, */ 85 /* or return an error code. */ 86 int 87 svga_find_mode(gx_device * dev, const mode_info * mip) 88 { 89 for (;; mip++) { 90 if (mip->width >= fb_dev->width && 91 mip->height >= fb_dev->height || 92 mip[1].mode < 0 93 ) { 94 fb_dev->mode = mip; 95 gx_device_adjust_resolution(dev, mip->width, mip->height, 1); 96 fb_dev->raster = fb_dev->width; 97 return 0; 98 } 99 } 100 return_error(gs_error_rangecheck); 101 } 102 103 /* Set the index for writing into the color DAC. */ 104 #define svga_dac_set_write_index(i) outportb(0x3c8, i) 105 106 /* Write 6-bit R,G,B values into the color DAC. */ 107 #define svga_dac_write(r, g, b)\ 108 (outportb(0x3c9, r), outportb(0x3c9, g), outportb(0x3c9, b)) 109 110 /* ------ Common procedures ------ */ 111 112 #define cv_bits(v,n) (v >> (gx_color_value_bits - n)) 113 114 /* Initialize the dynamic color table, if any. */ 115 void 116 svga_init_colors(gx_device * dev) 117 { 118 if (fb_dev->fixed_colors) 119 next_dc_index = num_colors; 120 else { 121 memset(dynamic_colors, 0, 122 (dc_hash_size + 1) * sizeof(dc_entry)); 123 next_dc_index = first_dc_index; 124 } 125 } 126 127 /* Load the color DAC with the predefined colors. */ 128 private void 129 svga_load_colors(gx_device * dev) 130 { 131 int ci; 132 133 svga_dac_set_write_index(0); 134 if (fb_dev->fixed_colors) 135 for (ci = 0; ci < num_colors; ci++) { 136 gx_color_value rgb[3]; 137 138 pc_8bit_map_color_rgb(dev, (gx_color_index) ci, rgb); 139 svga_dac_write(cv_bits(rgb[0], 6), cv_bits(rgb[1], 6), 140 cv_bits(rgb[2], 6)); 141 } else 142 for (ci = 0; ci < 64; ci++) { 143 static const byte c2[10] = 144 {0, 42, 0, 0, 0, 0, 0, 0, 21, 63}; 145 146 svga_dac_write(c2[(ci >> 2) & 9], c2[(ci >> 1) & 9], 147 c2[ci & 9]); 148 } 149 } 150 151 /* Initialize the device structure and the DACs. */ 152 int 153 svga_open(gx_device * dev) 154 { 155 fb_dev->x_pixels_per_inch = 156 fb_dev->y_pixels_per_inch = 157 fb_dev->height / PAGE_HEIGHT_INCHES; 158 /* Set the display mode. */ 159 if (svga_save_mode < 0) 160 svga_save_mode = (*fb_dev->get_mode) (); 161 (*fb_dev->set_mode) (fb_dev->mode->mode); 162 svga_init_colors(dev); 163 svga_load_colors(dev); 164 fb_dev->current_page = -1; 165 return 0; 166 } 167 168 /* Close the device; reinitialize the display for text mode. */ 169 int 170 svga_close(gx_device * dev) 171 { 172 if (svga_save_mode >= 0) 173 (*fb_dev->set_mode) (svga_save_mode); 174 svga_save_mode = -1; 175 return 0; 176 } 177 178 /* Map a r-g-b color to a palette index. */ 179 /* The first 64 entries of the color map are set */ 180 /* for compatibility with the older display modes: */ 181 /* these are indexed as 0.0.R0.G0.B0.R1.G1.B1. */ 182 gx_color_index 183 svga_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g, 184 gx_color_value b) 185 { 186 ushort rgb; 187 188 if (fb_dev->fixed_colors) { 189 gx_color_index ci = pc_8bit_map_rgb_color(dev, r, g, b); 190 191 /* Here is where we should permute the index to match */ 192 /* the old color map... but we don't yet. */ 193 return ci; 194 } { 195 ushort r5 = cv_bits(r, 5), g5 = cv_bits(g, 5), b5 = cv_bits(b, 5); 196 static const byte cube_bits[32] = 197 {0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 198 8, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 199 1, 128, 128, 128, 128, 128, 128, 128, 128, 128, 200 9 201 }; 202 uint cx = ((uint) cube_bits[r5] << 2) + 203 ((uint) cube_bits[g5] << 1) + 204 (uint) cube_bits[b5]; 205 206 /* Check for a color on the cube. */ 207 if (cx < 64) 208 return (gx_color_index) cx; 209 /* Not on the cube, check the dynamic color table. */ 210 rgb = (r5 << 10) + (g5 << 5) + b5; 211 } 212 { 213 register dc_entry *pdc; 214 215 for (pdc = &dynamic_colors[rgb % dc_hash_size]; 216 pdc->rgb != 0; pdc++ 217 ) 218 if (pdc->rgb == rgb) 219 return (gx_color_index) (pdc->index); 220 if (pdc == &dynamic_colors[dc_hash_size]) { /* Wraparound */ 221 for (pdc = &dynamic_colors[0]; pdc->rgb != 0; pdc++) 222 if (pdc->rgb == rgb) 223 return (gx_color_index) (pdc->index); 224 } 225 if (next_dc_index == num_colors) { /* No space left, report failure. */ 226 return gx_no_color_index; 227 } 228 /* Not on the cube, and not in the dynamic table. */ 229 /* Put in the dynamic table if space available. */ 230 { 231 int i = next_dc_index++; 232 233 pdc->rgb = rgb; 234 pdc->index = i; 235 svga_dac_set_write_index(i); 236 svga_dac_write(cv_bits(r, 6), cv_bits(g, 6), 237 cv_bits(b, 6)); 238 return (gx_color_index) i; 239 } 240 } 241 } 242 243 /* Map a color code to r-g-b. */ 244 /* This routine must invert the transformation of the one above. */ 245 /* Since this is practically never used, we just read the DAC. */ 246 int 247 svga_map_color_rgb(gx_device * dev, gx_color_index color, 248 gx_color_value prgb[3]) 249 { 250 uint cval; 251 252 outportb(0x3c7, (byte) color); 253 #define dacin() (cval = inportb(0x3c9) >> 1,\ 254 ((cval << 11) + (cval << 6) + (cval << 1) + (cval >> 4)) >>\ 255 (16 - gx_color_value_bits)) 256 prgb[0] = dacin(); 257 prgb[1] = dacin(); 258 prgb[2] = dacin(); 259 #undef dacin 260 return 0; 261 } 262 263 /* Fill a rectangle. */ 264 int 265 svga_fill_rectangle(gx_device * dev, int x, int y, int w, int h, 266 gx_color_index color) 267 { 268 uint raster = fb_dev->raster; 269 ushort limit = (ushort) - raster; 270 int yi; 271 fb_ptr ptr; 272 273 fit_fill(dev, x, y, w, h); 274 set_pixel_write_ptr(ptr, fb_dev, x, y); 275 /* Most fills are very small and don't cross a page boundary. */ 276 yi = h; 277 switch (w) { 278 case 0: 279 return 0; /* no-op */ 280 case 1: 281 while (--yi >= 0 && PTR_OFF(ptr) < limit) 282 ptr[0] = (byte) color, 283 ptr += raster; 284 if (!++yi) 285 return 0; 286 break; 287 case 2: 288 while (--yi >= 0 && PTR_OFF(ptr) < limit) 289 ptr[0] = ptr[1] = (byte) color, 290 ptr += raster; 291 if (!++yi) 292 return 0; 293 break; 294 case 3: 295 while (--yi >= 0 && PTR_OFF(ptr) < limit) 296 ptr[0] = ptr[1] = ptr[2] = (byte) color, 297 ptr += raster; 298 if (!++yi) 299 return 0; 300 break; 301 case 4: 302 while (--yi >= 0 && PTR_OFF(ptr) < limit) 303 ptr[0] = ptr[1] = ptr[2] = ptr[3] = (byte) color, 304 ptr += raster; 305 if (!++yi) 306 return 0; 307 break; 308 default: 309 if (w < 0) 310 return 0; 311 /* Check for erasepage. */ 312 if (w == dev->width && h == dev->height && 313 color < first_dc_index 314 ) 315 svga_init_colors(dev); 316 } 317 while (--yi >= 0) { 318 if (PTR_OFF(ptr) < limit) { 319 memset(ptr, (byte) color, w); 320 ptr += raster; 321 } else if (PTR_OFF(ptr) <= (ushort) (-w)) { 322 memset(ptr, (byte) color, w); 323 if (yi > 0) 324 set_pixel_write_ptr(ptr, fb_dev, x, y + h - yi); 325 } else { 326 uint left = (uint) 0x10000 - PTR_OFF(ptr); 327 328 memset(ptr, (byte) color, left); 329 set_pixel_write_ptr(ptr, fb_dev, x + left, y + h - 1 - yi); 330 memset(ptr, (byte) color, w - left); 331 ptr += raster - left; 332 } 333 } 334 return 0; 335 } 336 337 /* Copy a monochrome bitmap. The colors are given explicitly. */ 338 /* Color = gx_no_color_index means transparent (no effect on the image). */ 339 int 340 svga_copy_mono(gx_device * dev, 341 const byte * base, int sourcex, int sraster, gx_bitmap_id id, 342 int x, int y, int w, int h, gx_color_index czero, gx_color_index cone) 343 { 344 uint raster = fb_dev->raster; 345 ushort limit; 346 register int wi; 347 uint skip; 348 int yi; 349 register fb_ptr ptr = (fb_ptr) 0; 350 const byte *srow; 351 uint invert; 352 353 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); 354 limit = (ushort) - w; 355 skip = raster - w + 1; 356 srow = base + (sourcex >> 3); 357 #define izero (int)czero 358 #define ione (int)cone 359 if (ione == no_color) { 360 gx_color_index temp; 361 362 if (izero == no_color) 363 return 0; /* no-op */ 364 temp = czero; 365 czero = cone; 366 cone = temp; 367 invert = ~0; 368 } else 369 invert = 0; 370 /* Pre-filling saves us a test in the loop, */ 371 /* and since tiling is uncommon, we come out ahead. */ 372 if (izero != no_color) 373 svga_fill_rectangle(dev, x, y, w, h, czero); 374 for (yi = 0; yi < h; yi++) { 375 const byte *sptr = srow; 376 uint bits; 377 int bitno = sourcex & 7; 378 379 wi = w; 380 if (PTR_OFF(ptr) <= skip) { 381 set_pixel_write_ptr(ptr, fb_dev, x, y + yi); 382 } else if (PTR_OFF(ptr) > limit) { /* We're crossing a page boundary. */ 383 /* This is extremely rare, so it doesn't matter */ 384 /* how slow it is. */ 385 int xi = (ushort) - PTR_OFF(ptr); 386 387 svga_copy_mono(dev, srow, sourcex & 7, sraster, 388 gx_no_bitmap_id, x, y + yi, xi, 1, 389 gx_no_color_index, cone); 390 set_pixel_write_ptr(ptr, fb_dev, x + xi, y + yi); 391 sptr = srow - (sourcex >> 3) + ((sourcex + xi) >> 3); 392 bitno = (sourcex + xi) & 7; 393 wi -= xi; 394 } 395 bits = *sptr ^ invert; 396 switch (bitno) { 397 #define ifbit(msk)\ 398 if ( bits & msk ) *ptr = (byte)ione;\ 399 if ( !--wi ) break; ptr++ 400 case 0: 401 bit0:ifbit(0x80); 402 case 1: 403 ifbit(0x40); 404 case 2: 405 ifbit(0x20); 406 case 3: 407 ifbit(0x10); 408 case 4: 409 ifbit(0x08); 410 case 5: 411 ifbit(0x04); 412 case 6: 413 ifbit(0x02); 414 case 7: 415 ifbit(0x01); 416 #undef ifbit 417 bits = *++sptr ^ invert; 418 goto bit0; 419 } 420 ptr += skip; 421 srow += sraster; 422 } 423 #undef izero 424 #undef ione 425 return 0; 426 } 427 428 /* Copy a color pixelmap. This is just like a bitmap, */ 429 /* except that each pixel takes 8 bits instead of 1. */ 430 int 431 svga_copy_color(gx_device * dev, 432 const byte * base, int sourcex, int sraster, gx_bitmap_id id, 433 int x, int y, int w, int h) 434 { 435 int xi, yi; 436 int skip; 437 const byte *sptr; 438 fb_ptr ptr; 439 440 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); 441 skip = sraster - w; 442 sptr = base + sourcex; 443 for (yi = y; yi - y < h; yi++) { 444 ptr = 0; 445 for (xi = x; xi - x < w; xi++) { 446 if (PTR_OFF(ptr) == 0) 447 set_pixel_write_ptr(ptr, fb_dev, xi, yi); 448 *ptr++ = *sptr++; 449 } 450 sptr += skip; 451 } 452 return 0; 453 } 454 455 /* Put parameters. */ 456 int 457 svga_put_params(gx_device * dev, gs_param_list * plist) 458 { 459 int ecode = 0; 460 int code; 461 const char *param_name; 462 463 if ((code = ecode) < 0 || 464 (code = gx_default_put_params(dev, plist)) < 0 465 ) { 466 } 467 return code; 468 } 469 470 /* Read scan lines back from the frame buffer. */ 471 int 472 svga_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data) 473 { 474 uint bytes_per_row = dev->width; 475 ushort limit = (ushort) - bytes_per_row; 476 fb_ptr src; 477 478 if (y < 0 || y >= dev->height) 479 return gs_error_rangecheck; 480 set_pixel_read_ptr(src, fb_dev, 0, y); 481 /* The logic here is similar to fill_rectangle. */ 482 if (PTR_OFF(src) <= limit) 483 memcpy(data, src, bytes_per_row); 484 else { 485 uint left = (uint) 0x10000 - PTR_OFF(src); 486 487 memcpy(data, src, left); 488 set_pixel_read_ptr(src, fb_dev, left, y); 489 memcpy(data + left, src, bytes_per_row - left); 490 } 491 if (actual_data != 0) 492 *actual_data = data; 493 return 0; 494 } 495 496 /* Copy an alpha-map to the screen. */ 497 /* Depth is 1, 2, or 4. */ 498 private int 499 svga_copy_alpha(gx_device * dev, const byte * base, int sourcex, 500 int sraster, gx_bitmap_id id, int x, int y, int w, int h, 501 gx_color_index color, int depth) 502 { 503 int xi, yi; 504 int skip; 505 const byte *sptr; 506 byte mask; 507 int ishift; 508 509 /* We fake alpha by interpreting it as saturation, i.e., */ 510 /* alpha = 0 is white, alpha = 1 is the full color. */ 511 byte shades[16]; 512 gx_color_value rgb[3]; 513 int log2_depth = depth >> 1; /* works for 1,2,4 */ 514 int n1 = (1 << depth) - 1; 515 516 fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); 517 shades[0] = (byte) svga_map_rgb_color(dev, gx_max_color_value, 518 gx_max_color_value, 519 gx_max_color_value); 520 shades[n1] = (byte) color; 521 if (n1 > 1) { 522 memset(shades + 1, 255, n1 - 1); 523 svga_map_color_rgb(dev, color, rgb); 524 } 525 skip = sraster - ((w * depth) >> 3); 526 sptr = base + (sourcex >> (3 - log2_depth)); 527 mask = n1; 528 ishift = (~sourcex & (7 >> log2_depth)) << log2_depth; 529 for (yi = y; yi - y < h; yi++) { 530 fb_ptr ptr = 0; 531 int shift = ishift; 532 533 for (xi = x; xi - x < w; xi++, ptr++) { 534 uint a = (*sptr >> shift) & mask; 535 536 if (PTR_OFF(ptr) == 0) 537 set_pixel_write_ptr(ptr, fb_dev, xi, yi); 538 map:if (a != 0) { 539 byte ci = shades[a]; 540 541 if (ci == 255) { /* Map the color now. */ 542 #define make_shade(v, alpha, n1)\ 543 (gx_max_color_value -\ 544 ((ulong)(gx_max_color_value - (v)) * (alpha) / (n1))) 545 gx_color_value r = 546 make_shade(rgb[0], a, n1); 547 gx_color_value g = 548 make_shade(rgb[1], a, n1); 549 gx_color_value b = 550 make_shade(rgb[2], a, n1); 551 gx_color_index sci = 552 svga_map_rgb_color(dev, r, g, b); 553 554 if (sci == gx_no_color_index) { 555 a += (n1 + 1 - a) >> 1; 556 goto map; 557 } 558 shades[a] = ci = (byte) sci; 559 } 560 *ptr = ci; 561 } 562 if (shift == 0) 563 shift = 8 - depth, sptr++; 564 else 565 shift -= depth; 566 } 567 sptr += skip; 568 } 569 return 0; 570 } 571 572 /* ------ The VESA device ------ */ 573 574 private dev_proc_open_device(vesa_open); 575 private const gx_device_procs vesa_procs = svga_procs(vesa_open); 576 int vesa_get_mode(P0()); 577 void vesa_set_mode(P1(int)); 578 private void vesa_set_page(P3(gx_device_svga *, int, int)); 579 gx_device_svga far_data gs_vesa_device = 580 svga_device(vesa_procs, "vesa", vesa_get_mode, vesa_set_mode, vesa_set_page); 581 582 /* Define the structures for information returned by the BIOS. */ 583 #define bits_include(a, m) !(~(a) & (m)) 584 /* Information about the BIOS capabilities. */ 585 typedef struct { 586 byte vesa_signature[4]; /* "VESA" */ 587 ushort vesa_version; 588 char *product_info; /* product name string */ 589 byte capabilities[4]; /* (undefined) */ 590 ushort *mode_list; /* supported video modes, -1 ends */ 591 } vga_bios_info; 592 593 /* Information about an individual VESA mode. */ 594 typedef enum { 595 m_supported = 1, 596 m_graphics = 0x10 597 } mode_attribute; 598 typedef enum { 599 w_supported = 1, 600 w_readable = 2, 601 w_writable = 4 602 } win_attribute; 603 typedef struct { 604 ushort mode_attributes; 605 byte win_a_attributes; 606 byte win_b_attributes; 607 ushort win_granularity; 608 ushort win_size; 609 ushort win_a_segment; 610 ushort win_b_segment; 611 void (*win_func_ptr) (P2(int, int)); 612 ushort bytes_per_line; 613 /* Optional information */ 614 ushort x_resolution; 615 ushort y_resolution; 616 byte x_char_size; 617 byte y_char_size; 618 byte number_of_planes; 619 byte bits_per_pixel; 620 byte number_of_banks; 621 byte memory_model; 622 byte bank_size; 623 /* Padding to 256 bytes */ 624 byte _padding[256 - 29]; 625 } vesa_info; 626 627 /* Read the device mode */ 628 int 629 vesa_get_mode(void) 630 { 631 registers regs; 632 633 regs.h.ah = 0x4f; 634 regs.h.al = 0x03; 635 int86(0x10, ®s, ®s); 636 return regs.rshort.bx; 637 } 638 639 /* Set the device mode */ 640 void 641 vesa_set_mode(int mode) 642 { 643 registers regs; 644 645 regs.h.ah = 0x4f; 646 regs.h.al = 0x02; 647 regs.rshort.bx = mode; 648 int86(0x10, ®s, ®s); 649 } 650 651 /* Read information about a device mode */ 652 private int 653 vesa_get_info(int mode, vesa_info _ss * info) 654 { 655 registers regs; 656 struct SREGS sregs; 657 658 regs.h.ah = 0x4f; 659 regs.h.al = 0x01; 660 regs.rshort.cx = mode; 661 segread(&sregs); 662 sregs.es = sregs.ss; 663 regs.rshort.di = PTR_OFF(info); 664 int86x(0x10, ®s, ®s, &sregs); 665 #ifdef DEBUG 666 if (regs.h.ah == 0 && regs.h.al == 0x4f) 667 dlprintf8("vesa_get_info(%x): ma=%x wa=%x/%x wg=%x ws=%x wseg=%x/%x\n", 668 mode, info->mode_attributes, 669 info->win_a_attributes, info->win_b_attributes, 670 info->win_granularity, info->win_size, 671 info->win_a_segment, info->win_b_segment); 672 else 673 dlprintf3("vesa_get_info(%x) failed: ah=%x al=%x\n", 674 mode, regs.h.ah, regs.h.al); 675 #endif 676 return (regs.h.ah == 0 && regs.h.al == 0x4f ? 0 : -1); 677 } 678 679 /* Initialize the graphics mode. */ 680 /* Shared routine to look up a VESA-compatible BIOS mode. */ 681 private int 682 vesa_find_mode(gx_device * dev, const mode_info * mode_table) 683 { /* Select the proper video mode */ 684 vesa_info info; 685 const mode_info *mip; 686 687 for (mip = mode_table; mip->mode >= 0; mip++) { 688 if (mip->width >= fb_dev->width && 689 mip->height >= fb_dev->height && 690 vesa_get_info(mip->mode, &info) >= 0 && 691 bits_include(info.mode_attributes, 692 m_supported | m_graphics) && 693 info.win_granularity <= 64 && 694 (info.win_granularity & (info.win_granularity - 1)) == 0 && 695 info.win_size == 64 && 696 bits_include(info.win_a_attributes, 697 w_supported) && 698 info.win_a_segment == regen 699 ) { /* Make sure we can both read & write. */ 700 /* Initialize for the default case. */ 701 fb_dev->wnum_read = 0; 702 fb_dev->wnum_write = 0; 703 if (bits_include(info.win_a_attributes, 704 w_readable | w_writable) 705 ) 706 break; 707 else if (info.win_b_segment == regen && 708 bits_include(info.win_b_attributes, 709 w_supported) && 710 bits_include(info.win_a_attributes | 711 info.win_b_attributes, 712 w_readable | w_writable) 713 ) { /* Two superimposed windows. */ 714 if (!bits_include(info.win_a_attributes, 715 w_writable) 716 ) 717 fb_dev->wnum_write = 1; 718 else 719 fb_dev->wnum_read = 1; 720 } 721 break; 722 } 723 } 724 if (mip->mode < 0) 725 return_error(gs_error_rangecheck); /* mode not available */ 726 fb_dev->mode = mip; 727 gx_device_adjust_resolution(dev, mip->width, mip->height, 1); 728 fb_dev->info.vesa.bios_set_page = info.win_func_ptr; 729 fb_dev->info.vesa.pn_shift = ilog2(64 / info.win_granularity); 730 /* Reset the raster per the VESA info. */ 731 fb_dev->raster = info.bytes_per_line; 732 return 0; 733 } 734 private int 735 vesa_open(gx_device * dev) 736 { 737 static const mode_info mode_table[] = 738 { 739 {640, 400, 0x100}, 740 {640, 480, 0x101}, 741 {800, 600, 0x103}, 742 {1024, 768, 0x105}, 743 {1280, 1024, 0x107}, 744 {-1, -1, -1} 745 }; 746 int code = vesa_find_mode(dev, mode_table); 747 748 if (code < 0) 749 return code; 750 return svga_open(dev); 751 } 752 753 /* Set the current display page. */ 754 private void 755 vesa_set_page(gx_device_svga * dev, int pn, int wnum) 756 { 757 #if USE_ASM 758 extern void vesa_call_set_page(P3(void (*)(P2(int, int)), int, int)); 759 760 if (dev->info.vesa.bios_set_page != NULL) 761 vesa_call_set_page(dev->info.vesa.bios_set_page, pn << dev->info.vesa.pn_shift, wnum); 762 else 763 #endif 764 { 765 registers regs; 766 767 regs.rshort.dx = pn << dev->info.vesa.pn_shift; 768 regs.h.ah = 0x4f; 769 regs.h.al = 5; 770 regs.rshort.bx = wnum; 771 int86(0x10, ®s, ®s); 772 } 773 } 774 775 /* ------ The ATI Wonder device ------ */ 776 777 private dev_proc_open_device(atiw_open); 778 private const gx_device_procs atiw_procs = svga_procs(atiw_open); 779 private int atiw_get_mode(P0()); 780 private void atiw_set_mode(P1(int)); 781 private void atiw_set_page(P3(gx_device_svga *, int, int)); 782 gx_device_svga far_data gs_atiw_device = 783 svga_device(atiw_procs, "atiw", atiw_get_mode, atiw_set_mode, atiw_set_page); 784 785 /* Read the device mode */ 786 private int 787 atiw_get_mode(void) 788 { 789 registers regs; 790 791 regs.h.ah = 0xf; 792 int86(0x10, ®s, ®s); 793 return regs.h.al; 794 } 795 796 /* Set the device mode */ 797 private void 798 atiw_set_mode(int mode) 799 { 800 registers regs; 801 802 regs.h.ah = 0; 803 regs.h.al = mode; 804 int86(0x10, ®s, ®s); 805 } 806 807 /* Initialize the graphics mode. */ 808 private int 809 atiw_open(gx_device * dev) 810 { /* Select the proper video mode */ 811 { 812 static const mode_info mode_table[] = 813 { 814 {640, 400, 0x61}, 815 {640, 480, 0x62}, 816 {800, 600, 0x63}, 817 {1024, 768, 0x64}, 818 {-1, -1, -1} 819 }; 820 int code = svga_find_mode(dev, mode_table); 821 822 if (code < 0) 823 return code; /* mode not available */ 824 fb_dev->info.atiw.select_reg = *(int *)MK_PTR(0xc000, 0x10); 825 return svga_open(dev); 826 } 827 } 828 829 /* Set the current display page. */ 830 private void 831 atiw_set_page(gx_device_svga * dev, int pn, int wnum) 832 { 833 int select_reg = dev->info.atiw.select_reg; 834 byte reg; 835 836 disable(); 837 outportb(select_reg, 0xb2); 838 reg = inportb(select_reg + 1); 839 outportb(select_reg, 0xb2); 840 outportb(select_reg + 1, (reg & 0xe1) + (pn << 1)); 841 enable(); 842 } 843 844 /* ------ The Trident device ------ */ 845 846 private dev_proc_open_device(tvga_open); 847 private const gx_device_procs tvga_procs = svga_procs(tvga_open); 848 849 /* We can use the atiw_get/set_mode procedures. */ 850 private void tvga_set_page(P3(gx_device_svga *, int, int)); 851 gx_device_svga far_data gs_tvga_device = 852 svga_device(tvga_procs, "tvga", atiw_get_mode, atiw_set_mode, tvga_set_page); 853 854 /* Initialize the graphics mode. */ 855 private int 856 tvga_open(gx_device * dev) 857 { 858 fb_dev->wnum_read = 1; 859 fb_dev->wnum_write = 0; 860 /* Select the proper video mode */ 861 { 862 static const mode_info mode_table[] = 863 { 864 {640, 400, 0x5c}, 865 {640, 480, 0x5d}, 866 {800, 600, 0x5e}, 867 {1024, 768, 0x62}, 868 {-1, -1, -1} 869 }; 870 int code = svga_find_mode(dev, mode_table); 871 872 if (code < 0) 873 return code; /* mode not available */ 874 return svga_open(dev); 875 } 876 } 877 878 /* Set the current display page. */ 879 private void 880 tvga_set_page(gx_device_svga * dev, int pn, int wnum) 881 { 882 /* new mode */ 883 outportb(0x3c4, 0x0b); 884 inportb(0x3c4); 885 886 outportb(0x3c4, 0x0e); 887 outportb(0x3c5, pn ^ 2); 888 } 889 890 /* ------ The Tseng Labs ET3000/4000 devices ------ */ 891 892 private dev_proc_open_device(tseng_open); 893 private const gx_device_procs tseng_procs = 894 svga_procs(tseng_open); 895 896 /* We can use the atiw_get/set_mode procedures. */ 897 private void tseng_set_page(P3(gx_device_svga *, int, int)); 898 899 /* The 256-color Tseng device */ 900 gx_device_svga far_data gs_tseng_device = 901 svga_device(tseng_procs, "tseng", atiw_get_mode, atiw_set_mode, tseng_set_page); 902 903 /* Initialize the graphics mode. */ 904 private int 905 tseng_open(gx_device * dev) 906 { 907 fb_dev->wnum_read = 1; 908 fb_dev->wnum_write = 0; 909 /* Select the proper video mode */ 910 { 911 static const mode_info mode_table[] = 912 { 913 {640, 350, 0x2d}, 914 {640, 480, 0x2e}, 915 {800, 600, 0x30}, 916 {1024, 768, 0x38}, 917 {-1, -1, -1} 918 }; 919 int code = svga_find_mode(dev, mode_table); 920 volatile_fb_ptr p0 = (volatile_fb_ptr) MK_PTR(regen, 0); 921 922 if (code < 0) 923 return code; /* mode not available */ 924 code = svga_open(dev); 925 if (code < 0) 926 return 0; 927 /* Figure out whether we have an ET3000 or an ET4000 */ 928 /* by playing with the segment register. */ 929 outportb(0x3cd, 0x44); 930 *p0 = 4; /* byte 0, page 4 */ 931 outportb(0x3cd, 0x40); 932 *p0 = 3; /* byte 0, page 0 */ 933 fb_dev->info.tseng.et_model = *p0; 934 /* read page 0 if ET3000, */ 935 /* page 4 if ET4000 */ 936 return 0; 937 } 938 } 939 940 /* Set the current display page. */ 941 private void 942 tseng_set_page(gx_device_svga * dev, int pn, int wnum) 943 { /* The ET3000 has read page = 5:3, write page = 2:0; */ 944 /* the ET4000 has read page = 7:4, write page = 3:0. */ 945 int shift = dev->info.tseng.et_model; 946 int mask = (1 << shift) - 1; 947 948 if (wnum) 949 pn <<= shift, mask <<= shift; 950 outportb(0x3cd, (inportb(0x3cd) & ~mask) + pn); 951 } 952 /* ------ The Cirrus device (CL-GD54XX) ------ */ 953 /* Written by Piotr Strzelczyk, BOP s.c., Gda\'nsk, Poland, */ 954 /* e-mail contact via B.Jackowski@GUST.org.pl */ 955 956 private dev_proc_open_device(cirr_open); 957 private gx_device_procs cirr_procs = svga_procs(cirr_open); 958 959 /* We can use the atiw_get/set_mode procedures. */ 960 private void cirr_set_page(P3(gx_device_svga *, int, int)); 961 gx_device_svga gs_cirr_device = 962 svga_device(cirr_procs, "cirr", atiw_get_mode, atiw_set_mode, cirr_set_page); 963 964 /* Initialize the graphics mode. */ 965 private int 966 cirr_open(gx_device * dev) 967 { 968 fb_dev->wnum_read = 1; 969 fb_dev->wnum_write = 0; 970 /* Select the proper video mode */ 971 { 972 static const mode_info mode_table[] = 973 { 974 {640, 400, 0x5e}, 975 {640, 480, 0x5f}, 976 {800, 600, 0x5c}, 977 {1024, 768, 0x60}, 978 {-1, -1, -1} 979 }; 980 int code = svga_find_mode(dev, mode_table); 981 982 if (code < 0) 983 return code; /* mode not available */ 984 outportb(0x3c4, 0x06); 985 outportb(0x3c5, 0x12); 986 outportb(0x3ce, 0x0b); 987 outportb(0x3cf, (inportb(0x3cf) & 0xde)); 988 return svga_open(dev); 989 } 990 } 991 992 /* Set the current display page. */ 993 private void 994 cirr_set_page(gx_device_svga * dev, int pn, int wnum) 995 { 996 outportb(0x3ce, 0x09); 997 outportb(0x3cf, pn << 4); 998 } 999 1000 /* ------ The Avance Logic device (mostly experimental) ------ */ 1001 /* For questions about this device, please contact Stefan Freund */ 1002 /* <freund@ikp.uni-koeln.de>. */ 1003 1004 private dev_proc_open_device(ali_open); 1005 private const gx_device_procs ali_procs = svga_procs(ali_open); 1006 1007 /* We can use the atiw_get/set_mode procedures. */ 1008 private void ali_set_page(P3(gx_device_svga *, int, int)); 1009 1010 /* The 256-color Avance Logic device */ 1011 gx_device_svga gs_ali_device = 1012 svga_device(ali_procs, "ali", atiw_get_mode, atiw_set_mode, 1013 ali_set_page); 1014 1015 /* Initialize the graphics mode. */ 1016 private int 1017 ali_open(gx_device * dev) 1018 { 1019 fb_dev->wnum_read = 1; 1020 fb_dev->wnum_write = 0; 1021 /* Select the proper video mode */ 1022 { 1023 static const mode_info mode_table[] = 1024 { 1025 {640, 400, 0x29}, 1026 {640, 480, 0x2a}, 1027 {800, 600, 0x2c}, 1028 {1024, 768, 0x31}, 1029 {-1, -1, -1} 1030 }; 1031 int code = svga_find_mode(dev, mode_table); 1032 1033 if (code < 0) 1034 return code; /* mode not available */ 1035 return svga_open(dev); 1036 } 1037 1038 } 1039 1040 /* Set the current display page. */ 1041 private void 1042 ali_set_page(gx_device_svga * dev, int pn, int wnum) 1043 { 1044 outportb(0x3d6, pn); /* read */ 1045 outportb(0x3d7, pn); /* write */ 1046 } 1047