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