1 /* Copyright (C) 1991, 1995, 1996, 1997, 1998, 1999 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: gdevsvga.c,v 1.2.6.1.2.1 2003/01/17 00:49:01 giles 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
svga_find_mode(gx_device * dev,const mode_info * mip)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
svga_init_colors(gx_device * dev)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
svga_load_colors(gx_device * dev)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
svga_open(gx_device * dev)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
svga_close(gx_device * dev)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
svga_map_rgb_color(gx_device * dev,gx_color_value r,gx_color_value g,gx_color_value b)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
svga_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])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
svga_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)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
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)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
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)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
svga_put_params(gx_device * dev,gs_param_list * plist)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
svga_get_bits(gx_device * dev,int y,byte * data,byte ** actual_data)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
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)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
vesa_get_mode(void)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
vesa_set_mode(int mode)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
vesa_get_info(int mode,vesa_info _ss * info)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
vesa_find_mode(gx_device * dev,const mode_info * mode_table)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
vesa_open(gx_device * dev)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
vesa_set_page(gx_device_svga * dev,int pn,int wnum)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
atiw_get_mode(void)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
atiw_set_mode(int mode)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
atiw_open(gx_device * dev)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
atiw_set_page(gx_device_svga * dev,int pn,int wnum)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
tvga_open(gx_device * dev)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
tvga_set_page(gx_device_svga * dev,int pn,int wnum)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
tseng_open(gx_device * dev)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
tseng_set_page(gx_device_svga * dev,int pn,int wnum)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
cirr_open(gx_device * dev)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
cirr_set_page(gx_device_svga * dev,int pn,int wnum)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
ali_open(gx_device * dev)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
ali_set_page(gx_device_svga * dev,int pn,int wnum)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