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
svga_find_mode(gx_device * dev,const mode_info * mip)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
svga_init_colors(gx_device * dev)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
svga_load_colors(gx_device * dev)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
svga_open(gx_device * dev)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
svga_close(gx_device * dev)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
svga_map_rgb_color(gx_device * dev,const gx_color_value cv[])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
svga_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])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
svga_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)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
svga_copy_mono(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index czero,gx_color_index cone)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
svga_copy_color(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h)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
svga_put_params(gx_device * dev,gs_param_list * plist)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
svga_get_bits(gx_device * dev,int y,byte * data,byte ** actual_data)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
svga_copy_alpha(gx_device * dev,const byte * base,int sourcex,int sraster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index color,int depth)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
vesa_get_mode(void)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
vesa_set_mode(int mode)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
vesa_get_info(int mode,vesa_info _ss * info)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
vesa_find_mode(gx_device * dev,const mode_info * mode_table)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
vesa_open(gx_device * dev)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
vesa_set_page(gx_device_svga * dev,int pn,int wnum)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
atiw_get_mode(void)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
atiw_set_mode(int mode)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
atiw_open(gx_device * dev)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
atiw_set_page(gx_device_svga * dev,int pn,int wnum)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
tvga_open(gx_device * dev)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
tvga_set_page(gx_device_svga * dev,int pn,int wnum)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
tseng_open(gx_device * dev)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
tseng_set_page(gx_device_svga * dev,int pn,int wnum)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
cirr_open(gx_device * dev)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
cirr_set_page(gx_device_svga * dev,int pn,int wnum)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
ali_open(gx_device * dev)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
ali_set_page(gx_device_svga * dev,int pn,int wnum)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