xref: /plan9-contrib/sys/src/cmd/gs/src/gdevsvga.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1991, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevsvga.c,v 1.6 2004/04/01 04:51:42 dan Exp $ */
187dd7cddfSDavid du Colombier /* SuperVGA display drivers */
197dd7cddfSDavid du Colombier #include "memory_.h"
207dd7cddfSDavid du Colombier #include "gconfigv.h"		/* for USE_ASM */
217dd7cddfSDavid du Colombier #include "gx.h"
227dd7cddfSDavid du Colombier #include "gserrors.h"
237dd7cddfSDavid du Colombier #include "gxarith.h"		/* for ...log2 */
247dd7cddfSDavid du Colombier #include "gxdevice.h"
257dd7cddfSDavid du Colombier #include "gdevpccm.h"
267dd7cddfSDavid du Colombier #include "gdevpcfb.h"
277dd7cddfSDavid du Colombier #include "gdevsvga.h"
287dd7cddfSDavid du Colombier #include "gsparam.h"
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier /* The color map for dynamically assignable colors. */
317dd7cddfSDavid du Colombier #define first_dc_index 64
327dd7cddfSDavid du Colombier private int next_dc_index;
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier #define dc_hash_size 293	/* prime, >num_dc */
357dd7cddfSDavid du Colombier typedef struct {
367dd7cddfSDavid du Colombier     ushort rgb, index;
377dd7cddfSDavid du Colombier } dc_entry;
387dd7cddfSDavid du Colombier private dc_entry dynamic_colors[dc_hash_size + 1];
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier #define num_colors 255
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier /* Macro for casting gx_device argument */
437dd7cddfSDavid du Colombier #define fb_dev ((gx_device_svga *)dev)
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier /* Procedure records */
467dd7cddfSDavid du Colombier #define svga_procs(open) {\
477dd7cddfSDavid du Colombier 	open, NULL /*get_initial_matrix*/,\
487dd7cddfSDavid du Colombier 	NULL /*sync_output*/, NULL /*output_page*/, svga_close,\
497dd7cddfSDavid du Colombier 	svga_map_rgb_color, svga_map_color_rgb,\
507dd7cddfSDavid du Colombier 	svga_fill_rectangle, NULL /*tile_rectangle*/,\
517dd7cddfSDavid du Colombier 	svga_copy_mono, svga_copy_color, NULL /*draw_line*/,\
527dd7cddfSDavid du Colombier 	svga_get_bits, NULL /*get_params*/, svga_put_params,\
537dd7cddfSDavid du Colombier 	NULL /*map_cmyk_color*/, NULL /*get_xfont_procs*/,\
547dd7cddfSDavid du Colombier 	NULL /*get_xfont_device*/, NULL /*map_rgb_alpha_color*/,\
557dd7cddfSDavid du Colombier 	gx_page_device_get_page_device, NULL /*get_alpha_bits*/,\
567dd7cddfSDavid du Colombier 	svga_copy_alpha\
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier /* Save the controller mode */
607dd7cddfSDavid du Colombier private int svga_save_mode = -1;
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier /* ------ Internal routines ------ */
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier #define regen 0xa000
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier /* Construct a pointer for writing a pixel. */
677dd7cddfSDavid du Colombier /* Assume 64K pages, 64K granularity. */
687dd7cddfSDavid du Colombier /* We know that y is within bounds. */
697dd7cddfSDavid du Colombier #define set_pixel_ptr(ptr, fbdev, x, y, wnum)\
707dd7cddfSDavid du Colombier {	ulong index = (ulong)(y) * fbdev->raster + (uint)(x);\
717dd7cddfSDavid du Colombier 	if ( (uint)(index >> 16) != fbdev->current_page )\
727dd7cddfSDavid du Colombier 	   {	(*fbdev->set_page)(fbdev, (fbdev->current_page = index >> 16), wnum);\
737dd7cddfSDavid du Colombier 	   }\
747dd7cddfSDavid du Colombier 	ptr = (fb_ptr)MK_PTR(regen, (ushort)index);\
757dd7cddfSDavid du Colombier }
767dd7cddfSDavid du Colombier #define set_pixel_write_ptr(ptr, fbdev, x, y)\
777dd7cddfSDavid du Colombier   set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_write)
787dd7cddfSDavid du Colombier #define set_pixel_read_ptr(ptr, fbdev, x, y)\
797dd7cddfSDavid du Colombier   set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_read)
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier /* Find the graphics mode for a desired width and height. */
827dd7cddfSDavid du Colombier /* Set the mode in the device structure and return 0, */
837dd7cddfSDavid du Colombier /* or return an error code. */
847dd7cddfSDavid du Colombier int
svga_find_mode(gx_device * dev,const mode_info * mip)857dd7cddfSDavid du Colombier svga_find_mode(gx_device * dev, const mode_info * mip)
867dd7cddfSDavid du Colombier {
877dd7cddfSDavid du Colombier     for (;; mip++) {
887dd7cddfSDavid du Colombier 	if (mip->width >= fb_dev->width &&
897dd7cddfSDavid du Colombier 	    mip->height >= fb_dev->height ||
907dd7cddfSDavid du Colombier 	    mip[1].mode < 0
917dd7cddfSDavid du Colombier 	    ) {
927dd7cddfSDavid du Colombier 	    fb_dev->mode = mip;
937dd7cddfSDavid du Colombier 	    gx_device_adjust_resolution(dev, mip->width, mip->height, 1);
947dd7cddfSDavid du Colombier 	    fb_dev->raster = fb_dev->width;
957dd7cddfSDavid du Colombier 	    return 0;
967dd7cddfSDavid du Colombier 	}
977dd7cddfSDavid du Colombier     }
987dd7cddfSDavid du Colombier     return_error(gs_error_rangecheck);
997dd7cddfSDavid du Colombier }
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier /* Set the index for writing into the color DAC. */
1027dd7cddfSDavid du Colombier #define svga_dac_set_write_index(i) outportb(0x3c8, i)
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier /* Write 6-bit R,G,B values into the color DAC. */
1057dd7cddfSDavid du Colombier #define svga_dac_write(r, g, b)\
1067dd7cddfSDavid du Colombier   (outportb(0x3c9, r), outportb(0x3c9, g), outportb(0x3c9, b))
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier /* ------ Common procedures ------ */
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier #define cv_bits(v,n) (v >> (gx_color_value_bits - n))
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier /* Initialize the dynamic color table, if any. */
1137dd7cddfSDavid du Colombier void
svga_init_colors(gx_device * dev)1147dd7cddfSDavid du Colombier svga_init_colors(gx_device * dev)
1157dd7cddfSDavid du Colombier {
1167dd7cddfSDavid du Colombier     if (fb_dev->fixed_colors)
1177dd7cddfSDavid du Colombier 	next_dc_index = num_colors;
1187dd7cddfSDavid du Colombier     else {
1197dd7cddfSDavid du Colombier 	memset(dynamic_colors, 0,
1207dd7cddfSDavid du Colombier 	       (dc_hash_size + 1) * sizeof(dc_entry));
1217dd7cddfSDavid du Colombier 	next_dc_index = first_dc_index;
1227dd7cddfSDavid du Colombier     }
1237dd7cddfSDavid du Colombier }
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier /* Load the color DAC with the predefined colors. */
1267dd7cddfSDavid du Colombier private void
svga_load_colors(gx_device * dev)1277dd7cddfSDavid du Colombier svga_load_colors(gx_device * dev)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier     int ci;
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier     svga_dac_set_write_index(0);
1327dd7cddfSDavid du Colombier     if (fb_dev->fixed_colors)
1337dd7cddfSDavid du Colombier 	for (ci = 0; ci < num_colors; ci++) {
1347dd7cddfSDavid du Colombier 	    gx_color_value rgb[3];
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier 	    pc_8bit_map_color_rgb(dev, (gx_color_index) ci, rgb);
1377dd7cddfSDavid du Colombier 	    svga_dac_write(cv_bits(rgb[0], 6), cv_bits(rgb[1], 6),
1387dd7cddfSDavid du Colombier 			   cv_bits(rgb[2], 6));
1397dd7cddfSDavid du Colombier     } else
1407dd7cddfSDavid du Colombier 	for (ci = 0; ci < 64; ci++) {
1417dd7cddfSDavid du Colombier 	    static const byte c2[10] =
1427dd7cddfSDavid du Colombier 	    {0, 42, 0, 0, 0, 0, 0, 0, 21, 63};
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier 	    svga_dac_write(c2[(ci >> 2) & 9], c2[(ci >> 1) & 9],
1457dd7cddfSDavid du Colombier 			   c2[ci & 9]);
1467dd7cddfSDavid du Colombier 	}
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier /* Initialize the device structure and the DACs. */
1507dd7cddfSDavid du Colombier int
svga_open(gx_device * dev)1517dd7cddfSDavid du Colombier svga_open(gx_device * dev)
1527dd7cddfSDavid du Colombier {
1537dd7cddfSDavid du Colombier     fb_dev->x_pixels_per_inch =
1547dd7cddfSDavid du Colombier 	fb_dev->y_pixels_per_inch =
1557dd7cddfSDavid du Colombier 	fb_dev->height / PAGE_HEIGHT_INCHES;
1567dd7cddfSDavid du Colombier     /* Set the display mode. */
1577dd7cddfSDavid du Colombier     if (svga_save_mode < 0)
1587dd7cddfSDavid du Colombier 	svga_save_mode = (*fb_dev->get_mode) ();
1597dd7cddfSDavid du Colombier     (*fb_dev->set_mode) (fb_dev->mode->mode);
1607dd7cddfSDavid du Colombier     svga_init_colors(dev);
1617dd7cddfSDavid du Colombier     svga_load_colors(dev);
1627dd7cddfSDavid du Colombier     fb_dev->current_page = -1;
1637dd7cddfSDavid du Colombier     return 0;
1647dd7cddfSDavid du Colombier }
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier /* Close the device; reinitialize the display for text mode. */
1677dd7cddfSDavid du Colombier int
svga_close(gx_device * dev)1687dd7cddfSDavid du Colombier svga_close(gx_device * dev)
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier     if (svga_save_mode >= 0)
1717dd7cddfSDavid du Colombier 	(*fb_dev->set_mode) (svga_save_mode);
1727dd7cddfSDavid du Colombier     svga_save_mode = -1;
1737dd7cddfSDavid du Colombier     return 0;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier /* Map a r-g-b color to a palette index. */
1777dd7cddfSDavid du Colombier /* The first 64 entries of the color map are set */
1787dd7cddfSDavid du Colombier /* for compatibility with the older display modes: */
1797dd7cddfSDavid du Colombier /* these are indexed as 0.0.R0.G0.B0.R1.G1.B1. */
1807dd7cddfSDavid du Colombier gx_color_index
svga_map_rgb_color(gx_device * dev,const gx_color_value cv[])181*593dc095SDavid du Colombier svga_map_rgb_color(gx_device * dev, const gx_color_value cv[])
1827dd7cddfSDavid du Colombier {
1837dd7cddfSDavid du Colombier     ushort rgb;
184*593dc095SDavid du Colombier     gx_color_value r = cv[0], g = cv[1], b = cv[2];
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier     if (fb_dev->fixed_colors) {
187*593dc095SDavid du Colombier 	gx_color_index ci = pc_8bit_map_rgb_color(dev, cv);
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier 	/* Here is where we should permute the index to match */
1907dd7cddfSDavid du Colombier 	/* the old color map... but we don't yet. */
1917dd7cddfSDavid du Colombier 	return ci;
1927dd7cddfSDavid du Colombier     } {
1937dd7cddfSDavid du Colombier 	ushort r5 = cv_bits(r, 5), g5 = cv_bits(g, 5), b5 = cv_bits(b, 5);
1947dd7cddfSDavid du Colombier 	static const byte cube_bits[32] =
1957dd7cddfSDavid du Colombier 	{0, 128, 128, 128, 128, 128, 128, 128, 128, 128,
1967dd7cddfSDavid du Colombier 	 8, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
1977dd7cddfSDavid du Colombier 	 1, 128, 128, 128, 128, 128, 128, 128, 128, 128,
1987dd7cddfSDavid du Colombier 	 9
1997dd7cddfSDavid du Colombier 	};
2007dd7cddfSDavid du Colombier 	uint cx = ((uint) cube_bits[r5] << 2) +
2017dd7cddfSDavid du Colombier 	((uint) cube_bits[g5] << 1) +
2027dd7cddfSDavid du Colombier 	(uint) cube_bits[b5];
2037dd7cddfSDavid du Colombier 
2047dd7cddfSDavid du Colombier 	/* Check for a color on the cube. */
2057dd7cddfSDavid du Colombier 	if (cx < 64)
2067dd7cddfSDavid du Colombier 	    return (gx_color_index) cx;
2077dd7cddfSDavid du Colombier 	/* Not on the cube, check the dynamic color table. */
2087dd7cddfSDavid du Colombier 	rgb = (r5 << 10) + (g5 << 5) + b5;
2097dd7cddfSDavid du Colombier     }
2107dd7cddfSDavid du Colombier     {
2117dd7cddfSDavid du Colombier 	register dc_entry *pdc;
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier 	for (pdc = &dynamic_colors[rgb % dc_hash_size];
2147dd7cddfSDavid du Colombier 	     pdc->rgb != 0; pdc++
2157dd7cddfSDavid du Colombier 	    )
2167dd7cddfSDavid du Colombier 	    if (pdc->rgb == rgb)
2177dd7cddfSDavid du Colombier 		return (gx_color_index) (pdc->index);
2187dd7cddfSDavid du Colombier 	if (pdc == &dynamic_colors[dc_hash_size]) {	/* Wraparound */
2197dd7cddfSDavid du Colombier 	    for (pdc = &dynamic_colors[0]; pdc->rgb != 0; pdc++)
2207dd7cddfSDavid du Colombier 		if (pdc->rgb == rgb)
2217dd7cddfSDavid du Colombier 		    return (gx_color_index) (pdc->index);
2227dd7cddfSDavid du Colombier 	}
2237dd7cddfSDavid du Colombier 	if (next_dc_index == num_colors) {	/* No space left, report failure. */
2247dd7cddfSDavid du Colombier 	    return gx_no_color_index;
2257dd7cddfSDavid du Colombier 	}
2267dd7cddfSDavid du Colombier 	/* Not on the cube, and not in the dynamic table. */
2277dd7cddfSDavid du Colombier 	/* Put in the dynamic table if space available. */
2287dd7cddfSDavid du Colombier 	{
2297dd7cddfSDavid du Colombier 	    int i = next_dc_index++;
2307dd7cddfSDavid du Colombier 
2317dd7cddfSDavid du Colombier 	    pdc->rgb = rgb;
2327dd7cddfSDavid du Colombier 	    pdc->index = i;
2337dd7cddfSDavid du Colombier 	    svga_dac_set_write_index(i);
2347dd7cddfSDavid du Colombier 	    svga_dac_write(cv_bits(r, 6), cv_bits(g, 6),
2357dd7cddfSDavid du Colombier 			   cv_bits(b, 6));
2367dd7cddfSDavid du Colombier 	    return (gx_color_index) i;
2377dd7cddfSDavid du Colombier 	}
2387dd7cddfSDavid du Colombier     }
2397dd7cddfSDavid du Colombier }
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier /* Map a color code to r-g-b. */
2427dd7cddfSDavid du Colombier /* This routine must invert the transformation of the one above. */
2437dd7cddfSDavid du Colombier /* Since this is practically never used, we just read the DAC. */
2447dd7cddfSDavid du Colombier int
svga_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])2457dd7cddfSDavid du Colombier svga_map_color_rgb(gx_device * dev, gx_color_index color,
2467dd7cddfSDavid du Colombier 		   gx_color_value prgb[3])
2477dd7cddfSDavid du Colombier {
2487dd7cddfSDavid du Colombier     uint cval;
2497dd7cddfSDavid du Colombier 
2507dd7cddfSDavid du Colombier     outportb(0x3c7, (byte) color);
2517dd7cddfSDavid du Colombier #define dacin() (cval = inportb(0x3c9) >> 1,\
2527dd7cddfSDavid du Colombier   ((cval << 11) + (cval << 6) + (cval << 1) + (cval >> 4)) >>\
2537dd7cddfSDavid du Colombier    (16 - gx_color_value_bits))
2547dd7cddfSDavid du Colombier     prgb[0] = dacin();
2557dd7cddfSDavid du Colombier     prgb[1] = dacin();
2567dd7cddfSDavid du Colombier     prgb[2] = dacin();
2577dd7cddfSDavid du Colombier #undef dacin
2587dd7cddfSDavid du Colombier     return 0;
2597dd7cddfSDavid du Colombier }
2607dd7cddfSDavid du Colombier 
2617dd7cddfSDavid du Colombier /* Fill a rectangle. */
2627dd7cddfSDavid du Colombier int
svga_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)2637dd7cddfSDavid du Colombier svga_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
2647dd7cddfSDavid du Colombier 		    gx_color_index color)
2657dd7cddfSDavid du Colombier {
2667dd7cddfSDavid du Colombier     uint raster = fb_dev->raster;
2677dd7cddfSDavid du Colombier     ushort limit = (ushort) - raster;
2687dd7cddfSDavid du Colombier     int yi;
2697dd7cddfSDavid du Colombier     fb_ptr ptr;
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier     fit_fill(dev, x, y, w, h);
2727dd7cddfSDavid du Colombier     set_pixel_write_ptr(ptr, fb_dev, x, y);
2737dd7cddfSDavid du Colombier     /* Most fills are very small and don't cross a page boundary. */
2747dd7cddfSDavid du Colombier     yi = h;
2757dd7cddfSDavid du Colombier     switch (w) {
2767dd7cddfSDavid du Colombier 	case 0:
2777dd7cddfSDavid du Colombier 	    return 0;		/* no-op */
2787dd7cddfSDavid du Colombier 	case 1:
2797dd7cddfSDavid du Colombier 	    while (--yi >= 0 && PTR_OFF(ptr) < limit)
2807dd7cddfSDavid du Colombier 		ptr[0] = (byte) color,
2817dd7cddfSDavid du Colombier 		    ptr += raster;
2827dd7cddfSDavid du Colombier 	    if (!++yi)
2837dd7cddfSDavid du Colombier 		return 0;
2847dd7cddfSDavid du Colombier 	    break;
2857dd7cddfSDavid du Colombier 	case 2:
2867dd7cddfSDavid du Colombier 	    while (--yi >= 0 && PTR_OFF(ptr) < limit)
2877dd7cddfSDavid du Colombier 		ptr[0] = ptr[1] = (byte) color,
2887dd7cddfSDavid du Colombier 		    ptr += raster;
2897dd7cddfSDavid du Colombier 	    if (!++yi)
2907dd7cddfSDavid du Colombier 		return 0;
2917dd7cddfSDavid du Colombier 	    break;
2927dd7cddfSDavid du Colombier 	case 3:
2937dd7cddfSDavid du Colombier 	    while (--yi >= 0 && PTR_OFF(ptr) < limit)
2947dd7cddfSDavid du Colombier 		ptr[0] = ptr[1] = ptr[2] = (byte) color,
2957dd7cddfSDavid du Colombier 		    ptr += raster;
2967dd7cddfSDavid du Colombier 	    if (!++yi)
2977dd7cddfSDavid du Colombier 		return 0;
2987dd7cddfSDavid du Colombier 	    break;
2997dd7cddfSDavid du Colombier 	case 4:
3007dd7cddfSDavid du Colombier 	    while (--yi >= 0 && PTR_OFF(ptr) < limit)
3017dd7cddfSDavid du Colombier 		ptr[0] = ptr[1] = ptr[2] = ptr[3] = (byte) color,
3027dd7cddfSDavid du Colombier 		    ptr += raster;
3037dd7cddfSDavid du Colombier 	    if (!++yi)
3047dd7cddfSDavid du Colombier 		return 0;
3057dd7cddfSDavid du Colombier 	    break;
3067dd7cddfSDavid du Colombier 	default:
3077dd7cddfSDavid du Colombier 	    if (w < 0)
3087dd7cddfSDavid du Colombier 		return 0;
3097dd7cddfSDavid du Colombier 	    /* Check for erasepage. */
3107dd7cddfSDavid du Colombier 	    if (w == dev->width && h == dev->height &&
3117dd7cddfSDavid du Colombier 		color < first_dc_index
3127dd7cddfSDavid du Colombier 		)
3137dd7cddfSDavid du Colombier 		svga_init_colors(dev);
3147dd7cddfSDavid du Colombier     }
3157dd7cddfSDavid du Colombier     while (--yi >= 0) {
3167dd7cddfSDavid du Colombier 	if (PTR_OFF(ptr) < limit) {
3177dd7cddfSDavid du Colombier 	    memset(ptr, (byte) color, w);
3187dd7cddfSDavid du Colombier 	    ptr += raster;
3197dd7cddfSDavid du Colombier 	} else if (PTR_OFF(ptr) <= (ushort) (-w)) {
3207dd7cddfSDavid du Colombier 	    memset(ptr, (byte) color, w);
3217dd7cddfSDavid du Colombier 	    if (yi > 0)
3227dd7cddfSDavid du Colombier 		set_pixel_write_ptr(ptr, fb_dev, x, y + h - yi);
3237dd7cddfSDavid du Colombier 	} else {
3247dd7cddfSDavid du Colombier 	    uint left = (uint) 0x10000 - PTR_OFF(ptr);
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 	    memset(ptr, (byte) color, left);
3277dd7cddfSDavid du Colombier 	    set_pixel_write_ptr(ptr, fb_dev, x + left, y + h - 1 - yi);
3287dd7cddfSDavid du Colombier 	    memset(ptr, (byte) color, w - left);
3297dd7cddfSDavid du Colombier 	    ptr += raster - left;
3307dd7cddfSDavid du Colombier 	}
3317dd7cddfSDavid du Colombier     }
3327dd7cddfSDavid du Colombier     return 0;
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier /* Copy a monochrome bitmap.  The colors are given explicitly. */
3367dd7cddfSDavid du Colombier /* Color = gx_no_color_index means transparent (no effect on the image). */
3377dd7cddfSDavid du Colombier 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)3387dd7cddfSDavid du Colombier svga_copy_mono(gx_device * dev,
3397dd7cddfSDavid du Colombier 	       const byte * base, int sourcex, int sraster, gx_bitmap_id id,
3407dd7cddfSDavid du Colombier       int x, int y, int w, int h, gx_color_index czero, gx_color_index cone)
3417dd7cddfSDavid du Colombier {
3427dd7cddfSDavid du Colombier     uint raster = fb_dev->raster;
3437dd7cddfSDavid du Colombier     ushort limit;
3447dd7cddfSDavid du Colombier     register int wi;
3457dd7cddfSDavid du Colombier     uint skip;
3467dd7cddfSDavid du Colombier     int yi;
3477dd7cddfSDavid du Colombier     register fb_ptr ptr = (fb_ptr) 0;
3487dd7cddfSDavid du Colombier     const byte *srow;
3497dd7cddfSDavid du Colombier     uint invert;
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
3527dd7cddfSDavid du Colombier     limit = (ushort) - w;
3537dd7cddfSDavid du Colombier     skip = raster - w + 1;
3547dd7cddfSDavid du Colombier     srow = base + (sourcex >> 3);
3557dd7cddfSDavid du Colombier #define izero (int)czero
3567dd7cddfSDavid du Colombier #define ione (int)cone
3577dd7cddfSDavid du Colombier     if (ione == no_color) {
3587dd7cddfSDavid du Colombier 	gx_color_index temp;
3597dd7cddfSDavid du Colombier 
3607dd7cddfSDavid du Colombier 	if (izero == no_color)
3617dd7cddfSDavid du Colombier 	    return 0;		/* no-op */
3627dd7cddfSDavid du Colombier 	temp = czero;
3637dd7cddfSDavid du Colombier 	czero = cone;
3647dd7cddfSDavid du Colombier 	cone = temp;
3657dd7cddfSDavid du Colombier 	invert = ~0;
3667dd7cddfSDavid du Colombier     } else
3677dd7cddfSDavid du Colombier 	invert = 0;
3687dd7cddfSDavid du Colombier     /* Pre-filling saves us a test in the loop, */
3697dd7cddfSDavid du Colombier     /* and since tiling is uncommon, we come out ahead. */
3707dd7cddfSDavid du Colombier     if (izero != no_color)
3717dd7cddfSDavid du Colombier 	svga_fill_rectangle(dev, x, y, w, h, czero);
3727dd7cddfSDavid du Colombier     for (yi = 0; yi < h; yi++) {
3737dd7cddfSDavid du Colombier 	const byte *sptr = srow;
3747dd7cddfSDavid du Colombier 	uint bits;
3757dd7cddfSDavid du Colombier 	int bitno = sourcex & 7;
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier 	wi = w;
3787dd7cddfSDavid du Colombier 	if (PTR_OFF(ptr) <= skip) {
3797dd7cddfSDavid du Colombier 	    set_pixel_write_ptr(ptr, fb_dev, x, y + yi);
3807dd7cddfSDavid du Colombier 	} else if (PTR_OFF(ptr) > limit) {	/* We're crossing a page boundary. */
3817dd7cddfSDavid du Colombier 	    /* This is extremely rare, so it doesn't matter */
3827dd7cddfSDavid du Colombier 	    /* how slow it is. */
3837dd7cddfSDavid du Colombier 	    int xi = (ushort) - PTR_OFF(ptr);
3847dd7cddfSDavid du Colombier 
3857dd7cddfSDavid du Colombier 	    svga_copy_mono(dev, srow, sourcex & 7, sraster,
3867dd7cddfSDavid du Colombier 			   gx_no_bitmap_id, x, y + yi, xi, 1,
3877dd7cddfSDavid du Colombier 			   gx_no_color_index, cone);
3887dd7cddfSDavid du Colombier 	    set_pixel_write_ptr(ptr, fb_dev, x + xi, y + yi);
3897dd7cddfSDavid du Colombier 	    sptr = srow - (sourcex >> 3) + ((sourcex + xi) >> 3);
3907dd7cddfSDavid du Colombier 	    bitno = (sourcex + xi) & 7;
3917dd7cddfSDavid du Colombier 	    wi -= xi;
3927dd7cddfSDavid du Colombier 	}
3937dd7cddfSDavid du Colombier 	bits = *sptr ^ invert;
3947dd7cddfSDavid du Colombier 	switch (bitno) {
3957dd7cddfSDavid du Colombier #define ifbit(msk)\
3967dd7cddfSDavid du Colombier   if ( bits & msk ) *ptr = (byte)ione;\
3977dd7cddfSDavid du Colombier   if ( !--wi ) break; ptr++
3987dd7cddfSDavid du Colombier 	    case 0:
3997dd7cddfSDavid du Colombier 	      bit0:ifbit(0x80);
4007dd7cddfSDavid du Colombier 	    case 1:
4017dd7cddfSDavid du Colombier 		ifbit(0x40);
4027dd7cddfSDavid du Colombier 	    case 2:
4037dd7cddfSDavid du Colombier 		ifbit(0x20);
4047dd7cddfSDavid du Colombier 	    case 3:
4057dd7cddfSDavid du Colombier 		ifbit(0x10);
4067dd7cddfSDavid du Colombier 	    case 4:
4077dd7cddfSDavid du Colombier 		ifbit(0x08);
4087dd7cddfSDavid du Colombier 	    case 5:
4097dd7cddfSDavid du Colombier 		ifbit(0x04);
4107dd7cddfSDavid du Colombier 	    case 6:
4117dd7cddfSDavid du Colombier 		ifbit(0x02);
4127dd7cddfSDavid du Colombier 	    case 7:
4137dd7cddfSDavid du Colombier 		ifbit(0x01);
4147dd7cddfSDavid du Colombier #undef ifbit
4157dd7cddfSDavid du Colombier 		bits = *++sptr ^ invert;
4167dd7cddfSDavid du Colombier 		goto bit0;
4177dd7cddfSDavid du Colombier 	}
4187dd7cddfSDavid du Colombier 	ptr += skip;
4197dd7cddfSDavid du Colombier 	srow += sraster;
4207dd7cddfSDavid du Colombier     }
4217dd7cddfSDavid du Colombier #undef izero
4227dd7cddfSDavid du Colombier #undef ione
4237dd7cddfSDavid du Colombier     return 0;
4247dd7cddfSDavid du Colombier }
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier /* Copy a color pixelmap.  This is just like a bitmap, */
4277dd7cddfSDavid du Colombier /* except that each pixel takes 8 bits instead of 1. */
4287dd7cddfSDavid du Colombier 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)4297dd7cddfSDavid du Colombier svga_copy_color(gx_device * dev,
4307dd7cddfSDavid du Colombier 		const byte * base, int sourcex, int sraster, gx_bitmap_id id,
4317dd7cddfSDavid du Colombier 		int x, int y, int w, int h)
4327dd7cddfSDavid du Colombier {
4337dd7cddfSDavid du Colombier     int xi, yi;
4347dd7cddfSDavid du Colombier     int skip;
4357dd7cddfSDavid du Colombier     const byte *sptr;
4367dd7cddfSDavid du Colombier     fb_ptr ptr;
4377dd7cddfSDavid du Colombier 
4387dd7cddfSDavid du Colombier     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
4397dd7cddfSDavid du Colombier     skip = sraster - w;
4407dd7cddfSDavid du Colombier     sptr = base + sourcex;
4417dd7cddfSDavid du Colombier     for (yi = y; yi - y < h; yi++) {
4427dd7cddfSDavid du Colombier 	ptr = 0;
4437dd7cddfSDavid du Colombier 	for (xi = x; xi - x < w; xi++) {
4447dd7cddfSDavid du Colombier 	    if (PTR_OFF(ptr) == 0)
4457dd7cddfSDavid du Colombier 		set_pixel_write_ptr(ptr, fb_dev, xi, yi);
4467dd7cddfSDavid du Colombier 	    *ptr++ = *sptr++;
4477dd7cddfSDavid du Colombier 	}
4487dd7cddfSDavid du Colombier 	sptr += skip;
4497dd7cddfSDavid du Colombier     }
4507dd7cddfSDavid du Colombier     return 0;
4517dd7cddfSDavid du Colombier }
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier /* Put parameters. */
4547dd7cddfSDavid du Colombier int
svga_put_params(gx_device * dev,gs_param_list * plist)4557dd7cddfSDavid du Colombier svga_put_params(gx_device * dev, gs_param_list * plist)
4567dd7cddfSDavid du Colombier {
4577dd7cddfSDavid du Colombier     int ecode = 0;
4587dd7cddfSDavid du Colombier     int code;
4597dd7cddfSDavid du Colombier     const char *param_name;
4607dd7cddfSDavid du Colombier 
4617dd7cddfSDavid du Colombier     if ((code = ecode) < 0 ||
4627dd7cddfSDavid du Colombier 	(code = gx_default_put_params(dev, plist)) < 0
4637dd7cddfSDavid du Colombier 	) {
4647dd7cddfSDavid du Colombier     }
4657dd7cddfSDavid du Colombier     return code;
4667dd7cddfSDavid du Colombier }
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier /* Read scan lines back from the frame buffer. */
4697dd7cddfSDavid du Colombier int
svga_get_bits(gx_device * dev,int y,byte * data,byte ** actual_data)4707dd7cddfSDavid du Colombier svga_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data)
4717dd7cddfSDavid du Colombier {
4727dd7cddfSDavid du Colombier     uint bytes_per_row = dev->width;
4737dd7cddfSDavid du Colombier     ushort limit = (ushort) - bytes_per_row;
4747dd7cddfSDavid du Colombier     fb_ptr src;
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier     if (y < 0 || y >= dev->height)
4777dd7cddfSDavid du Colombier 	return gs_error_rangecheck;
4787dd7cddfSDavid du Colombier     set_pixel_read_ptr(src, fb_dev, 0, y);
4797dd7cddfSDavid du Colombier     /* The logic here is similar to fill_rectangle. */
4807dd7cddfSDavid du Colombier     if (PTR_OFF(src) <= limit)
4817dd7cddfSDavid du Colombier 	memcpy(data, src, bytes_per_row);
4827dd7cddfSDavid du Colombier     else {
4837dd7cddfSDavid du Colombier 	uint left = (uint) 0x10000 - PTR_OFF(src);
4847dd7cddfSDavid du Colombier 
4857dd7cddfSDavid du Colombier 	memcpy(data, src, left);
4867dd7cddfSDavid du Colombier 	set_pixel_read_ptr(src, fb_dev, left, y);
4877dd7cddfSDavid du Colombier 	memcpy(data + left, src, bytes_per_row - left);
4887dd7cddfSDavid du Colombier     }
4897dd7cddfSDavid du Colombier     if (actual_data != 0)
4907dd7cddfSDavid du Colombier 	*actual_data = data;
4917dd7cddfSDavid du Colombier     return 0;
4927dd7cddfSDavid du Colombier }
4937dd7cddfSDavid du Colombier 
4947dd7cddfSDavid du Colombier /* Copy an alpha-map to the screen. */
4957dd7cddfSDavid du Colombier /* Depth is 1, 2, or 4. */
4967dd7cddfSDavid du Colombier 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)4977dd7cddfSDavid du Colombier svga_copy_alpha(gx_device * dev, const byte * base, int sourcex,
4987dd7cddfSDavid du Colombier 		int sraster, gx_bitmap_id id, int x, int y, int w, int h,
4997dd7cddfSDavid du Colombier 		gx_color_index color, int depth)
5007dd7cddfSDavid du Colombier {
5017dd7cddfSDavid du Colombier     int xi, yi;
5027dd7cddfSDavid du Colombier     int skip;
5037dd7cddfSDavid du Colombier     const byte *sptr;
5047dd7cddfSDavid du Colombier     byte mask;
5057dd7cddfSDavid du Colombier     int ishift;
5067dd7cddfSDavid du Colombier 
5077dd7cddfSDavid du Colombier     /* We fake alpha by interpreting it as saturation, i.e., */
5087dd7cddfSDavid du Colombier     /* alpha = 0 is white, alpha = 1 is the full color. */
5097dd7cddfSDavid du Colombier     byte shades[16];
5107dd7cddfSDavid du Colombier     gx_color_value rgb[3];
5117dd7cddfSDavid du Colombier     int log2_depth = depth >> 1;	/* works for 1,2,4 */
5127dd7cddfSDavid du Colombier     int n1 = (1 << depth) - 1;
5137dd7cddfSDavid du Colombier 
5147dd7cddfSDavid du Colombier     fit_copy(dev, base, sourcex, sraster, id, x, y, w, h);
5157dd7cddfSDavid du Colombier     shades[0] = (byte) svga_map_rgb_color(dev, gx_max_color_value,
5167dd7cddfSDavid du Colombier 					  gx_max_color_value,
5177dd7cddfSDavid du Colombier 					  gx_max_color_value);
5187dd7cddfSDavid du Colombier     shades[n1] = (byte) color;
5197dd7cddfSDavid du Colombier     if (n1 > 1) {
5207dd7cddfSDavid du Colombier 	memset(shades + 1, 255, n1 - 1);
5217dd7cddfSDavid du Colombier 	svga_map_color_rgb(dev, color, rgb);
5227dd7cddfSDavid du Colombier     }
5237dd7cddfSDavid du Colombier     skip = sraster - ((w * depth) >> 3);
5247dd7cddfSDavid du Colombier     sptr = base + (sourcex >> (3 - log2_depth));
5257dd7cddfSDavid du Colombier     mask = n1;
5267dd7cddfSDavid du Colombier     ishift = (~sourcex & (7 >> log2_depth)) << log2_depth;
5277dd7cddfSDavid du Colombier     for (yi = y; yi - y < h; yi++) {
5287dd7cddfSDavid du Colombier 	fb_ptr ptr = 0;
5297dd7cddfSDavid du Colombier 	int shift = ishift;
5307dd7cddfSDavid du Colombier 
5317dd7cddfSDavid du Colombier 	for (xi = x; xi - x < w; xi++, ptr++) {
5327dd7cddfSDavid du Colombier 	    uint a = (*sptr >> shift) & mask;
5337dd7cddfSDavid du Colombier 
5347dd7cddfSDavid du Colombier 	    if (PTR_OFF(ptr) == 0)
5357dd7cddfSDavid du Colombier 		set_pixel_write_ptr(ptr, fb_dev, xi, yi);
5367dd7cddfSDavid du Colombier 	  map:if (a != 0) {
5377dd7cddfSDavid du Colombier 		byte ci = shades[a];
5387dd7cddfSDavid du Colombier 
5397dd7cddfSDavid du Colombier 		if (ci == 255) {	/* Map the color now. */
5407dd7cddfSDavid du Colombier #define make_shade(v, alpha, n1)\
5417dd7cddfSDavid du Colombier   (gx_max_color_value -\
5427dd7cddfSDavid du Colombier    ((ulong)(gx_max_color_value - (v)) * (alpha) / (n1)))
5437dd7cddfSDavid du Colombier 		    gx_color_value r =
5447dd7cddfSDavid du Colombier 		    make_shade(rgb[0], a, n1);
5457dd7cddfSDavid du Colombier 		    gx_color_value g =
5467dd7cddfSDavid du Colombier 		    make_shade(rgb[1], a, n1);
5477dd7cddfSDavid du Colombier 		    gx_color_value b =
5487dd7cddfSDavid du Colombier 		    make_shade(rgb[2], a, n1);
5497dd7cddfSDavid du Colombier 		    gx_color_index sci =
5507dd7cddfSDavid du Colombier 		    svga_map_rgb_color(dev, r, g, b);
5517dd7cddfSDavid du Colombier 
5527dd7cddfSDavid du Colombier 		    if (sci == gx_no_color_index) {
5537dd7cddfSDavid du Colombier 			a += (n1 + 1 - a) >> 1;
5547dd7cddfSDavid du Colombier 			goto map;
5557dd7cddfSDavid du Colombier 		    }
5567dd7cddfSDavid du Colombier 		    shades[a] = ci = (byte) sci;
5577dd7cddfSDavid du Colombier 		}
5587dd7cddfSDavid du Colombier 		*ptr = ci;
5597dd7cddfSDavid du Colombier 	    }
5607dd7cddfSDavid du Colombier 	    if (shift == 0)
5617dd7cddfSDavid du Colombier 		shift = 8 - depth, sptr++;
5627dd7cddfSDavid du Colombier 	    else
5637dd7cddfSDavid du Colombier 		shift -= depth;
5647dd7cddfSDavid du Colombier 	}
5657dd7cddfSDavid du Colombier 	sptr += skip;
5667dd7cddfSDavid du Colombier     }
5677dd7cddfSDavid du Colombier     return 0;
5687dd7cddfSDavid du Colombier }
5697dd7cddfSDavid du Colombier 
5707dd7cddfSDavid du Colombier /* ------ The VESA device ------ */
5717dd7cddfSDavid du Colombier 
5727dd7cddfSDavid du Colombier private dev_proc_open_device(vesa_open);
5737dd7cddfSDavid du Colombier private const gx_device_procs vesa_procs = svga_procs(vesa_open);
574*593dc095SDavid du Colombier int vesa_get_mode(void);
575*593dc095SDavid du Colombier void vesa_set_mode(int);
576*593dc095SDavid du Colombier private void vesa_set_page(gx_device_svga *, int, int);
5777dd7cddfSDavid du Colombier gx_device_svga far_data gs_vesa_device =
5787dd7cddfSDavid du Colombier svga_device(vesa_procs, "vesa", vesa_get_mode, vesa_set_mode, vesa_set_page);
5797dd7cddfSDavid du Colombier 
5807dd7cddfSDavid du Colombier /* Define the structures for information returned by the BIOS. */
5817dd7cddfSDavid du Colombier #define bits_include(a, m) !(~(a) & (m))
5827dd7cddfSDavid du Colombier /* Information about the BIOS capabilities. */
5837dd7cddfSDavid du Colombier typedef struct {
5847dd7cddfSDavid du Colombier     byte vesa_signature[4];	/* "VESA" */
5857dd7cddfSDavid du Colombier     ushort vesa_version;
5867dd7cddfSDavid du Colombier     char *product_info;		/* product name string */
5877dd7cddfSDavid du Colombier     byte capabilities[4];	/* (undefined) */
5887dd7cddfSDavid du Colombier     ushort *mode_list;		/* supported video modes, -1 ends */
5897dd7cddfSDavid du Colombier } vga_bios_info;
5907dd7cddfSDavid du Colombier 
5917dd7cddfSDavid du Colombier /* Information about an individual VESA mode. */
5927dd7cddfSDavid du Colombier typedef enum {
5937dd7cddfSDavid du Colombier     m_supported = 1,
5947dd7cddfSDavid du Colombier     m_graphics = 0x10
5957dd7cddfSDavid du Colombier } mode_attribute;
5967dd7cddfSDavid du Colombier typedef enum {
5977dd7cddfSDavid du Colombier     w_supported = 1,
5987dd7cddfSDavid du Colombier     w_readable = 2,
5997dd7cddfSDavid du Colombier     w_writable = 4
6007dd7cddfSDavid du Colombier } win_attribute;
6017dd7cddfSDavid du Colombier typedef struct {
6027dd7cddfSDavid du Colombier     ushort mode_attributes;
6037dd7cddfSDavid du Colombier     byte win_a_attributes;
6047dd7cddfSDavid du Colombier     byte win_b_attributes;
6057dd7cddfSDavid du Colombier     ushort win_granularity;
6067dd7cddfSDavid du Colombier     ushort win_size;
6077dd7cddfSDavid du Colombier     ushort win_a_segment;
6087dd7cddfSDavid du Colombier     ushort win_b_segment;
609*593dc095SDavid du Colombier     void (*win_func_ptr) (int, int);
6107dd7cddfSDavid du Colombier     ushort bytes_per_line;
6117dd7cddfSDavid du Colombier     /* Optional information */
6127dd7cddfSDavid du Colombier     ushort x_resolution;
6137dd7cddfSDavid du Colombier     ushort y_resolution;
6147dd7cddfSDavid du Colombier     byte x_char_size;
6157dd7cddfSDavid du Colombier     byte y_char_size;
6167dd7cddfSDavid du Colombier     byte number_of_planes;
6177dd7cddfSDavid du Colombier     byte bits_per_pixel;
6187dd7cddfSDavid du Colombier     byte number_of_banks;
6197dd7cddfSDavid du Colombier     byte memory_model;
6207dd7cddfSDavid du Colombier     byte bank_size;
6217dd7cddfSDavid du Colombier     /* Padding to 256 bytes */
6227dd7cddfSDavid du Colombier     byte _padding[256 - 29];
6237dd7cddfSDavid du Colombier } vesa_info;
6247dd7cddfSDavid du Colombier 
6257dd7cddfSDavid du Colombier /* Read the device mode */
6267dd7cddfSDavid du Colombier int
vesa_get_mode(void)6277dd7cddfSDavid du Colombier vesa_get_mode(void)
6287dd7cddfSDavid du Colombier {
6297dd7cddfSDavid du Colombier     registers regs;
6307dd7cddfSDavid du Colombier 
6317dd7cddfSDavid du Colombier     regs.h.ah = 0x4f;
6327dd7cddfSDavid du Colombier     regs.h.al = 0x03;
6337dd7cddfSDavid du Colombier     int86(0x10, &regs, &regs);
6347dd7cddfSDavid du Colombier     return regs.rshort.bx;
6357dd7cddfSDavid du Colombier }
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier /* Set the device mode */
6387dd7cddfSDavid du Colombier void
vesa_set_mode(int mode)6397dd7cddfSDavid du Colombier vesa_set_mode(int mode)
6407dd7cddfSDavid du Colombier {
6417dd7cddfSDavid du Colombier     registers regs;
6427dd7cddfSDavid du Colombier 
6437dd7cddfSDavid du Colombier     regs.h.ah = 0x4f;
6447dd7cddfSDavid du Colombier     regs.h.al = 0x02;
6457dd7cddfSDavid du Colombier     regs.rshort.bx = mode;
6467dd7cddfSDavid du Colombier     int86(0x10, &regs, &regs);
6477dd7cddfSDavid du Colombier }
6487dd7cddfSDavid du Colombier 
6497dd7cddfSDavid du Colombier /* Read information about a device mode */
6507dd7cddfSDavid du Colombier private int
vesa_get_info(int mode,vesa_info _ss * info)6517dd7cddfSDavid du Colombier vesa_get_info(int mode, vesa_info _ss * info)
6527dd7cddfSDavid du Colombier {
6537dd7cddfSDavid du Colombier     registers regs;
6547dd7cddfSDavid du Colombier     struct SREGS sregs;
6557dd7cddfSDavid du Colombier 
6567dd7cddfSDavid du Colombier     regs.h.ah = 0x4f;
6577dd7cddfSDavid du Colombier     regs.h.al = 0x01;
6587dd7cddfSDavid du Colombier     regs.rshort.cx = mode;
6597dd7cddfSDavid du Colombier     segread(&sregs);
6607dd7cddfSDavid du Colombier     sregs.es = sregs.ss;
6617dd7cddfSDavid du Colombier     regs.rshort.di = PTR_OFF(info);
6627dd7cddfSDavid du Colombier     int86x(0x10, &regs, &regs, &sregs);
6637dd7cddfSDavid du Colombier #ifdef DEBUG
6647dd7cddfSDavid du Colombier     if (regs.h.ah == 0 && regs.h.al == 0x4f)
6657dd7cddfSDavid du Colombier 	dlprintf8("vesa_get_info(%x): ma=%x wa=%x/%x wg=%x ws=%x wseg=%x/%x\n",
6667dd7cddfSDavid du Colombier 		  mode, info->mode_attributes,
6677dd7cddfSDavid du Colombier 		  info->win_a_attributes, info->win_b_attributes,
6687dd7cddfSDavid du Colombier 		  info->win_granularity, info->win_size,
6697dd7cddfSDavid du Colombier 		  info->win_a_segment, info->win_b_segment);
6707dd7cddfSDavid du Colombier     else
6717dd7cddfSDavid du Colombier 	dlprintf3("vesa_get_info(%x) failed: ah=%x al=%x\n",
6727dd7cddfSDavid du Colombier 		  mode, regs.h.ah, regs.h.al);
6737dd7cddfSDavid du Colombier #endif
6747dd7cddfSDavid du Colombier     return (regs.h.ah == 0 && regs.h.al == 0x4f ? 0 : -1);
6757dd7cddfSDavid du Colombier }
6767dd7cddfSDavid du Colombier 
6777dd7cddfSDavid du Colombier /* Initialize the graphics mode. */
6787dd7cddfSDavid du Colombier /* Shared routine to look up a VESA-compatible BIOS mode. */
6797dd7cddfSDavid du Colombier private int
vesa_find_mode(gx_device * dev,const mode_info * mode_table)6807dd7cddfSDavid du Colombier vesa_find_mode(gx_device * dev, const mode_info * mode_table)
6817dd7cddfSDavid du Colombier {				/* Select the proper video mode */
6827dd7cddfSDavid du Colombier     vesa_info info;
6837dd7cddfSDavid du Colombier     const mode_info *mip;
6847dd7cddfSDavid du Colombier 
6857dd7cddfSDavid du Colombier     for (mip = mode_table; mip->mode >= 0; mip++) {
6867dd7cddfSDavid du Colombier 	if (mip->width >= fb_dev->width &&
6877dd7cddfSDavid du Colombier 	    mip->height >= fb_dev->height &&
6887dd7cddfSDavid du Colombier 	    vesa_get_info(mip->mode, &info) >= 0 &&
6897dd7cddfSDavid du Colombier 	    bits_include(info.mode_attributes,
6907dd7cddfSDavid du Colombier 			 m_supported | m_graphics) &&
6917dd7cddfSDavid du Colombier 	    info.win_granularity <= 64 &&
6927dd7cddfSDavid du Colombier 	    (info.win_granularity & (info.win_granularity - 1)) == 0 &&
6937dd7cddfSDavid du Colombier 	    info.win_size == 64 &&
6947dd7cddfSDavid du Colombier 	    bits_include(info.win_a_attributes,
6957dd7cddfSDavid du Colombier 			 w_supported) &&
6967dd7cddfSDavid du Colombier 	    info.win_a_segment == regen
6977dd7cddfSDavid du Colombier 	    ) {			/* Make sure we can both read & write. */
6987dd7cddfSDavid du Colombier 	    /* Initialize for the default case. */
6997dd7cddfSDavid du Colombier 	    fb_dev->wnum_read = 0;
7007dd7cddfSDavid du Colombier 	    fb_dev->wnum_write = 0;
7017dd7cddfSDavid du Colombier 	    if (bits_include(info.win_a_attributes,
7027dd7cddfSDavid du Colombier 			     w_readable | w_writable)
7037dd7cddfSDavid du Colombier 		)
7047dd7cddfSDavid du Colombier 		break;
7057dd7cddfSDavid du Colombier 	    else if (info.win_b_segment == regen &&
7067dd7cddfSDavid du Colombier 		     bits_include(info.win_b_attributes,
7077dd7cddfSDavid du Colombier 				  w_supported) &&
7087dd7cddfSDavid du Colombier 		     bits_include(info.win_a_attributes |
7097dd7cddfSDavid du Colombier 				  info.win_b_attributes,
7107dd7cddfSDavid du Colombier 				  w_readable | w_writable)
7117dd7cddfSDavid du Colombier 		) {		/* Two superimposed windows. */
7127dd7cddfSDavid du Colombier 		if (!bits_include(info.win_a_attributes,
7137dd7cddfSDavid du Colombier 				  w_writable)
7147dd7cddfSDavid du Colombier 		    )
7157dd7cddfSDavid du Colombier 		    fb_dev->wnum_write = 1;
7167dd7cddfSDavid du Colombier 		else
7177dd7cddfSDavid du Colombier 		    fb_dev->wnum_read = 1;
7187dd7cddfSDavid du Colombier 	    }
7197dd7cddfSDavid du Colombier 	    break;
7207dd7cddfSDavid du Colombier 	}
7217dd7cddfSDavid du Colombier     }
7227dd7cddfSDavid du Colombier     if (mip->mode < 0)
7237dd7cddfSDavid du Colombier 	return_error(gs_error_rangecheck);	/* mode not available */
7247dd7cddfSDavid du Colombier     fb_dev->mode = mip;
7257dd7cddfSDavid du Colombier     gx_device_adjust_resolution(dev, mip->width, mip->height, 1);
7267dd7cddfSDavid du Colombier     fb_dev->info.vesa.bios_set_page = info.win_func_ptr;
7277dd7cddfSDavid du Colombier     fb_dev->info.vesa.pn_shift = ilog2(64 / info.win_granularity);
7287dd7cddfSDavid du Colombier     /* Reset the raster per the VESA info. */
7297dd7cddfSDavid du Colombier     fb_dev->raster = info.bytes_per_line;
7307dd7cddfSDavid du Colombier     return 0;
7317dd7cddfSDavid du Colombier }
7327dd7cddfSDavid du Colombier private int
vesa_open(gx_device * dev)7337dd7cddfSDavid du Colombier vesa_open(gx_device * dev)
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier     static const mode_info mode_table[] =
7367dd7cddfSDavid du Colombier     {
7377dd7cddfSDavid du Colombier 	{640, 400, 0x100},
7387dd7cddfSDavid du Colombier 	{640, 480, 0x101},
7397dd7cddfSDavid du Colombier 	{800, 600, 0x103},
7407dd7cddfSDavid du Colombier 	{1024, 768, 0x105},
7417dd7cddfSDavid du Colombier 	{1280, 1024, 0x107},
7427dd7cddfSDavid du Colombier 	{-1, -1, -1}
7437dd7cddfSDavid du Colombier     };
7447dd7cddfSDavid du Colombier     int code = vesa_find_mode(dev, mode_table);
7457dd7cddfSDavid du Colombier 
7467dd7cddfSDavid du Colombier     if (code < 0)
7477dd7cddfSDavid du Colombier 	return code;
7487dd7cddfSDavid du Colombier     return svga_open(dev);
7497dd7cddfSDavid du Colombier }
7507dd7cddfSDavid du Colombier 
7517dd7cddfSDavid du Colombier /* Set the current display page. */
7527dd7cddfSDavid du Colombier private void
vesa_set_page(gx_device_svga * dev,int pn,int wnum)7537dd7cddfSDavid du Colombier vesa_set_page(gx_device_svga * dev, int pn, int wnum)
7547dd7cddfSDavid du Colombier {
7557dd7cddfSDavid du Colombier #if USE_ASM
756*593dc095SDavid du Colombier     extern void vesa_call_set_page(void (*)(int, int), int, int);
7577dd7cddfSDavid du Colombier 
7587dd7cddfSDavid du Colombier     if (dev->info.vesa.bios_set_page != NULL)
7597dd7cddfSDavid du Colombier 	vesa_call_set_page(dev->info.vesa.bios_set_page, pn << dev->info.vesa.pn_shift, wnum);
7607dd7cddfSDavid du Colombier     else
7617dd7cddfSDavid du Colombier #endif
7627dd7cddfSDavid du Colombier     {
7637dd7cddfSDavid du Colombier 	registers regs;
7647dd7cddfSDavid du Colombier 
7657dd7cddfSDavid du Colombier 	regs.rshort.dx = pn << dev->info.vesa.pn_shift;
7667dd7cddfSDavid du Colombier 	regs.h.ah = 0x4f;
7677dd7cddfSDavid du Colombier 	regs.h.al = 5;
7687dd7cddfSDavid du Colombier 	regs.rshort.bx = wnum;
7697dd7cddfSDavid du Colombier 	int86(0x10, &regs, &regs);
7707dd7cddfSDavid du Colombier     }
7717dd7cddfSDavid du Colombier }
7727dd7cddfSDavid du Colombier 
7737dd7cddfSDavid du Colombier /* ------ The ATI Wonder device ------ */
7747dd7cddfSDavid du Colombier 
7757dd7cddfSDavid du Colombier private dev_proc_open_device(atiw_open);
7767dd7cddfSDavid du Colombier private const gx_device_procs atiw_procs = svga_procs(atiw_open);
777*593dc095SDavid du Colombier private int atiw_get_mode(void);
778*593dc095SDavid du Colombier private void atiw_set_mode(int);
779*593dc095SDavid du Colombier private void atiw_set_page(gx_device_svga *, int, int);
7807dd7cddfSDavid du Colombier gx_device_svga far_data gs_atiw_device =
7817dd7cddfSDavid du Colombier svga_device(atiw_procs, "atiw", atiw_get_mode, atiw_set_mode, atiw_set_page);
7827dd7cddfSDavid du Colombier 
7837dd7cddfSDavid du Colombier /* Read the device mode */
7847dd7cddfSDavid du Colombier private int
atiw_get_mode(void)7857dd7cddfSDavid du Colombier atiw_get_mode(void)
7867dd7cddfSDavid du Colombier {
7877dd7cddfSDavid du Colombier     registers regs;
7887dd7cddfSDavid du Colombier 
7897dd7cddfSDavid du Colombier     regs.h.ah = 0xf;
7907dd7cddfSDavid du Colombier     int86(0x10, &regs, &regs);
7917dd7cddfSDavid du Colombier     return regs.h.al;
7927dd7cddfSDavid du Colombier }
7937dd7cddfSDavid du Colombier 
7947dd7cddfSDavid du Colombier /* Set the device mode */
7957dd7cddfSDavid du Colombier private void
atiw_set_mode(int mode)7967dd7cddfSDavid du Colombier atiw_set_mode(int mode)
7977dd7cddfSDavid du Colombier {
7987dd7cddfSDavid du Colombier     registers regs;
7997dd7cddfSDavid du Colombier 
8007dd7cddfSDavid du Colombier     regs.h.ah = 0;
8017dd7cddfSDavid du Colombier     regs.h.al = mode;
8027dd7cddfSDavid du Colombier     int86(0x10, &regs, &regs);
8037dd7cddfSDavid du Colombier }
8047dd7cddfSDavid du Colombier 
8057dd7cddfSDavid du Colombier /* Initialize the graphics mode. */
8067dd7cddfSDavid du Colombier private int
atiw_open(gx_device * dev)8077dd7cddfSDavid du Colombier atiw_open(gx_device * dev)
8087dd7cddfSDavid du Colombier {				/* Select the proper video mode */
8097dd7cddfSDavid du Colombier     {
8107dd7cddfSDavid du Colombier 	static const mode_info mode_table[] =
8117dd7cddfSDavid du Colombier 	{
8127dd7cddfSDavid du Colombier 	    {640, 400, 0x61},
8137dd7cddfSDavid du Colombier 	    {640, 480, 0x62},
8147dd7cddfSDavid du Colombier 	    {800, 600, 0x63},
8157dd7cddfSDavid du Colombier 	    {1024, 768, 0x64},
8167dd7cddfSDavid du Colombier 	    {-1, -1, -1}
8177dd7cddfSDavid du Colombier 	};
8187dd7cddfSDavid du Colombier 	int code = svga_find_mode(dev, mode_table);
8197dd7cddfSDavid du Colombier 
8207dd7cddfSDavid du Colombier 	if (code < 0)
8217dd7cddfSDavid du Colombier 	    return code;	/* mode not available */
8227dd7cddfSDavid du Colombier 	fb_dev->info.atiw.select_reg = *(int *)MK_PTR(0xc000, 0x10);
8237dd7cddfSDavid du Colombier 	return svga_open(dev);
8247dd7cddfSDavid du Colombier     }
8257dd7cddfSDavid du Colombier }
8267dd7cddfSDavid du Colombier 
8277dd7cddfSDavid du Colombier /* Set the current display page. */
8287dd7cddfSDavid du Colombier private void
atiw_set_page(gx_device_svga * dev,int pn,int wnum)8297dd7cddfSDavid du Colombier atiw_set_page(gx_device_svga * dev, int pn, int wnum)
8307dd7cddfSDavid du Colombier {
8317dd7cddfSDavid du Colombier     int select_reg = dev->info.atiw.select_reg;
8327dd7cddfSDavid du Colombier     byte reg;
8337dd7cddfSDavid du Colombier 
8347dd7cddfSDavid du Colombier     disable();
8357dd7cddfSDavid du Colombier     outportb(select_reg, 0xb2);
8367dd7cddfSDavid du Colombier     reg = inportb(select_reg + 1);
8377dd7cddfSDavid du Colombier     outportb(select_reg, 0xb2);
8387dd7cddfSDavid du Colombier     outportb(select_reg + 1, (reg & 0xe1) + (pn << 1));
8397dd7cddfSDavid du Colombier     enable();
8407dd7cddfSDavid du Colombier }
8417dd7cddfSDavid du Colombier 
8427dd7cddfSDavid du Colombier /* ------ The Trident device ------ */
8437dd7cddfSDavid du Colombier 
8447dd7cddfSDavid du Colombier private dev_proc_open_device(tvga_open);
8457dd7cddfSDavid du Colombier private const gx_device_procs tvga_procs = svga_procs(tvga_open);
8467dd7cddfSDavid du Colombier 
8477dd7cddfSDavid du Colombier /* We can use the atiw_get/set_mode procedures. */
848*593dc095SDavid du Colombier private void tvga_set_page(gx_device_svga *, int, int);
8497dd7cddfSDavid du Colombier gx_device_svga far_data gs_tvga_device =
8507dd7cddfSDavid du Colombier svga_device(tvga_procs, "tvga", atiw_get_mode, atiw_set_mode, tvga_set_page);
8517dd7cddfSDavid du Colombier 
8527dd7cddfSDavid du Colombier /* Initialize the graphics mode. */
8537dd7cddfSDavid du Colombier private int
tvga_open(gx_device * dev)8547dd7cddfSDavid du Colombier tvga_open(gx_device * dev)
8557dd7cddfSDavid du Colombier {
8567dd7cddfSDavid du Colombier     fb_dev->wnum_read = 1;
8577dd7cddfSDavid du Colombier     fb_dev->wnum_write = 0;
8587dd7cddfSDavid du Colombier     /* Select the proper video mode */
8597dd7cddfSDavid du Colombier     {
8607dd7cddfSDavid du Colombier 	static const mode_info mode_table[] =
8617dd7cddfSDavid du Colombier 	{
8627dd7cddfSDavid du Colombier 	    {640, 400, 0x5c},
8637dd7cddfSDavid du Colombier 	    {640, 480, 0x5d},
8647dd7cddfSDavid du Colombier 	    {800, 600, 0x5e},
8657dd7cddfSDavid du Colombier 	    {1024, 768, 0x62},
8667dd7cddfSDavid du Colombier 	    {-1, -1, -1}
8677dd7cddfSDavid du Colombier 	};
8687dd7cddfSDavid du Colombier 	int code = svga_find_mode(dev, mode_table);
8697dd7cddfSDavid du Colombier 
8707dd7cddfSDavid du Colombier 	if (code < 0)
8717dd7cddfSDavid du Colombier 	    return code;	/* mode not available */
8727dd7cddfSDavid du Colombier 	return svga_open(dev);
8737dd7cddfSDavid du Colombier     }
8747dd7cddfSDavid du Colombier }
8757dd7cddfSDavid du Colombier 
8767dd7cddfSDavid du Colombier /* Set the current display page. */
8777dd7cddfSDavid du Colombier private void
tvga_set_page(gx_device_svga * dev,int pn,int wnum)8787dd7cddfSDavid du Colombier tvga_set_page(gx_device_svga * dev, int pn, int wnum)
8797dd7cddfSDavid du Colombier {
8807dd7cddfSDavid du Colombier     /* new mode */
8817dd7cddfSDavid du Colombier     outportb(0x3c4, 0x0b);
8827dd7cddfSDavid du Colombier     inportb(0x3c4);
8837dd7cddfSDavid du Colombier 
8847dd7cddfSDavid du Colombier     outportb(0x3c4, 0x0e);
8857dd7cddfSDavid du Colombier     outportb(0x3c5, pn ^ 2);
8867dd7cddfSDavid du Colombier }
8877dd7cddfSDavid du Colombier 
8887dd7cddfSDavid du Colombier /* ------ The Tseng Labs ET3000/4000 devices ------ */
8897dd7cddfSDavid du Colombier 
8907dd7cddfSDavid du Colombier private dev_proc_open_device(tseng_open);
8917dd7cddfSDavid du Colombier private const gx_device_procs tseng_procs =
8927dd7cddfSDavid du Colombier svga_procs(tseng_open);
8937dd7cddfSDavid du Colombier 
8947dd7cddfSDavid du Colombier /* We can use the atiw_get/set_mode procedures. */
895*593dc095SDavid du Colombier private void tseng_set_page(gx_device_svga *, int, int);
8967dd7cddfSDavid du Colombier 
8977dd7cddfSDavid du Colombier /* The 256-color Tseng device */
8987dd7cddfSDavid du Colombier gx_device_svga far_data gs_tseng_device =
8997dd7cddfSDavid du Colombier svga_device(tseng_procs, "tseng", atiw_get_mode, atiw_set_mode, tseng_set_page);
9007dd7cddfSDavid du Colombier 
9017dd7cddfSDavid du Colombier /* Initialize the graphics mode. */
9027dd7cddfSDavid du Colombier private int
tseng_open(gx_device * dev)9037dd7cddfSDavid du Colombier tseng_open(gx_device * dev)
9047dd7cddfSDavid du Colombier {
9057dd7cddfSDavid du Colombier     fb_dev->wnum_read = 1;
9067dd7cddfSDavid du Colombier     fb_dev->wnum_write = 0;
9077dd7cddfSDavid du Colombier     /* Select the proper video mode */
9087dd7cddfSDavid du Colombier     {
9097dd7cddfSDavid du Colombier 	static const mode_info mode_table[] =
9107dd7cddfSDavid du Colombier 	{
9117dd7cddfSDavid du Colombier 	    {640, 350, 0x2d},
9127dd7cddfSDavid du Colombier 	    {640, 480, 0x2e},
9137dd7cddfSDavid du Colombier 	    {800, 600, 0x30},
9147dd7cddfSDavid du Colombier 	    {1024, 768, 0x38},
9157dd7cddfSDavid du Colombier 	    {-1, -1, -1}
9167dd7cddfSDavid du Colombier 	};
9177dd7cddfSDavid du Colombier 	int code = svga_find_mode(dev, mode_table);
9187dd7cddfSDavid du Colombier 	volatile_fb_ptr p0 = (volatile_fb_ptr) MK_PTR(regen, 0);
9197dd7cddfSDavid du Colombier 
9207dd7cddfSDavid du Colombier 	if (code < 0)
9217dd7cddfSDavid du Colombier 	    return code;	/* mode not available */
9227dd7cddfSDavid du Colombier 	code = svga_open(dev);
9237dd7cddfSDavid du Colombier 	if (code < 0)
9247dd7cddfSDavid du Colombier 	    return 0;
9257dd7cddfSDavid du Colombier 	/* Figure out whether we have an ET3000 or an ET4000 */
9267dd7cddfSDavid du Colombier 	/* by playing with the segment register. */
9277dd7cddfSDavid du Colombier 	outportb(0x3cd, 0x44);
9287dd7cddfSDavid du Colombier 	*p0 = 4;		/* byte 0, page 4 */
9297dd7cddfSDavid du Colombier 	outportb(0x3cd, 0x40);
9307dd7cddfSDavid du Colombier 	*p0 = 3;		/* byte 0, page 0 */
9317dd7cddfSDavid du Colombier 	fb_dev->info.tseng.et_model = *p0;
9327dd7cddfSDavid du Colombier 	/* read page 0 if ET3000, */
9337dd7cddfSDavid du Colombier 	/* page 4 if ET4000 */
9347dd7cddfSDavid du Colombier 	return 0;
9357dd7cddfSDavid du Colombier     }
9367dd7cddfSDavid du Colombier }
9377dd7cddfSDavid du Colombier 
9387dd7cddfSDavid du Colombier /* Set the current display page. */
9397dd7cddfSDavid du Colombier private void
tseng_set_page(gx_device_svga * dev,int pn,int wnum)9407dd7cddfSDavid du Colombier tseng_set_page(gx_device_svga * dev, int pn, int wnum)
9417dd7cddfSDavid du Colombier {				/* The ET3000 has read page = 5:3, write page = 2:0; */
9427dd7cddfSDavid du Colombier     /* the ET4000 has read page = 7:4, write page = 3:0. */
9437dd7cddfSDavid du Colombier     int shift = dev->info.tseng.et_model;
9447dd7cddfSDavid du Colombier     int mask = (1 << shift) - 1;
9457dd7cddfSDavid du Colombier 
9467dd7cddfSDavid du Colombier     if (wnum)
9477dd7cddfSDavid du Colombier 	pn <<= shift, mask <<= shift;
9487dd7cddfSDavid du Colombier     outportb(0x3cd, (inportb(0x3cd) & ~mask) + pn);
9497dd7cddfSDavid du Colombier }
9507dd7cddfSDavid du Colombier /* ------ The Cirrus device (CL-GD54XX) ------ */
9517dd7cddfSDavid du Colombier /* Written by Piotr Strzelczyk, BOP s.c., Gda\'nsk, Poland, */
9527dd7cddfSDavid du Colombier /* e-mail contact via B.Jackowski@GUST.org.pl */
9537dd7cddfSDavid du Colombier 
9547dd7cddfSDavid du Colombier private dev_proc_open_device(cirr_open);
9557dd7cddfSDavid du Colombier private gx_device_procs cirr_procs = svga_procs(cirr_open);
9567dd7cddfSDavid du Colombier 
9577dd7cddfSDavid du Colombier /* We can use the atiw_get/set_mode procedures. */
958*593dc095SDavid du Colombier private void cirr_set_page(gx_device_svga *, int, int);
9597dd7cddfSDavid du Colombier gx_device_svga gs_cirr_device =
9607dd7cddfSDavid du Colombier svga_device(cirr_procs, "cirr", atiw_get_mode, atiw_set_mode, cirr_set_page);
9617dd7cddfSDavid du Colombier 
9627dd7cddfSDavid du Colombier /* Initialize the graphics mode. */
9637dd7cddfSDavid du Colombier private int
cirr_open(gx_device * dev)9647dd7cddfSDavid du Colombier cirr_open(gx_device * dev)
9657dd7cddfSDavid du Colombier {
9667dd7cddfSDavid du Colombier     fb_dev->wnum_read = 1;
9677dd7cddfSDavid du Colombier     fb_dev->wnum_write = 0;
9687dd7cddfSDavid du Colombier     /* Select the proper video mode */
9697dd7cddfSDavid du Colombier     {
9707dd7cddfSDavid du Colombier 	static const mode_info mode_table[] =
9717dd7cddfSDavid du Colombier 	{
9727dd7cddfSDavid du Colombier 	    {640, 400, 0x5e},
9737dd7cddfSDavid du Colombier 	    {640, 480, 0x5f},
9747dd7cddfSDavid du Colombier 	    {800, 600, 0x5c},
9757dd7cddfSDavid du Colombier 	    {1024, 768, 0x60},
9767dd7cddfSDavid du Colombier 	    {-1, -1, -1}
9777dd7cddfSDavid du Colombier 	};
9787dd7cddfSDavid du Colombier 	int code = svga_find_mode(dev, mode_table);
9797dd7cddfSDavid du Colombier 
9807dd7cddfSDavid du Colombier 	if (code < 0)
9817dd7cddfSDavid du Colombier 	    return code;	/* mode not available */
9827dd7cddfSDavid du Colombier 	outportb(0x3c4, 0x06);
9837dd7cddfSDavid du Colombier 	outportb(0x3c5, 0x12);
9847dd7cddfSDavid du Colombier 	outportb(0x3ce, 0x0b);
9857dd7cddfSDavid du Colombier 	outportb(0x3cf, (inportb(0x3cf) & 0xde));
9867dd7cddfSDavid du Colombier 	return svga_open(dev);
9877dd7cddfSDavid du Colombier     }
9887dd7cddfSDavid du Colombier }
9897dd7cddfSDavid du Colombier 
9907dd7cddfSDavid du Colombier /* Set the current display page. */
9917dd7cddfSDavid du Colombier private void
cirr_set_page(gx_device_svga * dev,int pn,int wnum)9927dd7cddfSDavid du Colombier cirr_set_page(gx_device_svga * dev, int pn, int wnum)
9937dd7cddfSDavid du Colombier {
9947dd7cddfSDavid du Colombier     outportb(0x3ce, 0x09);
9957dd7cddfSDavid du Colombier     outportb(0x3cf, pn << 4);
9967dd7cddfSDavid du Colombier }
9977dd7cddfSDavid du Colombier 
9987dd7cddfSDavid du Colombier /* ------ The Avance Logic device (mostly experimental) ------ */
9997dd7cddfSDavid du Colombier /* For questions about this device, please contact Stefan Freund */
10007dd7cddfSDavid du Colombier /* <freund@ikp.uni-koeln.de>. */
10017dd7cddfSDavid du Colombier 
10027dd7cddfSDavid du Colombier private dev_proc_open_device(ali_open);
10037dd7cddfSDavid du Colombier private const gx_device_procs ali_procs = svga_procs(ali_open);
10047dd7cddfSDavid du Colombier 
10057dd7cddfSDavid du Colombier /* We can use the atiw_get/set_mode procedures. */
1006*593dc095SDavid du Colombier private void ali_set_page(gx_device_svga *, int, int);
10077dd7cddfSDavid du Colombier 
10087dd7cddfSDavid du Colombier /* The 256-color Avance Logic device */
10097dd7cddfSDavid du Colombier gx_device_svga gs_ali_device =
10107dd7cddfSDavid du Colombier svga_device(ali_procs, "ali", atiw_get_mode, atiw_set_mode,
10117dd7cddfSDavid du Colombier 	    ali_set_page);
10127dd7cddfSDavid du Colombier 
10137dd7cddfSDavid du Colombier /* Initialize the graphics mode. */
10147dd7cddfSDavid du Colombier private int
ali_open(gx_device * dev)10157dd7cddfSDavid du Colombier ali_open(gx_device * dev)
10167dd7cddfSDavid du Colombier {
10177dd7cddfSDavid du Colombier     fb_dev->wnum_read = 1;
10187dd7cddfSDavid du Colombier     fb_dev->wnum_write = 0;
10197dd7cddfSDavid du Colombier     /* Select the proper video mode */
10207dd7cddfSDavid du Colombier     {
10217dd7cddfSDavid du Colombier 	static const mode_info mode_table[] =
10227dd7cddfSDavid du Colombier 	{
10237dd7cddfSDavid du Colombier 	    {640, 400, 0x29},
10247dd7cddfSDavid du Colombier 	    {640, 480, 0x2a},
10257dd7cddfSDavid du Colombier 	    {800, 600, 0x2c},
10267dd7cddfSDavid du Colombier 	    {1024, 768, 0x31},
10277dd7cddfSDavid du Colombier 	    {-1, -1, -1}
10287dd7cddfSDavid du Colombier 	};
10297dd7cddfSDavid du Colombier 	int code = svga_find_mode(dev, mode_table);
10307dd7cddfSDavid du Colombier 
10317dd7cddfSDavid du Colombier 	if (code < 0)
10327dd7cddfSDavid du Colombier 	    return code;	/* mode not available */
10337dd7cddfSDavid du Colombier 	return svga_open(dev);
10347dd7cddfSDavid du Colombier     }
10357dd7cddfSDavid du Colombier 
10367dd7cddfSDavid du Colombier }
10377dd7cddfSDavid du Colombier 
10387dd7cddfSDavid du Colombier /* Set the current display page. */
10397dd7cddfSDavid du Colombier private void
ali_set_page(gx_device_svga * dev,int pn,int wnum)10407dd7cddfSDavid du Colombier ali_set_page(gx_device_svga * dev, int pn, int wnum)
10417dd7cddfSDavid du Colombier {
10427dd7cddfSDavid du Colombier     outportb(0x3d6, pn);	/* read  */
10437dd7cddfSDavid du Colombier     outportb(0x3d7, pn);	/* write */
10447dd7cddfSDavid du Colombier }
1045