Common subdirectories: /home/marco/src/hurdcvs/hurd.bak/console-client/CVS and console-client/CVS diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/Makefile console-client/Makefile --- /home/marco/src/hurdcvs/hurd.bak/console-client/Makefile 2003-08-18 14:17:43.000000000 +0200 +++ console-client/Makefile 2003-08-18 22:15:09.000000000 +0200 @@ -22,7 +22,7 @@ target = console SRCS = console.c timer.c driver.c LCLHDRS = timer.h driver.h display.h input.h bell.h \ unicode.h bdf.h \ - vga-dynafont.h vga-dynacolor.h vga-hw.h vga.h + vga-dynafont.h vga-dynacolor.h vga-hw.h vga.h video-driver.h OBJS = $(filter-out h,$(SRCS:.c=.o)) HURDLIBS = cons threads ports @@ -44,7 +44,7 @@ console: ../libcons/libcons.a ../libport modules = vga pc_kbd generic_speaker vga.so.$(hurd-version): $(patsubst ,%_pic.o,bdf.c vga-dynafont.c \ - vga-dynacolor.c vga-support.c vga.c) + vga-dynacolor.c vga-support.c vga.c vga-mode.c viddrv_vga.c viddrv_s3.c) pc_kbd.so.$(hurd-version): $(patsubst ,%_pic.o,pc-kbd.c) generic_speaker.so.$(hurd-version): $(patsubst ,%_pic.o,generic-speaker.c) diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/README.video console-client/README.video --- /home/marco/src/hurdcvs/hurd.bak/console-client/README.video 1970-01-01 01:00:00.000000000 +0100 +++ console-client/README.video 2003-08-27 21:26:52.000000000 +0200 @@ -0,0 +1,27 @@ +This file descibes the supported hardware and it's limitions. + +The VGA (and compatible) card is fully supported. Most common +available resolutions are 640x400 and 640x480 when using a VGA +monitor. When using a SVGA monitor the resolution can be a bit +higher, but not more than a few pixels. When using a SVGA monitor it +is always possible to increase the refresh rate for some modes. The +real limitation of the card is the pixelclock, it can be set to just +25 and 28 Mhz. Unfortunately the VGA driver is not DPMS capable at +all, but it will support some DPMS powermodes soon (most likely only +on and off). + +The S3 Trio card is capable of much more. It has a freely +programmable pixelclock and supports high resolutions and refresh +rates. Resolutions like 1058x480 were tested in textmode (132x60). +This driver is DPMS capable. + +(WIP) +The nvidia driver isn't capable of programming the pixelclock yet. +Because of this no highresolution textmodes are possible. However it +is possible to change the timings beyond the capabilities of VGA, that +makes some exotic dimensions possible for adventurous people. The +main reason for the nvidia driver to exists is for DPMS support; if +you have a nvidia chipset and want to use DPMS you have to use this +driver. I would like some information about how to program the +pixelclock; the only information I can find about this has a licence I +don't like. diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/vga-hw.h console-client/vga-hw.h --- /home/marco/src/hurdcvs/hurd.bak/console-client/vga-hw.h 2003-08-18 14:17:44.000000000 +0200 +++ console-client/vga-hw.h 2003-08-26 22:42:53.000000000 +0200 @@ -48,6 +48,7 @@ /* The clocking mode subregister. */ #define VGA_SEQ_CLOCK_MODE_ADDR 0x01 #define VGA_SEQ_CLOCK_MODE_8 0x01 /* 8-pixel width for fonts. */ +#define VGA_SEQ_CLOCK_MODE_SOFF 0x20 /* The map subregister specifies which planes are written to. */ #define VGA_SEQ_MAP_ADDR 0x02 @@ -104,23 +105,69 @@ /* The CRTC Registers. XXX Depends on the I/O Address Select field. However, the only need to use the other values is for compatibility with monochrome adapters. */ -#define VGA_CRT_ADDR_REG 0x3d4 -#define VGA_CRT_DATA_REG 0x3d5 +#define VGA_CRTC_ADDR_REG 0x3d4 +#define VGA_CRTC_DATA_REG 0x3d5 +/* Number of CRTC subregisters. */ +#define VGA_CRTC_REG_CNT 25 /* The maximum scan line subregister. */ -#define VGA_CRT_MAX_SCAN_LINE 0x09 +#define VGA_CRTC_MAX_SCAN_LINE 0x09 +#define VGA_CRTC_SVB9 0x20 /* The cursor start subregister. */ -#define VGA_CRT_CURSOR_START 0x0a -#define VGA_CRT_CURSOR_DISABLE 0x20 +#define VGA_CRTC_CURSOR_START 0x0a +#define VGA_CRTC_CURSOR_DISABLE 0x20 /* The cursor end subregister. */ -#define VGA_CRT_CURSOR_END 0x0b +#define VGA_CRTC_CURSOR_END 0x0b /* The cursor position subregisters. */ -#define VGA_CRT_CURSOR_HIGH 0x0e -#define VGA_CRT_CURSOR_LOW 0x0f +#define VGA_CRTC_CURSOR_HIGH 0x0e +#define VGA_CRTC_CURSOR_LOW 0x0f +/* Overflow register. */ +#define VGA_CRTC_OVERFLOW 0x07 +#define VGA_CRTC_VT8 0x01 +#define VGA_CRTC_VDE8 0x02 +#define VGA_CRTC_VRS8 0x04 +#define VGA_CRTC_SVB8 0x08 +#define VGA_CRTC_LC8 0x10 +#define VGA_CRTC_VT9 0x20 +#define VGA_CRTC_VDE9 0x40 +#define VGA_CRTC_VRS9 0x80 + +/* The vertical retrace subregisters. */ +#define VGA_CRTC_VRETRACE_START 0x10 +#define VGA_CRTC_VRETRACE_END 0x11 +/* Protects write access to CRTC registers 0 - 7. This bit is stored + in the End Vertical Retrace subregister. */ +#define VGA_CRTC_PROTECT 0x80 + +/* The horizontal retrace subregisters. */ +#define VGA_CRTC_HRETRACE_START 0x04 +#define VGA_CRTC_HRETRACE_END 0x05 +/* Bit 5 for End Horizontal Blanking is stored in the Horizontal + Retrace End subregister. */ +#define VGA_CRTC_EHB5 0x80 + +/* The vertical blanking subregisters. */ +#define VGA_CRTC_VBLANK_START 0x15 +#define VGA_CRTC_VBLANK_END 0x16 + +/* The horizontal blanking subregisters. */ +#define VGA_CRTC_HBLANK_START 0x02 +#define VGA_CRTC_HBLANK_END 0x03 + +/* The Display End subregisters. */ +#define VGA_CRTC_VDISPLAY_END 0x12 +#define VGA_CRTC_HDISPLAY_END 0x01 + +/* The Total subregisters. */ +#define VGA_CRTC_VTOTAL 0x06 +#define VGA_CRTC_HTOTAL 0x00 + +/* The Offset Register. */ +#define VGA_CRTC_OFFSET 0x13 /* The DAC Registers. */ #define VGA_DAC_WRITE_ADDR_REG 0x3c8 @@ -133,7 +180,19 @@ #define VGA_ATTR_DATA_READ_REG 0x3c1 +/* Miscellaneous Output Register (has separate ports for reading and + writing). */ +#define VGA_MISC_OUTPUT_RD_REG 0x3cc +#define VGA_MISC_OUTPUT_WRT_REG 0x32c + /* Other junk. */ #define VGA_INPUT_STATUS_1_REG 0x3da +#define VGA_INPUT_STATUS_1_VRT 0x08 +#define VGA_INPUT_STATUS_1_DD 0x01 + +/* Wait for vertical retrace. */ +#define VWAIT() \ + while (!(inb (VGA_INPUT_STATUS_1_REG) & VGA_INPUT_STATUS_1_VRT)); + #endif /* _VGA_HW_H_ */ diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/vga-mode.c console-client/vga-mode.c --- /home/marco/src/hurdcvs/hurd.bak/console-client/vga-mode.c 1970-01-01 01:00:00.000000000 +0100 +++ console-client/vga-mode.c 2003-08-27 22:11:44.000000000 +0200 @@ -0,0 +1,382 @@ +/* vga-mode.c -- Find and set best textmode. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Marco Gerards. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include <errno.h> +#include <assert.h> +#include <sys/io.h> +#include <stdlib.h> + +#include "vga-hw.h" +#include "vga-support.h" +#include "video-driver.h" +#include "vga-mode.h" + +/* The refresh rates of the user's monitor, set to VGA monitor by + default. */ +float vrefresh_min = 50.0; +float vrefresh_max = 72.0; +static const int vrefresh_max_diff = 1.5; + +float hrefresh_min = 30.0; +float hrefresh_max = 48.0; +static const int hrefresh_max_diff = 1.5; + +/* The display driver that is used. */ +video_driver_t video_driver; + +/* Some modelines I've copied from the default SVGATextMode + configuration file. XXX: The first should work on every VGA card + and VGA monitor because that one is used by default. */ +static struct modeline textmodes[] = + { + /* The old and crappy default VGA textmode. */ + {80, 25, 28.3, 640, 680, 776, 800, 400, 412, 414, 449, 9, 16}, + {80, 25, 25.2, 640, 680, 776, 800, 400, 412, 414, 449, 9, 16}, + /* Some variations on this, all have another number of rows. */ + {80, 28, 28.3, 640, 680, 776, 800, 392, 412, 414, 449, 9, 14}, + {80, 28, 25.2, 640, 680, 776, 800, 392, 412, 414, 449, 8, 14}, + {80, 29, 28.3, 640, 680, 776, 800, 464, 490, 492, 525, 9, 16}, + {80, 29, 25.2, 640, 680, 776, 800, 464, 490, 492, 525, 8, 16}, + {80, 30, 28.3, 640, 680, 776, 800, 480, 490, 492, 525, 9, 16}, + {80, 30, 25.2, 640, 680, 776, 800, 480, 490, 492, 525, 8, 16}, + {80, 32, 28.3, 640, 680, 776, 800, 480, 490, 492, 525, 9, 15}, + {80, 32, 25.2, 640, 680, 776, 800, 480, 490, 492, 525, 8, 15}, + {80, 40, 28.3, 640, 680, 776, 800, 480, 490, 492, 525, 9, 12}, + {80, 40, 25.2, 640, 680, 776, 800, 480, 490, 492, 525, 8, 12}, + {80, 50, 28.3, 640, 680, 776, 800, 400, 412, 414, 449, 9, 8}, + {80, 50, 25.2, 640, 680, 776, 800, 400, 412, 414, 449, 8, 8}, + {80, 60, 28.3, 640, 680, 776, 800, 480, 490, 492, 525, 9, 8}, + {80, 60, 25.2, 640, 680, 776, 800, 480, 490, 492, 525, 8, 8}, + + /* 132 column modes, 45 Mhz clock required! */ + {132, 25, 45.0, 1056, 1072, 1232, 1280, 400, 412, 414, 449, 9, 16}, + {132, 25, 40.0, 1056, 1072, 1232, 1280, 400, 412, 414, 449, 8, 16}, + {132, 30, 45.0, 1056, 1072, 1232, 1280, 480, 490, 492, 525, 9, 16}, + {132, 30, 40.0, 1056, 1072, 1232, 1280, 480, 490, 492, 525, 8, 16}, + {132, 40, 45.0, 1056, 1072, 1232, 1280, 480, 490, 492, 525, 9, 12}, + {132, 40, 40.0, 1056, 1072, 1232, 1280, 480, 490, 492, 525, 8, 12}, + {132, 50, 45.0, 1056, 1072, 1232, 1280, 400, 412, 414, 449, 9, 8}, + {132, 50, 40.0, 1056, 1072, 1232, 1280, 400, 412, 414, 449, 8, 8}, + {132, 60, 45.0, 1056, 1072, 1232, 1280, 480, 490, 492, 525, 9, 8}, + {132, 60, 40.0, 1056, 1072, 1232, 1280, 480, 490, 492, 525, 8, 8}, + {132, 80, 40.0, 1056, 1072, 1232, 1280, 480, 490, 492, 525, 8, 6}, + + /* Some 116 column modes, 40 Mhz clock required. */ + {116, 25, 40.0, 928, 944, 1080, 1128, 400, 412, 414, 449, 9, 16}, + {116, 25, 36.0, 928, 944, 1080, 1128, 400, 412, 414, 449, 8, 16}, + {116, 30, 40.0, 928, 944, 1080, 1128, 480, 490, 492, 525, 9, 16}, + {116, 30, 36.0, 928, 944, 1080, 1128, 480, 490, 492, 525, 8, 16}, + {116, 40, 40.0, 928, 944, 1080, 1128, 480, 490, 492, 525, 9, 12}, + {116, 40, 36.0, 928, 944, 1080, 1128, 480, 490, 492, 525, 8, 12}, + {116, 50, 40.0, 928, 944, 1080, 1128, 400, 412, 414, 449, 9, 8}, + {116, 50, 36.0, 928, 944, 1080, 1128, 400, 412, 414, 449, 8, 8}, + {116, 60, 40.0, 928, 944, 1080, 1128, 480, 490, 492, 525, 9, 8}, + {116, 60, 36.0, 928, 944, 1080, 1128, 480, 490, 492, 525, 8, 8}, + + /* Some nice 100 column modes, 56 Mhz clock required. */ + {100, 37, 56.0, 800, 872, 976, 1040, 600, 632, 638, 670, 9, 16}, + {100, 40, 56.0, 800, 872, 976, 1040, 640, 672, 678, 700, 9, 16}, + /* Very high res. 72 Mhz clock! */ + {100, 37, 72.0, 800, 848, 952, 1032, 600, 600, 606, 630, 8, 16}, + /* Same mode, but for 45 Mhz clock. */ + {100, 37, 45.0, 800, 864, 968, 1056, 600, 605, 607, 628, 9, 16}, + /* Same again, 36 Mhz clock, works on VGA monitors. */ + {100, 37, 36.0, 800, 864, 968, 1016, 518, 522, 525, 545, 9, 14}, + {100, 30, 36.0, 800, 864, 912, 1016, 480, 490, 495, 522, 9, 16}, + + /* Some extra VGA modes. */ + {40, 25, 14.15, 320, 340, 388, 400, 400, 412, 414, 449, 9, 16}, + /* (You DON'T want to use these modes, 49 Mhz pixelclock required + and you will get a terrible refresh rate and a headache! */ + {160, 60, 49, 1280, 1312, 1480, 1592, 480, 489, 491, 521, 8, 8}, + {160, 60, 56, 1280, 1312, 1480, 1592, 480, 489, 491, 521, 9, 8}, + {160, 30, 56, 1280, 1312, 1480, 1592, 480, 489, 491, 521, 9, 16}, + + /* Same and worse!! >:) */ + {160, 80, 49, 1280, 1312, 1480, 1592, 480, 489, 491, 521, 8, 6}, + {160, 80, 56, 1280, 1312, 1480, 1592, 480, 489, 491, 521, 9, 6}, + + /* Custom res, do not use when in doubt! Not usable with SVGATextMode */ + /* {80, 78, 38.4, 640, 680, 776, 800, 1250, 1251, 1265, 1500, 8, 16}, */ + {0} /* The last mode has been reached. */ + }; + +struct fontname fontnames[] = +{ + /* Width 8. */ + {8, 6, "4x6.bdf", NULL, NULL, NULL}, + {8, 7, "5x7.bdf", NULL, NULL, NULL}, + {8, 8, "5x8.bdf", NULL, NULL, NULL}, + {8, 9, "6x9.bdf", NULL, NULL, NULL}, + {8, 10, "6x10.bdf", NULL, NULL, NULL}, + {8, 12, "6x12.bdf", NULL, NULL, NULL}, + {8, 13, "8x13.bdf", NULL, NULL, NULL}, +/* {8, 14, "8x14.bdf", NULL, NULL, NULL}, */ + + /* Width 9. */ + /* {9, 10, "charR08.bdf", NULL, NULL, NULL}, */ + /* {9, 11, "helvR08.bdf", NULL, NULL, NULL}, */ + {9, 15, "9x15.bdf", NULL, NULL, NULL}, + {9, 18, "9x18.bdf", NULL, NULL, NULL}, + {0} /* The last font has been reached. */ +}; + + +/* Calculate the horizontal refresh rate for mode MODE. Return the horizontal refreshrate in Khz. */ +double +vga_calc_hrefresh (struct modeline *mode) +{ + return ((mode->freq * 1000) / (mode->htotal * (mode->fontw / 8.0))); +} + +/* Calculate vertical refresh rate for mode MODE. Return the vertical + refreshrate in Hz. */ +double +vga_calc_vrefresh (struct modeline *mode) +{ + return (vga_calc_hrefresh (mode) * 1000 ) / mode->vtotal; +} + +/* Check if the mode MODE can be set using the current driver. Return + -1 if it isn't possible, return 0 if it is. */ +static int +vga_check_mode (struct modeline *mode) +{ + if (video_driver->max_hdisplay_end < mode->hdisplay_end + || video_driver->max_hsync_start < mode->hsync_start +/* || video_driver->max_hblank_start > mode->hblank_start */ + || video_driver->max_htotal < mode->htotal + || video_driver->max_vdisplay_end < mode->vdisplay_end + || video_driver->max_vsync_start < mode->vsync_start +/* || video_driver->max_vblank_start > mode->vblank_start */ + || video_driver->max_vtotal < mode->vtotal) + return -1; + else + return 0; +} + + +/* Find a font in the font directory that has a width of WIDTH and a + height of HEIGHT. Return the filename of this font. */ +struct fontname * +vga_find_best_font (int width, int height) +{ + /* XXX: Assume that the first font in the list is also the + smallest. */ + struct fontname *currfont = fontnames; + struct fontname *bestfont = fontnames; + + while (currfont->width) + { + /* An exact match was found! */ + if (currfont->width == width && currfont->height == height) + return currfont; + + if (currfont->height < height && currfont->height > bestfont->height + && currfont->width == width) + bestfont = currfont; + currfont++; + } + + /* Return the smallest font. */ + return bestfont; +} + +/* XXX: What about a vga_create_best_mode? */ + +/* Try to find a mode that exactly matches the dimension that has ROWS + rows and COLS columns and has the highest refresh rate possible. + If none match find the next greater dimension. If really nothing + can be found select the next smaller dimension. */ +struct modeline * +vga_find_best_mode (int rows, int cols) +{ + int diff_dimensions (struct modeline *cmode) + { + int diff; + if (cmode->cols < cols) + diff = cols - cmode->cols; + else + diff = cmode->cols - cols; + if (cmode->rows < rows) + diff += rows- cmode->rows; + else + diff += cmode->rows - rows; + return diff; + } + + int is_smaller (struct modeline *cmode) + { + return (cmode->rows < rows || cmode->cols < cols); + } + + /* XXX: The first mode should be usable on ALL VGA monitors!! */ + struct modeline *bestmode = &textmodes[0]; + struct modeline *currmode = &textmodes[1]; + + + /* XXX: Also check which mode has better fonts. This might be + required for fonts with a width of 8 or 9. */ + while (currmode->rows) + { + int vrefresh = vga_calc_vrefresh (currmode); + int hrefresh = vga_calc_hrefresh (currmode); + + /* XXX: For now only select fonts with a width of 8 because + there are many of those. */ + if (currmode->fontw == 8) + { + currmode++; + continue; + } + + /* Check if the monitor can handle the mode. */ + if (vrefresh > vrefresh_max + vrefresh_max_diff + || vrefresh < vrefresh_min - vrefresh_max_diff + || hrefresh > hrefresh_max + hrefresh_max_diff + || hrefresh < hrefresh_min - hrefresh_max_diff) + { + /* Nope, it can't. */ + currmode++; + continue; + } + + /* Check if the clock is available. XXX: 1500 is just some + random number, what would be sane to use? */ + if (video_driver->test_pixclock (currmode->freq * 1000, 1500) == 0) + { + currmode++; + continue; + } + + /* Check if the mode is setable by the hardware. */ + if (vga_check_mode (currmode) == -1) + { + currmode++; + continue; + } + + if (is_smaller (bestmode)) + { + /* The old mode was smaller than the mode we are looking + for, check if the currently checked mode isn't. Don't + use a smaller mode if it isn't required! */ + if (!is_smaller (currmode)) + bestmode = currmode; + else + /* Check if the currently checked mode matches the mode + that is searched for better. */ + if (diff_dimensions (currmode) < diff_dimensions (bestmode)) + bestmode = currmode; + /* If the currently checked has a better refresh rate than + the old mode. */ + else if (diff_dimensions (currmode) == diff_dimensions (bestmode) + && vga_calc_vrefresh (bestmode) < vrefresh) + bestmode = currmode; + } + else if (!is_smaller (currmode)) + { + /* Check if the currently checked mode matches the mode + we want better. */ + if (diff_dimensions (currmode) < diff_dimensions (bestmode)) + bestmode = currmode; + /* check if the dimensions of the modes are the same, + but the refresh rate of the currently tested mode is + better. */ + else if ((diff_dimensions (currmode) + == diff_dimensions (bestmode)) + && vga_calc_vrefresh (bestmode) < vrefresh) + bestmode = currmode; + } + + /* Select the next modeline. */ + currmode++; + } + + return bestmode; +} + +/* Set the textmode described by the modeline MODE. */ +error_t +vga_set_mode (struct modeline *mode) +{ + error_t err; + struct modeline oldmode; + + assert (vga_check_mode (mode) == 0); + + /* Backup the current horizontal timings. */ + video_driver->get_horiz_timings (&oldmode.hdisplay_end, + &oldmode.hsync_start, + &oldmode.hsync_end, + &oldmode.htotal); + + /* Try to set the horizontal timings. */ + err = video_driver->set_horiz_timings (mode->hdisplay_end, + mode->hsync_start, + mode->hsync_end, + mode->htotal); + if (err) + { + /* The mode could not be set, restore the old horizontal + timings. Ignore all errors when trying to restore the + mode. */ + video_driver->set_horiz_timings (mode->hdisplay_end, + mode->hsync_start, + mode->hsync_end, + mode->htotal); + return err; + } + + /* Backup the current vertical timings. */ + video_driver->get_vert_timings (&oldmode.vdisplay_end, + &oldmode.vsync_start, + &oldmode.vsync_end, + &oldmode.vtotal); + + /* Try to set the vertical timings. */ + err = video_driver->set_vert_timings (mode->vdisplay_end, + mode->vsync_start, + mode->vsync_end, + mode->vtotal); + + /* Program the clock during the vertical retrace. */ + VWAIT (); + /* XXX: Should something be done before selecting the clock? */ + if (!err) + err = video_driver->set_pixclock (mode->freq * 1000, 1500); + + if (err) + { + /* The mode could not be set, restore the old timings. Ignore + all errors when trying to restore the mode. */ + video_driver->set_horiz_timings (mode->hdisplay_end, + mode->hsync_start, + mode->hsync_end, + mode->htotal); + video_driver->set_vert_timings (mode->vdisplay_end, + mode->vsync_start, + mode->vsync_end, + mode->vtotal); + return err; + } + + return 0; +} diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/vga-mode.h console-client/vga-mode.h --- /home/marco/src/hurdcvs/hurd.bak/console-client/vga-mode.h 1970-01-01 01:00:00.000000000 +0100 +++ console-client/vga-mode.h 2003-08-27 22:19:36.000000000 +0200 @@ -0,0 +1,91 @@ +/* vga-mode.c -- Interfaces for finding and setting textmodes. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Marco Gerards. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +/* A display modeline. */ +struct modeline +{ + /* Number of rows on the screen. */ + int rows; + /* Number of columns on the screen. */ + int cols; + + /* Frequency of the required pixelclock in Mhz. */ + double freq; + + /* Number of visible pixels per scanline. */ + int hdisplay_end; + /* The pixel on the scanline where the horizontal retrace + starts. */ + int hsync_start; + /* The pixel on the scanline where the horizontal retrace ends. */ + int hsync_end; + /* The number of pixels per scanline. */ + int htotal; + + /* Number of visible scanlines on the screen. */ + int vdisplay_end; + /* The scanline where the vertical retrace starts. */ + int vsync_start; + /* The scanline where the vertical retrace ends. */ + int vsync_end; + /* The number scanlines. */ + int vtotal; + + /* Font width. */ + int fontw; + /* Font height. */ + int fonth; +}; + +/* Map a font width and height to the fontnames. For every fonttype a + name can be available. */ +struct fontname +{ + /* The fontsize. */ + int width; + int height; + + /* The filenames of the fonts. */ + char *font; + /* These fontnames are allowed to be set to NULL when there is no + font available. */ + char *font_italic; + char *font_bold; + char *font_bold_italic; +}; + +extern float vrefresh_min; +extern float vrefresh_max; + +extern float hrefresh_min; +extern float hrefresh_max; + +/* Find a font in the font directory that has a width of WIDTH and a + height of HEIGHT. Return the filename of this font. */ +struct fontname *vga_find_best_font (int width, int height); + +/* Try to find a mode that exactly matches the dimension that has ROWS + rows and COLS columns and has the highest refresh rate possible. + If none match find the next greater dimension. If really nothing + can be found select the next smaller dimension. */ +struct modeline *vga_find_best_mode (int rows, int cols); + +/* Set the textmode described by the modeline MODE. */ +error_t vga_set_mode (struct modeline *mode); diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/vga-support.c console-client/vga-support.c --- /home/marco/src/hurdcvs/hurd.bak/console-client/vga-support.c 2003-08-18 14:17:44.000000000 +0200 +++ console-client/vga-support.c 2003-08-26 23:41:51.000000000 +0200 @@ -1,5 +1,5 @@ /* vga-support.c - VGA hardware access. - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. Written by Marcus Brinkmann. This file is part of the GNU Hurd. @@ -46,13 +46,12 @@ struct vga_state unsigned char gfx_mode; unsigned char gfx_misc; - unsigned char crt_max_scan_line; - unsigned char crt_cursor_start; - unsigned char crt_cursor_end; - unsigned char crt_cursor_high; - unsigned char crt_cursor_low; + unsigned char misc_output; - char videomem[2 * 80 * 25]; + char crtcregs[VGA_CRTC_REG_CNT]; + + char videomem[2 * 80 * 25]; /* XXX: This should be dynamicly + allocated. */ unsigned char fontmem[2 * VGA_FONT_SIZE * VGA_FONT_HEIGHT]; }; @@ -72,11 +71,30 @@ static struct vga_state *vga_state; #endif +/* Unlock write access to CRTC subregisters 0-7. The vga_lock must be + held when this function is called. */ +void +vga_crtc_unlock (void) +{ + outb (VGA_CRTC_VRETRACE_END, VGA_CRTC_ADDR_REG); + outb (inb (VGA_CRTC_DATA_REG) & ~VGA_CRTC_PROTECT, VGA_CRTC_DATA_REG); +} + +/* Lock write access to CRTC subregisters 0-7. The vga_lock must be + held when this function is called. */ +void +vga_crtc_lock (void) +{ + outb (VGA_CRTC_VRETRACE_END, VGA_CRTC_ADDR_REG); + outb (inb (VGA_CRTC_DATA_REG) | VGA_CRTC_PROTECT, VGA_CRTC_DATA_REG); +} + error_t vga_init (void) { error_t err; int fd; + int i; /* Acquire I/O port access. */ if (ioperm (VGA_MIN_REG, VGA_MAX_REG - VGA_MIN_REG + 1, 1) < 0) @@ -162,17 +180,16 @@ vga_init (void) outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG); vga_state->gfx_misc = inb (VGA_GFX_DATA_REG); - outb (VGA_CRT_MAX_SCAN_LINE, VGA_CRT_ADDR_REG); - vga_state->crt_max_scan_line = inb (VGA_CRT_DATA_REG); - outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG); - vga_state->crt_cursor_start = inb (VGA_CRT_DATA_REG); - outb (VGA_CRT_CURSOR_END, VGA_CRT_ADDR_REG); - vga_state->crt_cursor_end = inb (VGA_CRT_DATA_REG); - outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG); - vga_state->crt_cursor_high = inb (VGA_CRT_DATA_REG); - outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG); - vga_state->crt_cursor_low = inb (VGA_CRT_DATA_REG); + vga_state->misc_output = inb (0x3cc); + vga_crtc_unlock (); + for (i = 0; i <= VGA_CRTC_REG_CNT; i++) + { + outb (i, VGA_CRTC_ADDR_REG); + vga_state->crtcregs[i] = inb (VGA_CRTC_DATA_REG); + } + vga_crtc_lock (); + /* Read/write in interleaved mode. */ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG); outb (VGA_GFX_MISC_CHAINOE | VGA_GFX_MISC_A0TOAF, VGA_GFX_DATA_REG); @@ -196,6 +213,8 @@ vga_init (void) void vga_fini (void) { + int i; + /* Recover the saved state. */ vga_write_font_buffer (0, 0, vga_state->fontmem, 2 * VGA_FONT_SIZE * VGA_FONT_HEIGHT); @@ -218,16 +237,15 @@ vga_fini (void) outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG); outb (vga_state->gfx_misc, VGA_GFX_DATA_REG); - outb (VGA_CRT_MAX_SCAN_LINE, VGA_CRT_ADDR_REG); - outb (vga_state->crt_max_scan_line, VGA_CRT_DATA_REG); - outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG); - outb (vga_state->crt_cursor_start, VGA_CRT_DATA_REG); - outb (VGA_CRT_CURSOR_END, VGA_CRT_ADDR_REG); - outb (vga_state->crt_cursor_end, VGA_CRT_DATA_REG); - outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG); - outb (vga_state->crt_cursor_high, VGA_CRT_DATA_REG); - outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG); - outb (vga_state->crt_cursor_low, VGA_CRT_DATA_REG); + outb (vga_state->misc_output, 0x3c2); + + vga_crtc_unlock (); + for (i = 0; i < VGA_CRTC_REG_CNT; i++) + { + outb (i, VGA_CRTC_ADDR_REG); + outb (vga_state->crtcregs[i], VGA_CRTC_DATA_REG); + } + vga_crtc_lock (); ioperm (VGA_MIN_REG, VGA_MAX_REG, 0); munmap (vga_videomem, VGA_VIDEO_MEM_LENGTH); @@ -325,11 +343,11 @@ vga_set_font_height (int height) { char saved; - outb (VGA_CRT_MAX_SCAN_LINE, VGA_CRT_ADDR_REG); - saved = inb (VGA_CRT_DATA_REG); + outb (VGA_CRTC_MAX_SCAN_LINE, VGA_CRTC_ADDR_REG); + saved = inb (VGA_CRTC_DATA_REG); saved &= ~31; saved |= (height - 1) & 31; - outb (saved, VGA_CRT_DATA_REG); + outb (saved, VGA_CRTC_DATA_REG); } @@ -367,13 +385,13 @@ vga_display_cursor (int on) { char crs_start; - outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG); - crs_start = inb (VGA_CRT_DATA_REG); + outb (VGA_CRTC_CURSOR_START, VGA_CRTC_ADDR_REG); + crs_start = inb (VGA_CRTC_DATA_REG); if (on) - crs_start &= ~VGA_CRT_CURSOR_DISABLE; + crs_start &= ~VGA_CRTC_CURSOR_DISABLE; else - crs_start |= VGA_CRT_CURSOR_DISABLE; - outb (crs_start, VGA_CRT_DATA_REG); + crs_start |= VGA_CRTC_CURSOR_DISABLE; + outb (crs_start, VGA_CRTC_DATA_REG); } @@ -386,19 +404,19 @@ vga_set_cursor_size (int start, int end) if (start >= 0) { - outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG); - saved = inb (VGA_CRT_DATA_REG); + outb (VGA_CRTC_CURSOR_START, VGA_CRTC_ADDR_REG); + saved = inb (VGA_CRTC_DATA_REG); saved &= ~31; saved |= start & 31; - outb (saved, VGA_CRT_DATA_REG); + outb (saved, VGA_CRTC_DATA_REG); } if (end >= 0) { - outb (VGA_CRT_CURSOR_END, VGA_CRT_ADDR_REG); - saved = inb (VGA_CRT_DATA_REG); + outb (VGA_CRTC_CURSOR_END, VGA_CRTC_ADDR_REG); + saved = inb (VGA_CRTC_DATA_REG); saved &= ~31; saved |= end & 31; - outb (saved, VGA_CRT_DATA_REG); + outb (saved, VGA_CRTC_DATA_REG); } } @@ -407,10 +425,10 @@ vga_set_cursor_size (int start, int end) void vga_set_cursor_pos (unsigned int pos) { - outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG); - outb (pos >> 8, VGA_CRT_DATA_REG); - outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG); - outb (pos & 0xff, VGA_CRT_DATA_REG); + outb (VGA_CRTC_CURSOR_HIGH, VGA_CRTC_ADDR_REG); + outb (pos >> 8, VGA_CRTC_DATA_REG); + outb (VGA_CRTC_CURSOR_LOW, VGA_CRTC_ADDR_REG); + outb (pos & 0xff, VGA_CRTC_DATA_REG); } diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/vga-support.h console-client/vga-support.h --- /home/marco/src/hurdcvs/hurd.bak/console-client/vga-support.h 2003-08-18 14:17:44.000000000 +0200 +++ console-client/vga-support.h 2003-08-27 18:38:17.000000000 +0200 @@ -27,8 +27,8 @@ /* The VGA interface does not do locking on its own, for maximum efficiency it relies on locking by the caller (because usually the - caller has some other data structures to lock along with the - VGA hardware. */ + caller has some other data structures to lock along with the VGA + hardware. */ /* The mapped video memory. */ extern char *vga_videomem; @@ -86,4 +86,12 @@ void vga_exchange_palette_attributes (un unsigned char *saved_palette_attr, int nr); +/* Unlock write access to CRTC subregisters 0-7. The vga_lock must be + held when this function is called. */ +void vga_crtc_unlock (void); + +/* Lock write access to CRTC subregisters 0-7. The vga_lock must be + held when this function is called. */ +void vga_crtc_lock (void); + #endif /* _VGA_SUPPORT_H_ */ diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/vga.c console-client/vga.c --- /home/marco/src/hurdcvs/hurd.bak/console-client/vga.c 2003-08-18 14:17:44.000000000 +0200 +++ console-client/vga.c 2003-08-27 22:29:03.000000000 +0200 @@ -43,28 +43,27 @@ #include "vga-dynafont.h" #include "vga-dynacolor.h" #include "unicode.h" +#include "video-driver.h" +#include "vga-mode.h" -#define VGA_DISP_WIDTH 80 -#define VGA_DISP_HEIGHT 25 +int vga_disp_width; +int vga_disp_height; -/* The font file. */ -#define DEFAULT_VGA_FONT "/lib/hurd/fonts/vga-system.bdf" -static char *vga_display_font; - -#define DEFAULT_VGA_FONT_ITALIC "/lib/hurd/fonts/vga-system-italic.bdf" -static char *vga_display_font_italic; - -#define DEFAULT_VGA_FONT_BOLD "/lib/hurd/fonts/vga-system-bold.bdf" -static char *vga_display_font_bold; - -#define DEFAULT_VGA_FONT_BOLD_ITALIC \ - "/lib/hurd/fonts/vga-system-bold-italic.bdf" -static char *vga_display_font_bold_italic; +/* Default font path. */ +#define DEFAULT_FONT_PATH "/lib/hurd/fonts/" +static char *vga_display_font_path = DEFAULT_FONT_PATH; /* If false use all colors, else use double font slots. */ static int vga_display_max_glyphs; +/* The video driver selected by the user. */ +static char *vga_display_viddrv; + +/* The horizontal and vertical refresh rates. */ +static char *vga_display_hrefresh; +static char *vga_display_vrefresh; + /* The timer used for flashing the screen. */ static struct timer_list vga_display_timer; @@ -113,9 +112,20 @@ struct vga_display /* Remember for each cell on the display the glyph written to it and the colors (in the upper byte) assigned. 0 means unassigned. */ - struct refchr refmatrix[VGA_DISP_HEIGHT][VGA_DISP_WIDTH]; + struct refchr *refmatrix; + + /* The currently used modeline */ + struct modeline *modeline; }; +/* Cache all loaded fonts. */ +struct font_cache +{ + /* The next font in the cache. */ + struct font_cache *next; + bdf_font_t bdf; + char *filename; +} *vga_font_cache; static void vga_display_invert_border (void) @@ -156,7 +166,7 @@ vga_display_flash (void *handle) static error_t parse_startup_args (int no_exit, int argc, char *argv[], int *next) { -#define PARSE_FONT_OPT(x,y) \ +#define PARSE_VGA_OPT(x,y) \ do { \ if (!strcmp (argv[*next], x)) \ { \ @@ -184,24 +194,23 @@ parse_startup_args (int no_exit, int arg } \ } while (0) -#define PARSE_FONT_OPT_NOARGS(x,y,z) \ - { \ - if (!strcmp (argv[*next], x)) \ - { \ - (*next)++; \ - vga_display_##y = z; \ - } \ +#define PARSE_VGA_OPT_NOARGS(x,y,z) \ + { \ + if (!strcmp (argv[*next], x)) \ + { \ + (*next)++; \ + vga_display_##y = z; \ + } \ } while (*next < argc) { - PARSE_FONT_OPT ("--font", font); - PARSE_FONT_OPT ("--font-italic", font_italic); - PARSE_FONT_OPT ("--font-bold", font_bold); - PARSE_FONT_OPT ("--font-bold-italic", font_bold_italic); - PARSE_FONT_OPT_NOARGS ("--max-colors", max_glyphs, 1); - PARSE_FONT_OPT_NOARGS ("--max-glyphs", max_glyphs, 0); - + PARSE_VGA_OPT ("--font-path", font_path); + PARSE_VGA_OPT ("--chipset", viddrv); + PARSE_VGA_OPT ("--hrefresh", hrefresh); + PARSE_VGA_OPT ("--vrefresh", vrefresh); + PARSE_VGA_OPT_NOARGS ("--max-colors", max_glyphs, 1); + PARSE_VGA_OPT_NOARGS ("--max-glyphs", max_glyphs, 0); break; } @@ -212,6 +221,43 @@ parse_startup_args (int no_exit, int arg static error_t vga_display_init (void **handle, int no_exit, int argc, char *argv[], int *next) { + /* Parse the string STR in which a refresh rate or a range is + stored. Put range for the refresh rates in LOW and HIGH. */ + error_t parse_refresh (char *str, float *low, float *high) + { + char *tail; + + /* The high value in the range, if STR is a range. */ + char *str2; + + str2 = strchr (str, '-'); + if (str2) + str2[0] = '\0'; + + *low = strtof (str, &tail); + if (tail == NULL || tail == str || *tail != '\0') + return EINVAL; + if (errno) + return errno; + + if (str2) + { + *high = strtof (str2, &tail); + if (tail == NULL || tail == str2 || *tail != '\0') + return EINVAL; + if (errno) + return errno; + } + else + *high = *low; + + /* A user that still doesn't get the basics was detected. */ + if (*high < *low) + return EINVAL; + + return 0; + } + error_t err; struct vga_display *disp; @@ -232,68 +278,56 @@ vga_display_init (void **handle, int no_ return ENOMEM; disp->df_size = vga_display_max_glyphs ? 512 : 256; - disp->width = VGA_DISP_WIDTH; - disp->height = VGA_DISP_HEIGHT; + + /* Select the video driver. */ + if (!vga_display_viddrv || !strcasecmp (vga_display_viddrv, "vga")) + video_driver = video_driver_vga; + else if (!strcasecmp (vga_display_viddrv, "s3")) + video_driver = video_driver_s3; + else + { + console_error (L"Unknown video driver.\n"); + return EINVAL; + } + + /* Parse the refresh rates provided by the user. */ + if (vga_display_hrefresh) + parse_refresh (vga_display_hrefresh, &hrefresh_min, &hrefresh_max); + if (vga_display_vrefresh) + parse_refresh (vga_display_vrefresh, &vrefresh_min, &vrefresh_max); *handle = disp; return 0; } - /* Start the driver. */ static error_t vga_display_start (void *handle) { error_t err; struct vga_display *disp = handle; - bdf_font_t font = NULL; - bdf_font_t font_italic = NULL; - bdf_font_t font_bold = NULL; - bdf_font_t font_bold_italic = NULL; - FILE *font_file; err = vga_init (); if (err) return err; - - dynacolor_init (); - -#define LOAD_FONT(x,y) \ - do { \ - font_file = fopen (vga_display_##x ?: DEFAULT_VGA_##y, "r"); \ - if (font_file) \ - { \ - bdf_error_t bdferr = bdf_read (font_file, &x, NULL); \ - if (bdferr) \ - x = NULL; \ - else \ - bdf_sort_glyphs (x); \ - fclose (font_file); \ - } \ - } while (0) - - LOAD_FONT (font, FONT); - LOAD_FONT (font_italic, FONT_ITALIC); - LOAD_FONT (font_bold, FONT_BOLD); - LOAD_FONT (font_bold_italic, FONT_BOLD_ITALIC); - - err = dynafont_new (font, font_italic, font_bold, font_bold_italic, - disp->df_size, &disp->df); - if (err) + + if (video_driver->init) { - free (disp); - vga_fini (); - return err; + err = video_driver->init (); + if (err) + { + vga_fini (); + return err; + } } - dynafont_activate (disp->df); + dynacolor_init (); disp->dc = (disp->df_size == 512) ? dynacolor_init_8 : dynacolor_init_16; dynacolor_activate (&disp->dc); err = driver_add_display (&vga_display_ops, disp); if (err) { - dynafont_free (disp->df); dynacolor_fini (); vga_fini (); free (disp); @@ -311,18 +345,11 @@ vga_display_fini (void *handle, int forc if (timer_remove (&vga_display_timer)) vga_display_flash_off (0); - dynafont_free (disp->df); + if (disp->df) + dynafont_free (disp->df); free (disp); dynacolor_fini (); vga_fini (); - if (vga_display_font) - free (vga_display_font); - if (vga_display_font_italic) - free (vga_display_font_italic); - if (vga_display_font_bold) - free (vga_display_font_bold); - if (vga_display_font_bold_italic) - free (vga_display_font_bold_italic); return 0; } @@ -400,13 +427,13 @@ vga_display_scroll (void *handle, int de { memmove (vga_videomem, vga_videomem + 2 * count, 2 * disp->width * (disp->height - delta)); - refpos = &disp->refmatrix[0][0]; + refpos = disp->refmatrix; } else { memmove (vga_videomem + 2 * count, vga_videomem, 2 * disp->width * (disp->height + delta)); - refpos = &disp->refmatrix[disp->height + delta][0]; + refpos = &disp->refmatrix[(disp->height + delta) * disp->width]; } for (i = 0; i < count; i++) @@ -424,15 +451,15 @@ vga_display_scroll (void *handle, int de if (delta > 0) { - memmove (&disp->refmatrix[0][0], &disp->refmatrix[0][0] + count, + memmove (disp->refmatrix, disp->refmatrix + count, sizeof (struct refchr) * disp->width * (disp->height - delta)); - refpos = &disp->refmatrix[disp->height - delta][0]; + refpos = &disp->refmatrix[(disp->height - delta) * disp->width]; } else { - memmove (&disp->refmatrix[0][0] + count, &disp->refmatrix[0][0], + memmove (disp->refmatrix + count, disp->refmatrix, sizeof (struct refchr) * disp->width * (disp->height + delta)); - refpos = &disp->refmatrix[0][0]; + refpos = disp->refmatrix; } for (i = 0; i < count; i++) @@ -441,6 +468,8 @@ vga_display_scroll (void *handle, int de return 0; } +/* Function is not used. */ +#if 0 /* Change the font on the console CONSOLE to font. The old font will not be accessed by the vga console subsystem anymore after this @@ -452,6 +481,7 @@ vga_display_change_font (void *handle, b dynafont_change_font (disp->df, font); } +#endif static inline char @@ -525,7 +555,7 @@ static error_t vga_display_clear (void *handle, size_t length, uint32_t col, uint32_t row) { struct vga_display *disp = handle; - struct refchr *refpos = &disp->refmatrix[row][0]; + struct refchr *refpos = &disp->refmatrix[row * disp->width]; int cols; /* The column can be outside the physical screen, in that case @@ -575,7 +605,7 @@ vga_display_write (void *handle, conchar { struct vga_display *disp = handle; char *pos; - struct refchr *refpos = &disp->refmatrix[row][col]; + struct refchr *refpos = &disp->refmatrix[row * disp->width + col]; /* The starting column is outside the physical screen. */ if (disp->width < current_width && col >= disp->width) @@ -666,19 +696,151 @@ vga_display_write (void *handle, conchar return 0; } +/* Load the font FILENAME into the font buffer BDF. If the font was + already in the cache use the cached font instead. */ +static error_t +load_font (char *filename, bdf_font_t *bdf) +{ + struct font_cache *cache = vga_font_cache; + struct font_cache *newfont; + FILE *font_file; + + /* Don't do anything. */ + if (!filename) + return 0; + + /* Lookup the font in the cache first. */ + /* XXX: Perhaps a hash should be used to lookup filenames. */ + for (cache = vga_font_cache; cache; cache = cache->next) + if (!strcmp (filename, cache->filename)) + { + *bdf = cache->bdf; + return 0; + } + + font_file = fopen (filename, "r"); + if (font_file) + { + bdf_error_t bdferr = bdf_read (font_file, bdf, NULL); + if (bdferr) + *bdf = NULL; + else + bdf_sort_glyphs (*bdf); + fclose (font_file); + } + + /* If a font was loaded put it in the font cache. */ + if (*bdf) + { + newfont = malloc (sizeof (struct font_cache)); + if (!newfont) + { + bdf_destroy (*bdf); + return ENOMEM; + } + newfont->bdf = *bdf; + newfont->filename = strdup (filename); + if (!newfont->filename) + { + bdf_destroy (*bdf); + free (newfont); + return ENOMEM; + } + newfont->next = vga_font_cache; + vga_font_cache = newfont; + } + + return 0; +} + +/* Load the fonts FONTS for display DISP. */ +static error_t +select_font (struct fontname *fonts, struct vga_display *disp) +{ + error_t err; + + bdf_font_t font = NULL; + bdf_font_t font_italic = NULL; + bdf_font_t font_bold = NULL; + bdf_font_t font_bold_italic = NULL; + + /* XXX: Is this thread save? */ + if (chdir (vga_display_font_path) == -1) + return errno; + + load_font (fonts->font, &font); + load_font (fonts->font_italic, &font_italic); + load_font (fonts->font_bold, &font_bold); + load_font (fonts->font_bold_italic, &font_bold_italic); + + /* XXX: Check if this operation is cheap, otherwise if the fonts are + already active don't load them. */ + err = dynafont_new (font, font_italic, font_bold, font_bold_italic, + disp->df_size, &disp->df); + if (err) + return err; + + dynafont_activate (disp->df); + return 0; +} + static error_t vga_set_dimension (void *handle, int width, int height) { - if (current_width && current_height) - vga_display_clear (handle, current_width * current_height, 0, 0); + error_t err; + struct vga_display *disp = handle; + struct modeline *bestmode; + struct modeline *evenbettermode; + struct fontname *bestfont; + + if (disp->refmatrix) + { + if (current_width && current_height) + vga_display_clear (handle, current_width * current_height, 0, 0); + free (disp->refmatrix); + } + + /* Find a mode that is the best. */ + bestmode = vga_find_best_mode (width, height); + disp->width = bestmode->rows; + disp->height = bestmode->cols; + + disp->refmatrix = calloc (sizeof (struct refchr), + disp->width * disp->height); current_width = width; current_height = height; - /* FIXME: Should support greater dimensions by changing the video - mode. */ + vga_disp_width = disp->width; + vga_disp_height = disp->height; - return 0; + /* Don't program the hardware if the mode is already active. */ + /* XXX: This is not really correct. The last lines could have been + hidden, this will break support for VTs with different + dimensions. */ + if (disp->modeline == bestmode) + return 0; + + bestfont = vga_find_best_font (bestmode->fontw, bestmode->fonth); + + /* Use the font that was found. */ + select_font (bestfont, disp); + + evenbettermode = malloc (sizeof (struct modeline)); + memcpy (evenbettermode, bestmode, sizeof (struct modeline)); + + /* Recalculate the vdisplay_end if the font is not be the one that + was requested. */ + if (bestfont->height < bestmode->fonth) + evenbettermode->vdisplay_end = height * bestfont->height; + + /* Set the mode. */ + err = vga_set_mode (evenbettermode); + + if (!err) + disp->modeline = bestmode; + + return err; } diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/viddrv_s3.c console-client/viddrv_s3.c --- /home/marco/src/hurdcvs/hurd.bak/console-client/viddrv_s3.c 1970-01-01 01:00:00.000000000 +0100 +++ console-client/viddrv_s3.c 2003-08-27 22:36:42.000000000 +0200 @@ -0,0 +1,194 @@ +/* viddrv_s3.c -- S3 driver. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Marco Gerards. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include <stdlib.h> +#include <errno.h> +#include <assert.h> +#include <sys/io.h> + +#include "vga-hw.h" +#include "video-driver.h" + +/* XXX: Remove or fix this redundancy. */ + +/* Maximal horizontal resolution. */ +#define VGA_MAX_HDISPLAY_END 2048 +/* Maximal beginning of horizontal retrace. */ +#define VGA_MAX_HSYNC_START 2040 +/* Maximal beginning of horizontal blanking. */ +#define VGA_MAX_HBLANK_START 2040 +/* Maximal horizontal total. */ +#define VGA_MAX_HTOTAL 2080 + +/* Maximal vertical resolution. */ +#define VGA_MAX_VDISPLAY_END 1023 +/* Maximal beginning of vertical retrace. */ +#define VGA_MAX_VSYNC_START 1023 +/* Maximal beginning of vertical blanking. */ +#define VGA_MAX_VBLANK_START 1015 +/* Maximal vertical total. */ +#define VGA_MAX_VTOTAL 1023 + + +static error_t +s3_driver_init (void) +{ + /* XXX: Forward some calls directly to the VGA driver. */ + video_driver_s3->set_horiz_timings = video_driver_vga->set_horiz_timings; + video_driver_s3->get_horiz_timings = video_driver_vga->get_horiz_timings; + video_driver_s3->set_vert_timings = video_driver_vga->set_vert_timings; + video_driver_s3->get_vert_timings = video_driver_vga->get_vert_timings; + + return 0; +} + + +/* Test if there is a pixelclock with FREQUENCY Khz available, the + frequency used by the hardware may be DEVIATION Khz more or less + than FREQUENCY. Return 1 if a clock is available, return 0 + otherwise. */ +static int +s3_test_pixclock (long freq, int dev) +{ + if (video_driver_vga->set_pixclock (freq, dev) == 1) + return 1; + + /* XXX: Check the minimum and maximum supported clock speed. */ + return 1; +} + +static int +calcfreq (long int freq, int *m, int *n1, int *n2) +{ + int fm; + int fn1; + int fn2; + + /* The frequency is always multiplied by the base frequence, + 14138. */ + double ffreq = freq / 14318.0; + + /* Closest match. */ + int cm = 0; + int cn1 = 0; + int cn2 = 0; + double cdiff = 0; + + for (fn1 = 3; fn1 <33; fn1++) + for (fn2 = 0; fn2 < 3; fn2++) + { + double diff; + int nn = 1 << fn2; + + /* Determine m by calculating m required for this + frequency. */ + fm = ffreq * fn1 * nn; + + /* Test if the found M is in range. */ + if (fm <1 || fm > 127) + continue; + + diff = fm / (fn1 * (double) fn2) - freq; + + if (diff < 0) + diff = -diff; + + if (cdiff == 0 || (diff < cdiff)) + { + cdiff = diff; + cm = fm; + cn1 = fn1; + cn2 = fn2; + } + } + + *m = cm - 2; + *n1 = cn1 - 2; + *n2 = cn2; + + return 0; +} + + +/* Set the timer to FREQUENCY Khz, the frequency used by the hardware + may be DEVIATION Hhz more or less than FREQUENCY. If the + pixelclock cannot be set to FREQUENCY with the diviation DEVIATION + return EINVAL. */ +static error_t +s3_set_pixclock (long freq, int dev) +{ + int m, n1, n2; + int old; + + calcfreq (freq, &m, &n1, &n2); + + /* XXX: Replace values by names. */ + + /* Unlock. */ + outb (0x08, 0x3c4); + outb (0x06, 0x3c5); + + outb (0x12, 0x3c4); + outb (n1 | n2 << 5, 0x3c5); + + /* "M". */ + outb (0x13, 0x3c4); + outb (m, 0x3c5); + + old = inb (0x3cc); + old &= ~0x0C; + old |= 0xc; + outb (old, 0x3c2); + + /* Lock. */ + outb (0x08, 0x3c4); + outb (0x00, 0x3c5); + return 0; +} + +static struct video_driver s3_driver = +{ + "VGA", + NULL, + VGA_MAX_HDISPLAY_END, + VGA_MAX_HSYNC_START, + VGA_MAX_HBLANK_START, + VGA_MAX_HTOTAL, + VGA_MAX_VDISPLAY_END, + VGA_MAX_VSYNC_START, + VGA_MAX_VBLANK_START, + VGA_MAX_VTOTAL, + s3_driver_init, + /* vga_driver_fini */ NULL, + /* These functions will be available after the call to init. */ + NULL, + NULL, + NULL, + NULL, + s3_set_pixclock, + s3_test_pixclock, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +const video_driver_t video_driver_s3 = &s3_driver; diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/viddrv_vga.c console-client/viddrv_vga.c --- /home/marco/src/hurdcvs/hurd.bak/console-client/viddrv_vga.c 1970-01-01 01:00:00.000000000 +0100 +++ console-client/viddrv_vga.c 2003-08-27 22:36:29.000000000 +0200 @@ -0,0 +1,430 @@ +/* viddrv_vga.c -- Lowlevel VGA driver. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Marco Gerards. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +/* The VGA limitations. Don't get funny ideas because of these + values, a fast pixelclock (which is not available) is a requirement + for high resolutions. */ + +#define _GNU_SOURCE 1 + +#include <stdlib.h> +#include <errno.h> +#include <assert.h> +#include <sys/io.h> + +#include "vga-hw.h" +#include "vga-support.h" +#include "video-driver.h" + +/* Maximal horizontal resolution. */ +#define VGA_MAX_HDISPLAY_END 2048 +/* Maximal beginning of horizontal retrace. */ +#define VGA_MAX_HSYNC_START 2040 +/* Maximal beginning of horizontal blanking. */ +#define VGA_MAX_HBLANK_START 2040 +/* Maximal horizontal total. */ +#define VGA_MAX_HTOTAL 2080 + +/* Maximal vertical resolution. */ +#define VGA_MAX_VDISPLAY_END 1023 +/* Maximal beginning of vertical retrace. */ +#define VGA_MAX_VSYNC_START 1023 +/* Maximal beginning of vertical blanking. */ +#define VGA_MAX_VBLANK_START 1015 +/* Maximal vertical total. */ +#define VGA_MAX_VTOTAL 1023 + +/* The speed in KHz of the VGA pixelclocks. */ +#define VGA_CLOCK0 25175 +#define VGA_CLOCK1 28322 + + +/* Set the vertical retrace scanlines. The vga_lock must be held when + this function is called. */ +static void +vga_vert_sync (int start, int end) +{ + int overflow; + + /* Vertical retrace end (and unlock). This position is relative to + the start position. */ + /* XXX: Don't overwrite. */ + outb (VGA_CRTC_VRETRACE_END, VGA_CRTC_ADDR_REG); + outb (end & 0x0f, VGA_CRTC_DATA_REG); + + /* Vertical retrace start, bits 0-7. */ + outb (VGA_CRTC_VRETRACE_START, VGA_CRTC_ADDR_REG); + outb (start & 0xff, VGA_CRTC_DATA_REG); + + /* Vertical retrace start, bit 8 and 9 are stored in the CRTC + Overflow subregister. */ + outb (VGA_CRTC_OVERFLOW, VGA_CRTC_ADDR_REG); + overflow = inb (VGA_CRTC_DATA_REG); + overflow &= ~(VGA_CRTC_VRS8 | VGA_CRTC_VRS9); + overflow |= (start & 0x100) ? VGA_CRTC_VRS8 : 0; + overflow |= (start & 0x200) ? VGA_CRTC_VRS9 : 0; + outb (overflow, VGA_CRTC_DATA_REG); +} + +/* Set The horizontal retrace position. The vga_lock must be held + when this function is called. */ +static void +vga_horiz_sync (int start, int end) +{ + int old; + + /* There are just 5 bits available for END. */ + if (end > start + 63) + end = start + 63; + + /* Start Horizontal Retrace. */ + outb (VGA_CRTC_HRETRACE_START, VGA_CRTC_ADDR_REG); + outb (start, VGA_CRTC_DATA_REG); + + /* End Horizontal Retrace. */ + outb (VGA_CRTC_HRETRACE_END, VGA_CRTC_ADDR_REG); + old = inb (VGA_CRTC_DATA_REG); + old &= ~0x1f; + old |= end & 0x1f; + outb (old, VGA_CRTC_DATA_REG); +} + +/* Set the vertical blanking. */ +static void +vga_vert_blank (int start, int end) +{ + /* For backup Overflow Register. */ + int overflow; + /* for backup of Maximum Scan Line Register. */ + int msl; + + /* Sigh, the start vertical blanking value is spread over 3 + registers. */ + + /* Start vertical blanking (bits 0-7). */ + outb (VGA_CRTC_VBLANK_START, VGA_CRTC_ADDR_REG); + outb (start & 0xff, VGA_CRTC_DATA_REG); + + /* Bit 8 of Start Vertical Blanking (SVB) should be stored in the + overflow register. */ + outb (VGA_CRTC_OVERFLOW, VGA_CRTC_ADDR_REG); + overflow = inb (VGA_CRTC_DATA_REG); + overflow &= ~VGA_CRTC_SVB8; + overflow |= (start & 0x100) ? VGA_CRTC_SVB8 : 0; + outb (overflow, VGA_CRTC_DATA_REG); + + /* Bit 9 of Start Vertical Blanking (SVB) should be stored in the + Maximum Scanline register. */ + outb (VGA_CRTC_MAX_SCAN_LINE, VGA_CRTC_ADDR_REG); + msl = inb (VGA_CRTC_DATA_REG); + msl &= ~VGA_CRTC_SVB9; + msl |= (start & 0x200) ? VGA_CRTC_SVB9 : 0; + outb (msl, VGA_CRTC_DATA_REG); + + /* Write the End Vertical Blanking CRTC subregister. */ + outb (VGA_CRTC_VBLANK_END, VGA_CRTC_ADDR_REG); + outb (end & 0xff, VGA_CRTC_DATA_REG); +} + +static void +vga_horiz_blank (int start, int end) +{ + int old; + int size = end - start; + if (size > 63) + size = 63; + + if (end > start + 63) + end = start + 63; + + /* Start Horizontal Blank. */ + outb (VGA_CRTC_HBLANK_START, VGA_CRTC_ADDR_REG); + /* XXX: I do -1 to match the values produced by SVGATextMode, why is + that? */ + outb (start - 1, VGA_CRTC_DATA_REG); + + outb (VGA_CRTC_HBLANK_END, VGA_CRTC_ADDR_REG); + old = inb (VGA_CRTC_DATA_REG); + old &= ~0x1f; + + /* XXX: Is this calculation correct? */ + /* XXX: -3 to correct the value to what SVGATextMode has, this is + definately wrong, but ok for now. */ + old |= (end - 3) & 0x1f; + outb (old, VGA_CRTC_DATA_REG); + + /* Bit 5 of End Horizontal Blanking is stored in the End Horizontal + Retrace subregister */ + outb (VGA_CRTC_HRETRACE_END, VGA_CRTC_ADDR_REG); + old = inb (VGA_CRTC_DATA_REG); + old &= ~VGA_CRTC_EHB5; + /* XXX: -3 to correct the value to what SVGATextMode has, this is + definately wrong, but ok for now. */ + old |= ((end-3) & 0x20) ? VGA_CRTC_EHB5 : 0; + outb (old, VGA_CRTC_DATA_REG); +} + +/* XXX: start is ignored. */ +static void +vga_vert_display (int end, int total) +{ + /* For backup Overflow Register. */ + int overflow; + + /* Write the Vertical Display End Register (bits 0-7). */ + outb (VGA_CRTC_VDISPLAY_END, VGA_CRTC_ADDR_REG); + outb (end & 0xff, VGA_CRTC_DATA_REG); + + /* Read overflow. */ + outb (VGA_CRTC_OVERFLOW, VGA_CRTC_ADDR_REG); + overflow = inb (VGA_CRTC_DATA_REG); + + /* Put bit 8 and 9 of End Vertical in the Overflw subregister. */ + overflow &= ~(VGA_CRTC_VDE8 | VGA_CRTC_VDE9); + overflow |= (end & 0x100) ? VGA_CRTC_VDE8 : 0; + overflow |= (end & 0x200) ? VGA_CRTC_VDE9 : 0; + /* Put bit 8 and 9 of Vertical Total in the Overflow subregister. */ + overflow &= ~(VGA_CRTC_VT8 | VGA_CRTC_VT9); + overflow |= (total & 0x100) ? VGA_CRTC_VT8 : 0; + overflow |= (total & 0x200) ? VGA_CRTC_VT9 : 0; + outb (overflow, VGA_CRTC_DATA_REG); + + /* The Vertical Total Register is absolutely the last line on the + screen. This register stores bits (0 - 7) of this last line - + 2. */ + outb (VGA_CRTC_VTOTAL, VGA_CRTC_ADDR_REG); + outb ((total - 2) & 0xff, VGA_CRTC_DATA_REG); +} + +/* XXX: start is ignored. */ +static void +vga_horiz_display (int end, int total) +{ + /* Total number of characters. For VGA this value can't be put in + the register, first it needs to be substracted by 5. */ + outb (VGA_CRTC_HTOTAL, VGA_CRTC_ADDR_REG); + outb ((total) - 5, VGA_CRTC_DATA_REG); + + /* End Horizontal Display subregister. */ + outb (VGA_CRTC_HDISPLAY_END, VGA_CRTC_ADDR_REG); + outb (end - 1, VGA_CRTC_DATA_REG); + + /* This can be used to produce a logical screen width. In the + future this is required for scolling when the virtual console < + physical console. */ + /* Offset register. */ + outb (VGA_CRTC_OFFSET, VGA_CRTC_ADDR_REG); + outb (end / 2, VGA_CRTC_DATA_REG); +} + +/* Select the VGA pixelclock CLOCK. */ +void +vga_set_clock (int clock) +{ + int misc = inb (VGA_MISC_OUTPUT_RD_REG); + + /* For VGA the absolute maximal clocknumber is 3. */ + assert (clock <= 3); + + /* Clear the old timer value, it is stored on bits 2 and 3. */ + misc &= ~0x0c; + misc |= clock << 2; +} + +/* Set the last visible pixel on the display to END. Set the first + pixel of the horizontal retrace to SYNC_START and its last pixel to + SYNC_END. Set the last pixel of the screen to TOTAL, after this + the new line will begin. END, SYNC_START, SYNC_END and TOTAL must + be multiples of 8. Return EOVERFLOW when the hardware can't setup + the hardware registers without overflowing them, in that case the + videomode is not available. */ +static error_t +vga_driver_set_horiz_timings (int end, int sync_start, int sync_end, int total) +{ + int blank_end; + + /* The Values must be multiples of 8, the caller should have caught + all invalid values. */ + assert (!(end & 0x07)); + assert (!(sync_start & 0x07)); + assert (!(sync_end & 0x07)); + assert (!(total & 0x07)); + + /* Check if all values are within limits. */ + if (end > VGA_MAX_HDISPLAY_END + || sync_start > VGA_MAX_HSYNC_START + || end + 8 > VGA_MAX_HBLANK_START + || total > VGA_MAX_HTOTAL) + return EOVERFLOW; + + /* The CRTC controller multiplies these values by 8 when using them, + divide them by 8 here. */ + end >>= 3; + sync_start >>= 3; + sync_end >>= 3; + total >>= 3; + + /* The blanking range can be maximal 63 pixels big. */ + blank_end = total - end; + if (blank_end > 63) + blank_end = 63; + + vga_crtc_unlock (); + vga_horiz_sync (sync_start, sync_end); + /* Use the same ranges used by SVGATextMode to be sure its modes can + be used too. */ + vga_horiz_blank (end + 1, total + 1); + vga_horiz_display (end, total); + vga_crtc_lock (); + + return 0; +} + +/* Set the last visible scanline on the display to END. Set the first + scanline of the horizontal retrace to SYNC_START and its last + scanline to SYNC_END. Set the last scanline of the screen to + TOTAL, after this the new vertical period will begin. Return + EOVERFLOW when the hardware can't setup the hardware registers + without overflowing them, in that case the videomode is not + available. */ +static error_t +vga_driver_set_vert_timings (int end, int sync_start, int sync_end, int total) +{ + /* Check if all values are within limits. */ + if (end > VGA_MAX_VDISPLAY_END + || sync_start > VGA_MAX_VSYNC_START + || end + 8 > VGA_MAX_VBLANK_START + || total > VGA_MAX_VTOTAL) + return EOVERFLOW; + + vga_crtc_unlock (); + vga_vert_sync (sync_start, sync_end); + /* Use the same ranges used by SVGATextMode to be sure its modes can + be used too. */ + vga_vert_blank (end + 8, total - 8); + vga_vert_display (end - 1, total); + vga_crtc_lock (); + + return 0; +} + +int +vga_driver_get_horiz_timings (int *end, int *sync_start, int *sync_end, + int *total) +{ + /* XXX: Add some code here. */ + return 0; +} + +int +vga_driver_get_vert_timings (int *end, int *sync_start, int *sync_end, + int *total) +{ + /* XXX: Add some code here. */ + return 0; +} + +/* Set the timer to FREQUENCY Khz, the frequency used by the hardware + may be DEVIATION Khz more or less than FREQUENCY. If the + pixelclock cannot be set to FREQUENCY with the diviation DEVIATION + return EINVAL. */ +error_t +vga_driver_set_pixclock (long freq, int dev) +{ + int clock0dev; + int clock1dev; + + clock0dev = VGA_CLOCK0 - freq; + if (clock0dev < 0) + clock0dev = - clock0dev; + + clock1dev = VGA_CLOCK1 - freq; + if (clock1dev < 0) + clock1dev = - clock1dev; + + /* Choose the clock with the least deviation. */ + if (clock0dev < clock1dev) + { + if (clock0dev < dev) + vga_set_clock (0); + else + return EINVAL; + } + else + { + if (clock1dev < dev) + vga_set_clock (1); + else + return EINVAL; + } + return 0; +} + +/* Test if there is a pixelclock with FREQUENCY Khz available, the + frequency used by the hardware may be DEVIATION Khz more or less + than FREQUENCY. Return 1 if a clock is available, return 0 + otherwise. */ +error_t +vga_driver_test_pixclock (long freq, int dev) +{ + int clock0dev = VGA_CLOCK0 - freq; + int clock1dev = VGA_CLOCK1 - freq; + + if (clock0dev < 0) + clock0dev = - clock0dev; + + if (clock1dev < 0) + clock1dev = - clock1dev; + + if (clock0dev < dev || clock1dev < dev) + return 1; + else + return 0; +} + + +static struct video_driver vga_driver = +{ + "VGA", + NULL, + VGA_MAX_HDISPLAY_END, + VGA_MAX_HSYNC_START, + VGA_MAX_HBLANK_START, + VGA_MAX_HTOTAL, + VGA_MAX_VDISPLAY_END, + VGA_MAX_VSYNC_START, + VGA_MAX_VBLANK_START, + VGA_MAX_VTOTAL, + /*vga_driver_init*/ NULL, + /* vga_driver_fini */ NULL, + vga_driver_set_horiz_timings, + vga_driver_get_horiz_timings, + vga_driver_set_vert_timings, + vga_driver_get_vert_timings, + vga_driver_set_pixclock, + vga_driver_test_pixclock, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +const video_driver_t video_driver_vga = &vga_driver; diff -Nup /home/marco/src/hurdcvs/hurd.bak/console-client/video-driver.h console-client/video-driver.h --- /home/marco/src/hurdcvs/hurd.bak/console-client/video-driver.h 1970-01-01 01:00:00.000000000 +0100 +++ console-client/video-driver.h 2003-08-27 22:40:23.000000000 +0200 @@ -0,0 +1,214 @@ +/* video-driver.h - Video clock interfaces. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Marco Gerards. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +/* The powermodes that can be used to configure the power state of the + monitor. */ + +#ifndef _VIDEO_DRIVER_H_ +#define _VIDEO_DRIVER_H_ 1 + +/* DPMS powermodes. */ +enum powermode + { + /* Normal operation. */ + PM_ON, + PM_STANDBY, + PM_SUSPEND, + /* Turn the screen off. */ + PM_OFF + }; + +typedef enum powermode powermode_t; + +/* Use polarity to use for syncing. */ +typedef enum polarity + { + POLARITY_LOW, + POLARITY_HIGH + } polarity_t; + +/* The kind of sync signal that should be used. */ +typedef struct syncinfo +{ + enum + { + /* The videocard use the HSYNC and VSYNC lines to inform the + monitor of the sync. */ + SPLIT_SYNC, + /* The monitor uses only one line for both HSYNC and VSYNC. */ + CSYNC, + /* The monitor uses no seperate line for the sync; it uses one + of the color lines instead. */ + SYNC_ON_COLOR + } type; + union + { + struct + { + polarity_t hsync_pol; + polarity_t vsync_pol; + } split_sync; + struct + { + polarity_t csync_pol; + } csync; + struct + { + polarity_t pol; + /* The color line that is used for syncing. */ + enum + { + RED, + GREEN, + BLUE + } color; + } sync_on_color; + } sync_parameters; +} syncinfo_t; + +typedef unsigned int display_flags_t; + +/* Use interlacing. */ +#define DISPLAY_FLAGS_LACE (1 << 0); +/* Use a pixelclock from an external source (genlock?) */ +#define DISPLAY_FLAGS_EXTSYNC (1 << 1); +/* Use doublescan. Every line is shown twice, used for low resolution + modes. */ +#define DISPLAY_FLAGS_DOUBLE (1 << 2); + +/* Information and interfaces for a video driver. */ +struct video_driver +{ + /* Name of driver name. */ + const char *driver_name; + + /* Name of videocard or videochipset. This information is available + after initialisation with init. It can be set to NULL when it is + not relevant. */ + char *card_sub_name; + + /* Maximum allowed values. XXX: Are more maximum values + required? */ + int max_hdisplay_end; + int max_hsync_start; + int max_hblank_start; + int max_htotal; + int max_vdisplay_end; + int max_vsync_start; + int max_vblank_start; + int max_vtotal; + + /* Initialise video driver. If the hardware is not available or + usable ENODEV is returned. */ + error_t (*init) (void); + + /* Deinitialize the driver. */ + error_t (*fini) (void); + + /* Set the last visible pixel on the display to END. Set the first + pixel of the horizontal retrace to SYNC_START and its last pixel + to SYNC_END. Set the last pixel of the screen to TOTAL, after + this the new line will begin. END, SYNC_START, SYNC_END and + TOTAL must be multiples of 8. Return EOVERFLOW when the hardware + can't setup the hardware registers without overflowing them, in + that case the videomode is not available. */ + error_t (*set_horiz_timings) (int xres, int sync_start, int sync_end, + int total); + + /* Return in END the last visible pixel on the screen, in SYNC_START + the pixel on which the horizontal retrace starts, in SYNC_END the + pixel on which the horizontal retrace ends and in TOTAL the last + pixel of the screen. Never return values that are not usable + with set_horiz_timings. */ + error_t (*get_horiz_timings) (int *xres, int *sync_start, int *sync_end, + int *total); + + /* Set the last visible scanline on the display to END. Set the + first scanline of the horizontal retrace to SYNC_START and its + last scanline to SYNC_END. Set the last scanline of the screen + to TOTAL, after this the new vertical period will begin. Return + EOVERFLOW when the hardware can't setup the hardware registers + without overflowing them, in that case the videomode is not + available. */ + error_t (*set_vert_timings) (int yres, int sync_start, int sync_end, + int total); + + /* Return in END the last visible scanline on the screen, in + SYNC_START the scanline on which the horizontal retrace starts, + in SYNC_END the scanline on which the horizontal retrace ends and + in TOTAL the last scanline of the screen. Never return values + that are not usable with set_vert_timings. */ + error_t (*get_vert_timings) (int *yres, int *sync_start, int *sync_end, + int *total); + + /* Set the timer to FREQUENCY Khz, the frequency used by the + hardware may be DEVIATION Hhz more or less than FREQUENCY. If + the pixelclock cannot be set to FREQUENCY with the deviation + DEVIATION return EINVAL. */ + error_t (*set_pixclock) (long frequency, int deviation); + + /* Test if there is a pixelclock with FREQUENCY Khz available, the + frequency used by the hardware may be DEVIATION Khz more or less + than FREQUENCY. Return 1 if a clock is available, return 0 + otherwise. */ + int (*test_pixclock) (long frequency, int deviation); + + /* Set the powermode of the monitor connected to this card to + POWERMODE. If this mode is not supported, return EINVAL. */ + error_t (*set_powermode) (powermode_t powermode); + + /* Get the current powermode, it is guaranteed that the returned + powermode is setable with set_powermode. */ + powermode_t (*get_powermode) (void); + + /* Set the kind of syncronisation used to SI. */ + error_t (*set_syncinfo) (syncinfo_t *si); + + /* Get the kind of syncronisation that is used. Return the + information in *SI. SI should have been allocated by the + caller. */ + error_t (*get_syncinfo) (syncinfo_t *si); + + /* Use the options in FLAGS for producing display output. */ + error_t (*set_options) (display_flags_t flags); + + /* Get the currently used options and return them in FLAGS. */ + error_t (*get_options) (display_flags_t *flags); +}; + +typedef struct video_driver *video_driver_t; + + +/* Available video drivers. */ + +/* The video driver that is used. This is one of the drivers + below. */ +video_driver_t video_driver; + +/* The VGA driver. It only supports the minimal VGA hardware, a 25 + and 28 Mhz clock. This driver is also used by other drivers for + SVGA cards. */ +extern const video_driver_t video_driver_vga; + +/* The driver for S3 videochips. Only the S3 Trio is currently + supported, this chipset has a programmable clock. */ +extern const video_driver_t video_driver_s3; + +#endif /* _VIDEO_DRIVER_H_ */