Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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, &regs, &regs);
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, &regs, &regs);
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, &regs, &regs, &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, &regs, &regs);
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, &regs, &regs);
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, &regs, &regs);
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
}