Mercurial > hg > boxvnt
changeset 0:7b21e0889b05
Initial miniport commit; nearly identical to its sibling in the Open Watcom source tree.
author | Michal Necasek <mnecasek@yahoo.com> |
---|---|
date | Thu, 17 Jul 2014 23:22:50 +0200 |
parents | |
children | 6d1e2fb6763b |
files | boxv.c boxv.h boxv_io.h disk1 makefile oemsetup.inf readme.txt videomp.c videomp.h videomp.rc vidmini.inf vidmpdat.c |
diffstat | 12 files changed, 2191 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boxv.c Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,431 @@ +#include "boxv.h" +#include "boxv_io.h" + +/*-------------- VGA Specific ----------------*/ + +/* VGA I/O port addresses. */ +#define VGA_CRTC 0x3D4 /* Color only! */ +#define VGA_ATTR_W 0x3C0 +#define VGA_ATTR_R 0x3C1 +#define VGA_MISC_OUT_W 0x3C2 +#define VGA_SEQUENCER 0x3C4 +#define VGA_SEQUENCER_DATA 0x3C5 +#define VGA_PIXEL_MASK 0x3C6 +#define VGA_DAC_W_INDEX 0x3C8 +#define VGA_DAC_DATA 0x3C9 +#define VGA_MISC_OUT_R 0x3CC +#define VGA_GRAPH_CNTL 0x3CE +#define VGA_GRAPH_CNTL_DATA 0x3CF +#define VGA_STAT_ADDR 0x3DA /* Color only! */ + +/* VGA Attribute Controller register indexes. */ +#define VGA_AR_MODE 0x10 +#define VGA_AR_OVERSCAN 0x11 +#define VGA_AR_PLANE_EN 0x12 +#define VGA_AR_PIX_PAN 0x13 +#define VGA_AR_COLOR_SEL 0x14 + +/* VGA Graphics Controller register indexes. */ +#define VGA_GR_SET_RESET 0x00 +#define VGA_GR_DATA_ROTATE 0x03 +#define VGA_GR_READ_MAP_SEL 0x04 +#define VGA_GR_MODE 0x05 +#define VGA_GR_MISC 0x06 +#define VGA_GR_BIT_MASK 0x08 + +/* VGA Sequencer register indexes. */ +#define VGA_SR_RESET 0x00 +#define VGA_SR_CLK_MODE 0x01 +#define VGA_SR_PLANE_MASK 0x02 +#define VGA_SR_MEM_MODE 0x04 + +/* Sequencer constants. */ +#define VGA_SR0_NORESET 0x03 +#define VGA_SR0_RESET 0x00 +#define VGA_SR1_BLANK 0x20 + +/* VGA CRTC register indexes. */ +#define VGA_CR_HORZ_TOTAL 0x00 +#define VGA_CR_CUR_START 0x0A +#define VGA_CR_CUR_END 0x0B +#define VGA_CR_START_HI 0x0C +#define VGA_CR_START_LO 0x0D +#define VGA_CR_CUR_POS_HI 0x0E +#define VGA_CR_CUR_POS_LO 0x0F +#define VGA_CR_VSYNC_START 0x10 +#define VGA_CR_VSYNC_END 0x11 + +/* VGA Input Status Register 1 constants. */ +#define VGA_STAT_VSYNC 0x08 + +/*------------ End VGA Specific --------------*/ + +/*------------- bochs Specific ---------------*/ + +#define VBE_DISPI_BANK_ADDRESS 0xA0000 +#define VBE_DISPI_BANK_SIZE_KB 64 + +#define VBE_DISPI_MAX_XRES 1024 +#define VBE_DISPI_MAX_YRES 768 + +#define VBE_DISPI_IOPORT_INDEX 0x01CE +#define VBE_DISPI_IOPORT_DATA 0x01CF + +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 +#define VBE_DISPI_ID3 0xB0C3 +#define VBE_DISPI_ID4 0xB0C4 + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 + +/*------------ End bochs Specific -------------*/ + + +typedef unsigned char v_byte; +typedef unsigned short v_word; + +/* A structure describing the contents of VGA registers for a mode set. */ +typedef struct { + v_byte misc; /* Miscellaneous register. */ + v_byte seq[5]; /* Sequencer registers. */ + v_byte crtc[25]; /* CRTC registers. */ + v_byte gctl[9]; /* Graphics controller registers. */ + v_byte atr[21]; /* Attribute registers. */ +} v_vgaregs; + +/* A structure fully describing a graphics or text mode. */ +typedef struct { + int mode_no; /* Internal mode number. */ + int xres; /* Horizontal (X) resolution. */ + int yres; /* Vertical (Y) resolution. */ + int bpp; /* Bits per pixel. */ + int ext; /* Non-zero for extended modes. */ + v_vgaregs *vgaregs; /* Contents of VGA registers. */ +} v_mode; + +v_vgaregs vga_regs_ext = { + 0xe3, { 0x01, 0x01, 0x0f, 0x00, 0x0a }, { + 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x0c, 0xdf, 0x28, 0x4f, 0xe7, 0x04, 0xe3, 0xff }, { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff }, { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x41, 0x00, 0x0f, 0x00, 0x00 } +}; + +v_mode mode_640_480_8 = { + 0x101, 640, 480, 8, 1, &vga_regs_ext +}; + +v_mode mode_800_600_8 = { + 0x103, 800, 600, 8, 1, &vga_regs_ext +}; + +v_mode mode_1024_768_8 = { + 0x105, 1024, 768, 8, 1, &vga_regs_ext +}; + +v_mode mode_640_480_16 = { + 0x111, 640, 480, 16, 1, &vga_regs_ext +}; + +v_mode mode_800_600_16 = { + 0x114, 800, 600, 16, 1, &vga_regs_ext +}; + +v_mode mode_1024_768_16 = { + 0x117, 1024, 768, 16, 1, &vga_regs_ext +}; + +v_mode mode_640_480_32 = { + 0x129, 640, 480, 32, 1, &vga_regs_ext +}; + +v_mode mode_800_600_32 = { + 0x12E, 800, 600, 32, 1, &vga_regs_ext +}; + +v_mode mode_1024_768_32 = { + 0x138, 1024, 768, 32, 1, &vga_regs_ext +}; + +v_mode *mode_list[] = { + &mode_640_480_8, + &mode_800_600_8, + &mode_1024_768_8, + &mode_640_480_16, + &mode_800_600_16, + &mode_1024_768_16, + &mode_640_480_32, + &mode_800_600_32, + &mode_1024_768_32, + NULL +}; + +/* Write a single value to an indexed register at a specified + * index. Suitable for the CRTC or graphics controller. + */ +static void vid_wridx( void *cx, int idx_reg, int idx, v_byte data ) +{ + vid_outw( cx, idx_reg, idx | (data << 8) ); +} + +/* Program a sequence of bytes into an indexed register, starting + * at index 0. Suitable for loading the CRTC or graphics controller. + */ +static void vid_wridx_s( void *cx, int idx_reg, int count, v_byte *data ) +{ + int idx; + + for( idx = 0; idx < count; ++idx ) + vid_wridx( cx, idx_reg, idx, data[idx] ); /* Write index/data. */ +} + +/* Program a sequence of bytes into the attribute controller, starting + * at index 0. Note: This function may not be interrupted by code which + * also accesses the attribute controller. + */ +static void vid_wratc_s( void *cx, int count, v_byte *data ) +{ + int idx; + + vid_inb( cx, VGA_STAT_ADDR ); /* Reset flip-flop. */ + for( idx = 0; idx < count; ++idx ) { + vid_outb( cx, VGA_ATTR_W, idx ); /* Write index. */ + vid_outb( cx, VGA_ATTR_W, data[idx] ); /* Write data. */ + } +} + +v_mode *find_mode( int mode_no ) +{ + v_mode **p_mode; + v_mode *mode; + + mode = NULL; + for( p_mode = mode_list; *p_mode; ++p_mode ) { + if( (*p_mode)->mode_no == mode_no ) { + mode = *p_mode; + break; + } + } + return( mode ); +} + +/* Enumerate all available modes. Runs a callback for each mode; if the + * callback returns zero, the enumeration is terminated. + */ +void BOXV_mode_enumerate( void *cx, int (cb)( void *cx, BOXV_mode_t *mode ) ) +{ + BOXV_mode_t mode_info; + v_mode **p_mode; + v_mode *mode; + + for( p_mode = mode_list; *p_mode; ++p_mode ) { + mode = *p_mode; + mode_info.mode_no = mode->mode_no; + mode_info.xres = mode->xres; + mode_info.yres = mode->yres; + mode_info.bpp = mode->bpp; + if( !cb( cx, &mode_info ) ) + break; + } +} + +/* Set an extended non-VGA mode with given parameters. 8bpp and higher only. + * Returns non-zero value on failure. + */ +int BOXV_ext_mode_set( void *cx, int xres, int yres, int bpp, int v_xres, int v_yres ) +{ + /* Do basic parameter validation. */ + if( v_xres < xres || v_yres < yres ) + return( -1 ); + + /* Put the hardware into a state where the mode can be safely set. */ + vid_inb( cx, VGA_STAT_ADDR ); /* Reset flip-flop. */ + vid_outb( cx, VGA_ATTR_W, 0 ); /* Disable palette. */ + vid_wridx( cx, VGA_SEQUENCER, VGA_SR_RESET, VGA_SR_RESET ); + + /* Disable the extended display registers. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED ); + + /* Program the extended non-VGA registers. */ + + /* Set X resoultion. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, xres ); + /* Set Y resoultion. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, yres ); + /* Set bits per pixel. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, bpp ); + /* Set the virtual resolution. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, v_xres ); + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_HEIGHT ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, v_yres ); + /* Reset the current bank. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BANK ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 ); + /* Set the X and Y display offset to 0. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 ); + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 ); + /* Enable the extended display registers. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_8BIT_DAC ); + + /* Re-enable the sequencer. */ + vid_wridx( cx, VGA_SEQUENCER, VGA_SR_RESET, VGA_SR0_NORESET ); + + /* Re-enable palette. */ + vid_outb( cx, VGA_ATTR_W, 0x20 ); + + return( 0 ); +} + +/* Set the requested mode (text or graphics). + * Returns non-zero value on failure. + */ +int BOXV_mode_set( void *cx, int mode_no ) +{ + v_mode *mode; + v_vgaregs *vgarg; + + mode = find_mode( mode_no ); + if( !mode ) + return( -1 ); + + /* Put the hardware into a state where the mode can be safely set. */ + vid_inb( cx, VGA_STAT_ADDR ); /* Reset flip-flop. */ + vid_outb( cx, VGA_ATTR_W, 0 ); /* Disable palette. */ + vid_wridx( cx, VGA_CRTC, VGA_CR_VSYNC_END, 0 ); /* Unlock CR0-CR7. */ + vid_wridx( cx, VGA_SEQUENCER, VGA_SR_RESET, VGA_SR_RESET ); + + /* Disable the extended display registers. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED ); + + /* Optionally program the extended non-VGA registers. */ + if( mode->ext ) { + /* Set X resoultion. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, mode->xres ); + /* Set Y resoultion. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, mode->yres ); + /* Set bits per pixel. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, mode->bpp ); + /* Set the virtual resolution. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, mode->xres ); + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_HEIGHT ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, mode->yres ); + /* Reset the current bank. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BANK ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 ); + /* Set the X and Y display offset to 0. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 ); + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, 0 ); + /* Enable the extended display registers. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_8BIT_DAC ); + } + + vgarg = mode->vgaregs; + + /* Program misc. output register. */ + vid_outb( cx, VGA_MISC_OUT_W, vgarg->misc ); + + /* Program the sequencer. */ + vid_wridx_s( cx, VGA_SEQUENCER, sizeof( vgarg->seq ), vgarg->seq ); + vid_wridx( cx, VGA_SEQUENCER, VGA_SR_RESET, VGA_SR0_NORESET ); + + /* Program the CRTC and graphics controller. */ + vid_wridx_s( cx, VGA_CRTC, sizeof( vgarg->crtc ), vgarg->crtc ); + vid_wridx_s( cx, VGA_GRAPH_CNTL, sizeof( vgarg->gctl ), vgarg->gctl ); + + /* Finally program the attribute controller. */ + vid_wratc_s( cx, sizeof( vgarg->atr ), vgarg->atr ); + vid_outb( cx, VGA_ATTR_W, 0x20 ); /* Re-enable palette. */ + + return( 0 ); +} + +/* Program the DAC. Each of the 'count' entries is 4 bytes in size, + * red/green/blue/unused. + * Returns non-zero on failure. + */ +int BOXV_dac_set( void *cx, unsigned start, unsigned count, void *pal ) +{ + v_byte *prgbu = pal; + + /* Basic argument validation. */ + if( start + count > 256 ) + return( -1 ); + + /* Write the starting index. */ + vid_outb( cx, VGA_DAC_W_INDEX, start ); + /* Load the RGB data. */ + while( count-- ) { + vid_outb( cx, VGA_DAC_DATA, *prgbu++ ); + vid_outb( cx, VGA_DAC_DATA, *prgbu++ ); + vid_outb( cx, VGA_DAC_DATA, *prgbu++ ); + ++prgbu; + } + return( 0 ); +} + +/* Detect the presence of a supported adapter and amount of installed + * video memory. Returns zero if not found. + */ +int BOXV_detect( void *cx, unsigned long *vram_size ) +{ + v_word boxv_id; + + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID ); + boxv_id = vid_inw( cx, VBE_DISPI_IOPORT_DATA ); + if( vram_size ) { + *vram_size = vid_ind( cx, VBE_DISPI_IOPORT_DATA ); + } + if( boxv_id >= VBE_DISPI_ID0 && boxv_id <= VBE_DISPI_ID4 ) + return( boxv_id ); + else + return( 0 ); +} + +/* Disable extended mode and place the hardware into a VGA compatible state. + * Returns non-zero on failure. + */ +int BOXV_ext_disable( void *cx ) +{ + /* Disable the extended display registers. */ + vid_outw( cx, VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE ); + vid_outw( cx, VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED ); + return( 0 ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boxv.h Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,24 @@ +/* + * Public interface to the boxv library. + */ + +/* PCI vendor and device IDs. */ +#define BOXV_PCI_VEN 0x80EE +#define BOXV_PCI_DEV 0xBEEF + +/* A structure describing mode information. Note: The mode numbers + * usually match VBE, but this should not be relied upon. + */ +typedef struct { + int mode_no; /* Mode number */ + int xres; /* Horizontal resolution */ + int yres; /* Vertical resolution */ + int bpp; /* Color depth */ +} BOXV_mode_t; + +extern void BOXV_mode_enumerate( void *cx, int (cb)( void *cx, BOXV_mode_t *mode ) ); +extern int BOXV_detect( void *cx, unsigned long *vram_size ); +extern int BOXV_ext_mode_set( void *cx, int xres, int yres, int bpp, int v_xres, int v_yres ); +extern int BOXV_mode_set( void *cx, int mode_no ); +extern int BOXV_dac_set( void *cx, unsigned start, unsigned count, void *pal ); +extern int BOXV_ext_disable( void *cx );
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/boxv_io.h Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,44 @@ + +#include <miniport.h> +#include <ntddvdeo.h> +#include <video.h> +#include "videomp.h" + +/* In this case, vid_in/out cannot be defined as macros because NT uses + * a pretty funky interface for I/O port access. + */ + +static void vid_outb( void *cx, unsigned port, unsigned val ) +{ + PHW_DEV_EXT pExt = cx; + + VideoPortWritePortUchar( pExt->IOAddrVGA + port, val ); +} + +static void vid_outw( void *cx, unsigned port, unsigned val ) +{ + PHW_DEV_EXT pExt = cx; + + VideoPortWritePortUshort( (PUSHORT)(pExt->IOAddrVGA + port), val ); +} + +static unsigned vid_inb( void *cx, unsigned port ) +{ + PHW_DEV_EXT pExt = cx; + + return( VideoPortReadPortUchar( pExt->IOAddrVGA + port ) ); +} + +static unsigned vid_inw( void *cx, unsigned port ) +{ + PHW_DEV_EXT pExt = cx; + + return( VideoPortReadPortUshort( (PUSHORT)(pExt->IOAddrVGA + port) ) ); +} + +static unsigned vid_ind( void *cx, unsigned port ) +{ + PHW_DEV_EXT pExt = cx; + + return( VideoPortReadPortUlong( (PULONG)(pExt->IOAddrVGA + port) ) ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/disk1 Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,1 @@ +fdsjk \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/makefile Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,61 @@ +CC = wcc386 +RC = wrc +CFLAGS = -q -s -ecd -wx +RCFLAGS = -q -r -zm +INCS = -I"$(%WATCOM)/h/nt/ddk" +LIBS = $(%WATCOM)/lib386/nt/ddk + +# Debug flag - note that the video port in Windows NT 3.x only exports +# VideoDebugPort in checked builds! +#CFLAGS += -DDBG + +CFLAGS += -d1 -hc + +OBJS = videomp.obj vidmpdat.obj boxv.obj + +.c.obj : .autodepend + $(CC) $(CFLAGS) $(INCS) $< + +boxvideo.sys : $(OBJS) $(__MAKEFILES__) videomp.res + wlink op quiet, map name $@ format windows nt runtime native=1.0 & + debug codeview op symf, cvpack & + option start='_DriverEntry@8' & + option offset=0x10000, checksum, osversion=1.0, version=1.0 & + option stack=0x100000, heapsize=0x100000 & + segment class CODE nonpageable, class DATA nonpageable & + file { $OBJS } libpath $(LIBS) lib videoprt resource videomp.res + +# Normally we would like to use the following: +# option alignment=0x20, objalign=0x20 +# but that causes the driver image to fail loading on old NT releases; +# the driver is small enough that it's not worth the trouble + +videomp.res : videomp.rc + $(RC) $(RCFLAGS) $(INCS) $< + +# Create a 1.44MB distribution floppy image. +# NB: The mkimage tool is not supplied. +videomp.img : boxvideo.sys disk1 readme.txt oemsetup.inf vidmini.inf + if not exist dist mkdir dist + cp disk1 dist + cp boxvideo.sys dist + cp boxvideo.sym dist + cp oemsetup.inf dist + cp vidmini.inf dist + cp readme.txt dist + mkimage -l VIDEOMP -o videomp.img dist + +clean : .symbolic + rm -f *.obj + rm -f *.sys + rm -f *.sym + rm -f *.res + rm -f *.map + rm -f videomp.img + rm -f dist/disk1 + rm -f dist/boxvideo.sys + rm -f dist/boxvideo.sym + rm -f dist/oemsetup.inf + rm -f dist/vidmini.inf + rm -f dist/readme.txt + if exist dist rmdir dist
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/oemsetup.inf Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,577 @@ +;----------------------------------------------------------------------- +; OPTION TYPE +; ----------- +; This identifies the Option type we are dealing with. The different +; possible types are: +; +; COMPUTER, DISPLAY, MOUSE, KEYBOARD, LAYOUT, SCSI, PRINTER, ... +;----------------------------------------------------------------------- + +[Identification] + OptionType = VIDEO + +;----------------------------------------------------------------------- +; LANGUAGES SUPPORTED +; ------------------- +; +; The languages supported by the OEM INF, For every language supported +; we need to have a separate text section for every displayable text +; section. +; +;----------------------------------------------------------------------- + +[LanguagesSupported] + ENG + +;----------------------------------------------------------------------- +; OPTION LIST +; ----------- +; This section lists the OEM Option key names. These keys are locale +; independent and used to represent the option in a locale independent +; manner. +; +;----------------------------------------------------------------------- + +; +; Option list order: +; Option = Miniport driver, BitsPerPel, XResolution, YResolution, VRefresh, Interlaced +; +; If you don't want to create a VRefresh or Interlaced value under the service +; parameters then use the value "" + +[Options] + "VirtualBox 640x480x8" = boxv, 8, 640, 480, 60, 0 + "VirtualBox 800x600x8" = boxv, 8, 800, 600, 60, 0 + "VirtualBox 1024x768x8" = boxv, 8, 1024, 768, 60, 0 + "VirtualBox 1152x864x8" = boxv, 8, 1152, 864, 60, 0 + "VirtualBox 640x480x16" = boxv, 16, 640, 480, 60, 0 + "VirtualBox 800x600x16" = boxv, 16, 800, 600, 60, 0 + "VirtualBox 1024x768x16" = boxv, 16, 1024, 768, 60, 0 + "VirtualBox 1152x864x16" = boxv, 16, 1152, 864, 60, 0 + "VirtualBox 640x480x32" = boxv, 32, 640, 480, 60, 0 + "VirtualBox 800x600x32" = boxv, 32, 800, 600, 60, 0 + "VirtualBox 1024x768x32" = boxv, 32, 1024, 768, 60, 0 + "VirtualBox 1152x864x32" = boxv, 32, 1152, 864, 60, 0 + +; +; This maps detected options into the options we support +; +; Format: DetectedOption = MappedOption +; + +[MapOfOptions] + "VirtualBox 640x480x8" = "VirtualBox 640x480x8" + "VirtualBox 800x600x8" = "VirtualBox 800x600x8" + "VirtualBox 1024x768x8" = "VirtualBox 1024x768x8" + "VirtualBox 640x480x16" = "VirtualBox 640x480x16" + "VirtualBox 800x600x16" = "VirtualBox 800x600x16" + "VirtualBox 1024x768x16" = "VirtualBox 1024x768x16" + "VirtualBox 640x480x32" = "VirtualBox 640x480x32" + "VirtualBox 800x600x32" = "VirtualBox 800x600x32" + "VirtualBox 1024x768x32" = "VirtualBox 1024x768x32" + +; +; Order of the information: +; +; Port driver = Type, Group, ErrorControl, Tag, InstalledDisplay, VgaCompatible, EventMessageFile, TypesSupported +; + +[MiniportDrivers] + boxv = !SERVICE_KERNEL_DRIVER, Video, !SERVICE_ERROR_IGNORE, 12, {framebuf}, 0 , %SystemRoot%\System32\IoLogMsg.dll , 7 + +;----------------------------------------------------------------------- +; OPTION TEXT SECTION +; ------------------- +; These are text strings used to identify the option to the user. There +; are separate sections for each language supported. The format of the +; section name is "OptionsText" concatenated with the Language represented +; by the section. +; +;----------------------------------------------------------------------- + +[OptionsTextENG] + "VirtualBox 640x480x8" = "VirtualBox 640x480, 256 colors" + "VirtualBox 800x600x8" = "VirtualBox 800x600, 256 colors" + "VirtualBox 1024x768x8" = "VirtualBox 1024x768, 256 colors" + "VirtualBox 1152x864x8" = "VirtualBox 1152x864, 256 colors" + "VirtualBox 640x480x16" = "VirtualBox 640x480, 64K colors" + "VirtualBox 800x600x16" = "VirtualBox 800x600, 64K colors" + "VirtualBox 1024x768x16" = "VirtualBox 1024x768, 64K colors" + "VirtualBox 1152x864x16" = "VirtualBox 1152x864, 64K colors" + "VirtualBox 640x480x32" = "VirtualBox 640x480, True Color" + "VirtualBox 800x600x32" = "VirtualBox 800x600, True Color" + "VirtualBox 1024x768x32" = "VirtualBox 1024x768, True Color" + "VirtualBox 1152x864x32" = "VirtualBox 1152x864, True Color" + +;--------------------------------------------------------------------------- +; 1. Identify +; +; DESCRIPTION: To verify that this INF deals with the same type of options +; as we are choosing currently. +; +; INPUT: None +; +; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL +; $($R1): Option Type (COMPUTER ...) +; $($R2): Diskette description +;--------------------------------------------------------------------------- + +[Identify] + ; + ; + read-syms Identification + + set Status = STATUS_SUCCESSFUL + set Identifier = $(OptionType) + set Media = #("Source Media Descriptions", 1, 1) + + Return $(Status) $(Identifier) $(Media) + + + +;------------------------------------------------------------------------ +; 2. ReturnOptions: +; +; DESCRIPTION: To return the option list supported by this INF and the +; localised text list representing the options. +; +; +; INPUT: $($0): Language used. ( ENG | FRN | ... ) +; +; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL | +; STATUS_NOLANGUAGE +; STATUS_FAILED +; +; $($R1): Option List +; $($R2): Option Text List +;------------------------------------------------------------------------ + +[ReturnOptions] + ; + ; + set Status = STATUS_FAILED + set OptionList = {} + set OptionTextList = {} + + ; + ; Check if the language requested is supported + ; + set LanguageList = ^(LanguagesSupported, 1) + Ifcontains(i) $($0) in $(LanguageList) + goto returnoptions + else + set Status = STATUS_NOLANGUAGE + goto finish_ReturnOptions + endif + + ; + ; form a list of all the options and another of the text representing + ; + +returnoptions = + + set OptionList = ^(Options, 0) + set OptionTextList = ^(OptionsText$($0), 1) + set Status = STATUS_SUCCESSFUL + +finish_ReturnOptions = + + Return $(Status) $(OptionList) $(OptionTextList) + + +;--------------------------------------------------------------------------- +; MapToSupportedOption +; +; DESCRIPTION: To map a hardware detected option to the NT Supported +; option which represents it. +; +; INPUT: $($0): Option +; +; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL +; $($R1): Mapped Option +; +;--------------------------------------------------------------------------- + +[MapToSupportedOption] + ; + set Status = STATUS_FAILED + set MappedOption = $($0) + + ; + ; If the option is one we can support using one of our standard options + ; then map it to the standard option else pass it back as such to be + ; an OEM installed option + ; + + set OptionList = ^(MapOfOptions, 0) + ifcontains $($0) in $(OptionList) + set MappedOption = #(MapOfOptions, $($0), 1) + endif + + set Status = STATUS_SUCCESSFUL + Return $(Status) $(MappedOption) + + + +[ServicesEntry] + CurrentEntry = "" ? $(!LIBHANDLE) GetDevicemapValue Video \Device\Video0 + +; +; InstallOption: +; +; FUNCTION: To copy files representing Options +; To configure the installed option +; To update the registry for the installed option +; +; INPUT: $($0): Language to use +; $($1): OptionID to install +; $($2): SourceDirectory +; $($3): AddCopy (YES | NO) +; $($4): DoCopy (YES | NO) +; $($5): DoConfig (YES | NO) +; +; OUTPUT: $($R0): STATUS: STATUS_SUCCESSFUL | +; STATUS_NOLANGUAGE | +; STATUS_USERCANCEL | +; STATUS_FAILED +; + +[InstallOption] + + ; + ; Set default values for + ; + set Status = STATUS_FAILED + set DrivesToFree = {} + + ; + ; extract parameters + ; + set Option = $($1) + set SrcDir = $($2) + set AddCopy = $($3) + set DoCopy = $($4) + set DoConfig = $($5) + + ; + ; Check if the language requested is supported + ; + set LanguageList = ^(LanguagesSupported, 1) + Ifcontains(i) $($0) in $(LanguageList) + else + set Status = STATUS_NOLANGUAGE + goto finish_InstallOption + endif + read-syms Strings$($0) + + ; + ; check to see if Option is supported. + ; + + set OptionList = ^(Options, 0) + ifcontains $(Option) in $(OptionList) + else + goto finish_InstallOption + endif + set OptionList = "" + + ; + ; Option has been defined already + ; + + set MiniportDriver = #(Options, $(Option), 1) + set BitsPerPel = #(Options, $(Option), 2) + set XResolution = #(Options, $(Option), 3) + set YResolution = #(Options, $(Option), 4) + set VRefresh = #(Options, $(Option), 5) + set Interlaced = #(Options, $(Option), 6) + + set Type = $(#(MiniportDrivers, $(MiniportDriver), 1)) + set Group = #(MiniportDrivers, $(MiniportDriver), 2) + set ErrorControl = $(#(MiniportDrivers, $(MiniportDriver), 3)) + set Tag = #(MiniportDrivers, $(MiniportDriver), 4) + set InstalledDisplays = #(MiniportDrivers, $(MiniportDriver), 5) + set VgaCompatible = #(MiniportDrivers, $(MiniportDriver), 6) + set EventMessageFile = #(MiniportDrivers, $(MiniportDriver), 7) + set TypesSupported = #(MiniportDrivers, $(MiniportDriver), 8) + + + read-syms ServicesEntry + detect ServicesEntry + +installtheoption = + + + ; + ; Code to add files to copy list + ; + + ifstr(i) $(AddCopy) == "YES" + set DoActualCopy = NO + set FileToCheck = #(Files-DisplayMiniportDrivers, $(MiniportDriver), 2) + LibraryProcedure STATUS,$(!LIBHANDLE),CheckFileExistance $(!STF_WINDOWSSYSPATH)"\drivers\"$(FileToCheck) + ifstr(i) $(STATUS) == NO + set DoActualCopy = YES + goto addfiles + endif + ForListDo $(InstalledDisplays) + set FileToCheck = #(Files-DisplayDLLs, $($), 2) + LibraryProcedure STATUS,$(!LIBHANDLE),CheckFileExistance $(!STF_WINDOWSSYSPATH)"\"$(FileToCheck) + ifstr(i) $(STATUS) == NO + set DoActualCopy = YES + endif + EndForListDo + +addfiles = + + ifstr(i) $(DoActualCopy) == NO + shell "subroutn.inf" DriversExist $($0) $(String1) + ifint $($ShellCode) != $(!SHELL_CODE_OK) + Debug-Output "VIDEO.INF: shelling DriversExist failed" + goto finish_InstallOption + endif + + ifstr(i) $($R0) == STATUS_CURRENT + else-ifstr(i) $($R0) == STATUS_NEW + set DoActualCopy = YES + else-ifstr(i) $($R0) == STATUS_USERCANCEL + Debug-Output "VIDEO.INF: User cancelled video installation" + goto finish_InstallOption + else + Debug-Output "VIDEO.INF: Error reported in DriversExist routine in SUBROUTN.INF" + goto finish_InstallOption + endif + endif + + ifstr(i) $(DoActualCopy) == YES + + shell "subroutn.inf" DoAskSourceEx $(SrcDir) $(String2) + ifint $($ShellCode) != $(!SHELL_CODE_OK) + Debug-Output "Video.INF: shelling DoAskSourceEx failed" + goto finish_InstallOption + endif + + ifstr(i) $($R0) == STATUS_SUCCESSFUL + set SrcDir = $($R1) + ifstr(i) $($R2) != "" + set DrivesToFree = >($(DrivesToFree), $($R2)) + endif + else + Debug-Output "Video.inf: User cancelled asking source." + goto finish_InstallOption + endif + + install Install-AddCopyOption + ifstr(i) $(STF_INSTALL_OUTCOME) != "STF_SUCCESS" + Debug-Output "Adding video files to copy list failed" + goto finish_InstallOption + endif + else + set DoCopy = NO + endif + endif + + ifstr(i) $(DoCopy) == "YES" + read-syms ProgressCopy$($0) + install Install-DoCopyOption + ifstr(i) $(STF_INSTALL_OUTCOME) == "STF_FAILURE" + Debug-Output "Copying files failed" + goto finish_InstallOption + else-ifstr(i) $(STF_INSTALL_OUTCOME) == "STF_USERQUIT" + set Status = STATUS_USERCANCEL + goto finish_InstallOption + endif + endif + + ifstr(i) $(DoConfig) == "YES" + + ; + ; first run a privilege check on modifying the setup node + ; + + shell "registry.inf" CheckSetupModify + ifint $($ShellCode) != $(!SHELL_CODE_OK) + goto finish_InstallOption + endif + + ifstr(i) $($R0) != STATUS_SUCCESSFUL + goto finish_InstallOption + endif + + ; + ; first make a new video entry, the entry is created automatically + ; enabled + ; + + set ServiceNode = $(MiniportDriver) + set ServiceBinary = %SystemRoot%\System32\drivers\#(Files-DisplayMiniportDrivers, $(MiniportDriver), 2) + + set ServicesValues = { + + {Type, 0, $(!REG_VT_DWORD), $(Type) }, + + {Start, 0, $(!REG_VT_DWORD), $(!SERVICE_SYSTEM_START) }, + + {Group, 0, $(!REG_VT_SZ), $(Group) }, + + {ErrorControl, 0, $(!REG_VT_DWORD), $(ErrorControl) }, + + {Tag, 0, $(!REG_VT_DWORD), $(Tag) }, + + {BinaryPathName, 0, $(!REG_VT_EXPAND_SZ), $(ServiceBinary) } + + } + set ParametersValues = { + + {InstalledDisplayDrivers, 0, $(!REG_VT_MULTI_SZ), $(InstalledDisplays) }, + + {VgaCompatible, 0, $(!REG_VT_DWORD), $(VgaCompatible) }, + + {DefaultSettings.BitsPerPel, 0, $(!REG_VT_DWORD), $(BitsPerPel) }, + + {DefaultSettings.XResolution, 0, $(!REG_VT_DWORD), $(XResolution) }, + + {DefaultSettings.YResolution, 0, $(!REG_VT_DWORD), $(YResolution) } + + } + + ifstr(i) $(VRefresh) != "" + set VRefreshValue = {DefaultSettings.VRefresh, 0, $(!REG_VT_DWORD), $(VRefresh)} + set ParametersValue = >($(ParametersValue), $(VRefreshValue)) + endif + + ifstr(i) $(Interlaced) != "" + set InterlacedValue = {DefaultSettings.Interlaced, 0, $(!REG_VT_DWORD), $(Interlaced)} + set ParametersValue = >($(ParametersValue), $(InterlacedValue)) + endif + + set DeviceValues = {} + set EventLogValues = { + + {EventMessageFile, 0, $(!REG_VT_EXPAND_SZ), $(EventMessageFile) }, + + {TypesSupported, 0, $(!REG_VT_DWORD), $(TypesSupported) } + + } + + + shell "registry.inf" MakeServicesEntry $(ServiceNode) + + $(ServicesValues) + + $(ParametersValues) + + $(DeviceValues) + + $(EventLogValues) + + Device0 + + + ifint $($ShellCode) != $(!SHELL_CODE_OK) + Debug-Output "Couldn't execute MakeServicesEntry in registry.inf" + goto finish_InstallOption + endif + + ifstr(i) $($R0) != STATUS_SUCCESSFUL + Debug-Output "MakeServicesEntry failed for video" + goto finish_InstallOption + endif + + ; + ; + ; then disable the previous video entry + ; + + ifstr(i) $(CurrentEntry) != $(MiniportDriver) + ifstr(i) $(CurrentEntry) != VGA + ifstr(i) $(CurrentEntry) != "" + shell "registry.inf" ModifyServicesEntry $(CurrentEntry) $(!SERVICE_DISABLED) + + ifint $($ShellCode) != $(!SHELL_CODE_OK) + Debug-Output "Couldn't find DisableServicesEntry in registry.inf" + goto errorconfig + endif + + ifstr(i) $($R0) != STATUS_SUCCESSFUL + Debug-Output "DisableServices entry failed" + endif + endif + endif + endif + + goto configdone + +errorconfig = + + ifstr(i) $(CurrentEntry) != $(MiniportDriver) + shell "registry.inf" ModifyServicesEntry $(MiniportDriver) $(!SERVICE_DISABLED) + ifstr(i) $(CurrentEntry) != "" + shell "registry.inf" ModifyServicesEntry $(CurrentEntry) $(!SERVICE_SYSTEM_START) + endif + endif + goto finish_InstallOption + +configdone = + + + endif + + set Status = STATUS_SUCCESSFUL + +finish_InstallOption = + + ForListDo $(DrivesToFree) + LibraryProcedure STATUS,$(!LIBHANDLE), DeleteNetConnection $($) "TRUE" + EndForListDo + + Return $(Status) + + +[Install-AddCopyOption] + + set STF_VITAL = "" + ; + ; Add the files to the copy list + ; + AddSectionKeyFileToCopyList Files-DisplayMiniportDrivers + + $(MiniportDriver) + + $(SrcDir) + + $(!STF_WINDOWSSYSPATH)\drivers + + ForListDo $(InstalledDisplays) + AddSectionKeyFileToCopyList Files-DisplayDLLs + + $($) + + $(SrcDir) + + $(!STF_WINDOWSSYSPATH) + + EndForListDo + + exit + + +[Install-DoCopyOption] + + ; + ; Copy files in the copy list + ; + CopyFilesInCopyList + exit + +;************************************************************************** +; PROGRESS GUAGE VARIABLES +;************************************************************************** + +[ProgressCopyENG] + ProCaption = "Windows NT Setup" + ProCancel = "Cancel" + ProCancelMsg = "Windows NT is not correcly installed. Are you sure you want "+ + "to cancel copying files?" + ProCancelCap = "Setup Message" + ProText1 = "Copying:" + ProText2 = "To:" + +[StringsENG] + String1 = "Display" + String2 = "Please enter the full path to the Windows NT Display "+ + "driver files. Then choose Continue." + + + +;----------------------------------------------------------------------- +; SOURCE MEDIA DESCRIPTIONS +; ------------------------- +; The OEM should list all the diskette labels here. The source media +; description is used during copy to prompt the user for a diskette +; if the source is diskettes. +; +; Use 1 = "Diskette 1 Label" , TAGFILE = disk1 +; 2 = "Diskette 2 Label" , TAGFILE = disk2 +; ... +;----------------------------------------------------------------------- + +[Source Media Descriptions] + 1 = "OEM DISK (VIDEO)" , TAGFILE = disk1 + 2 = "Windows NT CD-ROM" , TAGFILE = cdrom.w + + +[Files-DisplayDLLs] +; Because this .INF script appears to be unable to copy from two different +; drives, we can't ask the user to insert the NT CD-ROM with framebuf.dll; +; the user must manually copy it alongside the video miniport. +framebuf = 1,framebuf.dll , SIZE=999 + +[Files-DisplayMiniportDrivers] +boxv = 1,boxvideo.sys , SIZE=999
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/readme.txt Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,39 @@ + + Windows NT Video Miniport Programming Example + --------------------------------------------- + + The sample video miniport supports the virtual SVGA chip supported by the +VirtualBox hypervisor. It may also work with bochs and qemu, but this has not +been tested; small changes may be required. + + The source code is split into two parts: The boxv module (boxv*) and the +miniport proper (videomp*). The boxv module provides a simple collection of +routines to set modes on the VirtualBox/qemu/bochs virtual SVGA chip. The +vidmini module implements the Windows NT video miniport interface. + + The miniport only provides minimal mode setting and palette access interface +since the virtual hardware does not support hardware cursors etc. All drawing +is left to framebuf.dll, the default Windows NT framebuffer display driver. + + Please refer to the Windows NT DDK for documentation on the video miniport +interface. + + + Supported Windows Versions + + The miniport supports all Windows NT x86 versions from the original NT 3.1 +up to 6.2 (Windows 7). Windows XP and above ships with a VGA/VESA driver which +provides similar functionality, but blocks power management (hibernation). + + + Installation + + The installation method depends on Windows version used. For Windows NT 3.1, +the Setup applet must be used. For all other versions, the display property +dialog should be used. There are two versions of the INF file: oemsetup.inf +for Windows NT 3.x and vidmini.inf for Windows NT 4 and later versions. + + Important: For Windows NT 3.x, the framebuf.dll library provided on the NT +installation media is required and should be copied to the directory which +contains the INF file. For Windows NT 4.0 and later, framebuf.dll +is already preinstalled on the system.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videomp.c Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,758 @@ +/* + * Windows NT Video Miniport for the VirtualBox/bochs/qemu SVGA adapter. + * This miniport programs the hardware directly and does not use or require + * the video BIOS or VBE. + * + * NB: This is not a "VGA compatible" miniport and standard VGA modes are + * handled by the default VGA miniport. + */ + +#include <miniport.h> +#include <ntddvdeo.h> +#include <video.h> +#include <dderror.h> +#include <stddef.h> + +#include "videomp.h" +#include "boxv.h" + + +/* Number of PCI access ranges. */ +#define NUM_PCI_RANGES 3 + +/* RGB color channel constants. */ +typedef enum { + CHANNEL_RED, + CHANNEL_GREEN, + CHANNEL_BLUE +} COLOR_CHANNEL; + + +#if defined( ALLOC_PRAGMA ) +#pragma alloc_text( PAGE, DriverEntry ) +#pragma alloc_text( PAGE, HwVidFindAdapter ) +#pragma alloc_text( PAGE, HwVidInitialize ) +#pragma alloc_text( PAGE, HwVidStartIO ) +#endif + + +/* Calculate pitch based on scanline length and bit depth. */ +static ULONG vmpPitchByBpp( ULONG Length, UCHAR Bpp ) +{ + ULONG ulPitch = 0; + + switch( Bpp ) { + case 4: + ulPitch = (Length + 1) / 2; + break; + case 8: + ulPitch = Length; + break; + case 15: + case 16: + ulPitch = Length * 2; + break; + case 24: + ulPitch = Length * 3; + break; + case 32: + ulPitch = Length * 4; + break; + } + return( ulPitch ); +} + + +/* Validate a given mode and set the appropriate flag. Note that the + * validation criteria are somewhat arbitrary. + */ +static void vmpValidateMode( PVIDEOMP_MODE Mode, ULONG FramebufLen ) +{ + ULONG ulModeMem; + + Mode->bValid = FALSE; + + do { + /* Horizontal resolution should be divisible by 8. */ + if( Mode->HorzRes % 8) + break; + + /* Validate memory requirements. */ + ulModeMem = vmpPitchByBpp( Mode->HorzRes, Mode->Bpp ) * Mode->VertRes; + if( ulModeMem > FramebufLen ) + break; + + /* Passed all checks, mode is valid. */ + Mode->bValid = TRUE; + } while( 0 ); +} + +/* Determine whether the supported adapter is present. Note that this + * function is not allowed to change the state of the adapter! + */ +VP_STATUS HwVidFindAdapter( PVOID HwDevExt, PVOID HwContext, PWSTR ArgumentString, + PVIDEO_PORT_CONFIG_INFO ConfigInfo, PUCHAR Again ) +{ + PHW_DEV_EXT pExt = HwDevExt; + PVOID *pVirtAddr; + ULONG i; + INT chip_id; + VP_STATUS status; + ULONG cbVramSize; + PWSTR pwszDesc; + ULONG cbDesc; +#ifdef USE_GETACCESSRANGES + VIDEO_ACCESS_RANGE pciAccessRanges[NUM_PCI_RANGES]; + USHORT usVendorId = BOXV_PCI_VEN; + USHORT usDeviceId = BOXV_PCI_DEV; + ULONG ulSlot = 0; +#endif + + //@todo: The framebuffer address should not be hardcoded for non-PCI access +#define NUM_ACCESS_RANGES 2 + VIDEO_ACCESS_RANGE accessRanges[NUM_ACCESS_RANGES] = { + /* StartLo StartHi Len IO Vis Shr */ + { 0x000001CE, 0x00000000, 0x00000002, 1, 1, 0 }, /* I/O ports */ + { 0xE0000000, 0x00000000, 0x00400000, 0, 1, 0 } /* Framebuffer */ + }; + + VideoDebugPrint( (1, "videomp: HwVidFindAdapter\n") ); + + /* Fail if the passed structure is smaller than the NT 3.1 version. */ + if( ConfigInfo->Length < offsetof( VIDEO_PORT_CONFIG_INFO, DmaChannel ) ) { + return( ERROR_INVALID_PARAMETER ); + } + + /* Sadly, VideoPortGetAccessRanges was not present in NT 3.1. There is no + * reasonably simple way to dynamically import port driver routines on + * newer versions, so we'll just do without. + */ +#ifdef USE_GETACCESSRANGES + /* If PCI is supported, query the bus for resource mappings. */ + if( ConfigInfo->AdapterInterfaceType == PCIBus ) { + /* Ask for bus specific access ranges. */ + VideoPortZeroMemory( pciAccessRanges, sizeof( pciAccessRanges ) ); + status = VideoPortGetAccessRanges( HwDevExt, 0, NULL, + NUM_PCI_RANGES, pciAccessRanges, + &usVendorId, &usDeviceId, &ulSlot ); + if( status == NO_ERROR ) { + VideoDebugPrint( (1, "videomp: Found adapter in PCI slot %d\n", ulSlot) ); + pExt->ulSlot = ulSlot; + /* The framebuffer is in the first slot of the PCI ranges. Copy + * the data into the access ranges we're going to request. + */ + accessRanges[1].RangeStart = pciAccessRanges[0].RangeStart; + accessRanges[1].RangeLength = pciAccessRanges[0].RangeLength; + } else { + /* On NT versions without PCI support, we won't even attempt this. + * So if we tried to query the PCI device and failed to find it, + * it really isn't there and we have to give up. + */ + VideoDebugPrint( (1, "videomp: PCI adapter not found\n") ); + return( ERROR_DEV_NOT_EXIST ); + } + } +#endif + + /* Some versions of vga.sys trap accesses to ports 0x1CE-0x1CF used on + * old ATI cards. On Windows 2000 and later we can report legacy + * resources to resolve this conflict. On NT 4 and older, we use a hack + * and claim other, non-conflicting ports. + */ + if( PortVersion < VP_VER_W2K ) + accessRanges[0].RangeStart = RtlConvertUlongToLargeInteger( 0x1CC ); + + /* Check for a conflict in case someone else claimed our resources. */ + status = VideoPortVerifyAccessRanges( HwDevExt, NUM_ACCESS_RANGES, accessRanges ); + if( status != NO_ERROR ) { + return( status ); + } + + /* Indicate no emulator support. */ + ConfigInfo->NumEmulatorAccessEntries = 0; + ConfigInfo->EmulatorAccessEntries = NULL; + ConfigInfo->EmulatorAccessEntriesContext = 0; + + ConfigInfo->HardwareStateSize = 0; + + ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = 0; + ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0; + ConfigInfo->VdmPhysicalVideoMemoryLength = 0; + + /* Describe the framebuffer. We claimed the range already. */ + pExt->PhysicalFrameAddress = accessRanges[1].RangeStart; + + + /* + * Map all memory and I/O ranges into system virtual address space. + * NB: The virtual addresses in the HwDevExt must match the number + * and type of AccessRange entries. + */ + pVirtAddr = &pExt->IoPorts; + + /* Attempt to claim and map the memory and I/O address ranges. */ + for( i = 0; i < NUM_ACCESS_RANGES; ++i, ++pVirtAddr ) { + *pVirtAddr = VideoPortGetDeviceBase( pExt, + accessRanges[i].RangeStart, + accessRanges[i].RangeLength, + accessRanges[i].RangeInIoSpace ); + if( *pVirtAddr == NULL ) { + return( ERROR_INVALID_PARAMETER ); + } + } + + /* Verify that supported hardware is present. */ + chip_id = BOXV_detect( pExt, &pExt->FramebufLen ); + if( !chip_id ) { + /* If supported hardware was not found, free allocated resources. */ + pVirtAddr = &pExt->IoPorts; + for( i = 0; i < NUM_ACCESS_RANGES; ++i, ++pVirtAddr ) + VideoPortFreeDeviceBase( pExt, *pVirtAddr ); + + return( ERROR_DEV_NOT_EXIST ); + } + + /* We need to access VGA and other I/O ports. Fortunately the HAL doesn't + * care at all how the I/O ports are or aren't mapped on x86 platforms. + */ + pExt->IOAddrVGA = NULL; + + /* Only support one attached monitor. */ + pExt->NumMonitors = 1; + + /* Set up mode information. */ + pExt->CurrentModeNumber = 0; + pExt->NumValidModes = 0; + + for( i = 0; i < ulAllModes; ++i ) { + vmpValidateMode( &VideoModes[i], pExt->FramebufLen ); + if( VideoModes[i].bValid ) + ++pExt->NumValidModes; + } + + /* Only one adapter supported, no need to call us again. */ + *Again = 0; + + /* Report the hardware names via registry. */ + +#define TEMP_CHIP_NAME L"bochs Mk II" + pwszDesc = TEMP_CHIP_NAME; + cbDesc = sizeof( TEMP_CHIP_NAME ); + + VideoPortSetRegistryParameters( pExt, L"HardwareInformation.ChipType", + pwszDesc, cbDesc ); + +#define TEMP_DAC_NAME L"Integrated DAC" + pwszDesc = TEMP_DAC_NAME; + cbDesc = sizeof( TEMP_DAC_NAME ); + VideoPortSetRegistryParameters( pExt, L"HardwareInformation.DacType", + pwszDesc, cbDesc ); + +#define TEMP_ADAPTER_NAME L"VirtualBox/bochs" + pwszDesc = TEMP_ADAPTER_NAME; + cbDesc = sizeof( TEMP_ADAPTER_NAME ); + VideoPortSetRegistryParameters( pExt, L"HardwareInformation.AdapterString", + pwszDesc, cbDesc ); + + cbVramSize = pExt->FramebufLen; + VideoPortSetRegistryParameters( pExt, L"HardwareInformation.MemorySize", + &cbVramSize, sizeof( ULONG ) ); + /* All is well. */ + return( NO_ERROR ); +} + + +/* Perform one-time device initialization. Once this function has been + * entered, the miniport may change adapter state. + */ +BOOLEAN HwVidInitialize( PVOID HwDevExt ) +{ + VideoDebugPrint( (1, "videomp: HwVidInitialize\n") ); + return( TRUE ); +} + + +/* Determine pixel mask given color depth and color channel. */ +static ULONG vmpMaskByBpp( UCHAR Bpp, COLOR_CHANNEL Channel ) +{ + ULONG ulMask; + + switch( Bpp ) { + case 24: + case 32: + ulMask = 0x00FF0000 >> (Channel * 8); + break; + case 15: + ulMask = 0x00007C00 >> (Channel * 5); + break; + case 16: + switch( Channel ) { + case CHANNEL_RED: + ulMask = 0x0000F800; + break; + case CHANNEL_GREEN: + ulMask = 0x000007E0; + break; + case CHANNEL_BLUE: + ulMask = 0x0000001F; + break; + } + break; + case 4: + case 8: + default: + ulMask = 0; /* Palettized modes don't have a mask. */ + } + + return( ulMask ); +} + +/* Fill out NT specific video mode information struct based on resolution + * and color depth. + */ +static void vmpFillModeInfo( PVIDEO_MODE_INFORMATION ModeInfo, USHORT HRes, USHORT VRes, UCHAR Bpp) +{ + /* First the basic mode information. */ + ModeInfo->Length = sizeof( VIDEO_MODE_INFORMATION ); + ModeInfo->ModeIndex = 0; /* Filled in later. */ + ModeInfo->VisScreenWidth = HRes; /* Horizontal resolution in pixels. */ + ModeInfo->VisScreenHeight = VRes; /* Vertical resolution in pixels. */ + + /* Assume no rounding is necessary. */ + ModeInfo->ScreenStride = vmpPitchByBpp( HRes, Bpp ); + + ModeInfo->NumberOfPlanes = 1; /* Always one plane - packed pixel only. */ + ModeInfo->BitsPerPlane = Bpp; /* Number of bits per pixel. */ + ModeInfo->Frequency = 60; /* Irrelevant; just make something up. */ + + /* Screen size is made up, but should correspond to aspect ratio. */ + ModeInfo->XMillimeter = 320; + ModeInfo->YMillimeter = ModeInfo->XMillimeter * VRes / HRes; + + /* The DAC always works with 8 bits per channel. */ + ModeInfo->NumberRedBits = 8; /* Red pixels in DAC. */ + ModeInfo->NumberGreenBits = 8; /* Green pixels in DAC. */ + ModeInfo->NumberBlueBits = 8; /* Blue pixels in DAC. */ + + /* Pixel mask depends on color depth. */ + ModeInfo->RedMask = vmpMaskByBpp( Bpp, CHANNEL_RED ); + ModeInfo->GreenMask = vmpMaskByBpp( Bpp, CHANNEL_GREEN ); + ModeInfo->BlueMask = vmpMaskByBpp( Bpp, CHANNEL_BLUE ); + + /* Mode attributes are only different for 8bpp modes. */ + ModeInfo->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR; + if( Bpp <= 8 ) + ModeInfo->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE; + + /* Strictly speaking, the following don't need to be filled out. */ + ModeInfo->VideoMemoryBitmapWidth = 0; + ModeInfo->VideoMemoryBitmapHeight = 0; + ModeInfo->DriverSpecificAttributeFlags = 0; +} + +/* Main I/O request handler routine. */ +BOOLEAN HwVidStartIO( PVOID HwDevExt, PVIDEO_REQUEST_PACKET ReqPkt ) +{ + PHW_DEV_EXT pExt = HwDevExt; + VP_STATUS status = NO_ERROR; + PVIDEO_MODE_INFORMATION modeInfo; + PVIDEO_MEMORY vidMem; + PVIDEO_SHARE_MEMORY pShrMem; + PVOID virtualAddress; + ULONG inIoSpace; + ULONG modeNumber; + ULONG ulLen; + ULONG i; + + VideoDebugPrint( (2, "videomp: HwVidStartIO: ") ); + + /* Process the VRP. Required requests are handled first. */ + switch( ReqPkt->IoControlCode ) { + case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES: + { + PVIDEO_NUM_MODES numModes; + + VideoDebugPrint( (2, "QUERY_NUM_AVAIL_MODES\n") ); + if( ReqPkt->OutputBufferLength < sizeof( VIDEO_NUM_MODES ) ) { + status = ERROR_INSUFFICIENT_BUFFER; + } else { + ReqPkt->StatusBlock->Information = sizeof( VIDEO_NUM_MODES ); + numModes = (PVIDEO_NUM_MODES)ReqPkt->OutputBuffer; + numModes->ModeInformationLength = sizeof( VIDEO_MODE_INFORMATION ); + numModes->NumModes = pExt->NumValidModes; + } + break; + } + + case IOCTL_VIDEO_QUERY_AVAIL_MODES: + VideoDebugPrint( (2, "QUERY_AVAIL_MODES\n") ); + ulLen = pExt->NumValidModes * sizeof( VIDEO_MODE_INFORMATION ); + if( ReqPkt->OutputBufferLength < ulLen ) { + status = ERROR_INSUFFICIENT_BUFFER; + } else { + ReqPkt->StatusBlock->Information = ulLen; + modeInfo = ReqPkt->OutputBuffer; + for( i = 0; i < ulAllModes; ++i ) { + if( VideoModes[i].bValid ) { + vmpFillModeInfo( modeInfo, VideoModes[i].HorzRes, + VideoModes[i].VertRes, VideoModes[i].Bpp ); + modeInfo->ModeIndex = i; //VideoModes[i].modeInformation.ModeIndex; + + modeInfo++; + } + } + } + break; + + case IOCTL_VIDEO_QUERY_CURRENT_MODE: + VideoDebugPrint( (2, "QUERY_CURRENT_MODE\n") ); + if( ReqPkt->OutputBufferLength < sizeof( VIDEO_MODE_INFORMATION ) ) { + status = ERROR_INSUFFICIENT_BUFFER; + } else { + ReqPkt->StatusBlock->Information = sizeof( VIDEO_MODE_INFORMATION ); + modeInfo = ReqPkt->OutputBuffer; + vmpFillModeInfo( modeInfo, + VideoModes[pExt->CurrentModeNumber].HorzRes, + VideoModes[pExt->CurrentModeNumber].VertRes, + VideoModes[pExt->CurrentModeNumber].Bpp ); + modeInfo->ModeIndex = pExt->CurrentModeNumber; //VideoModes[pExt->CurrentModeNumber].modeInformation.ModeIndex; + } + + break; + + case IOCTL_VIDEO_SET_CURRENT_MODE: + VideoDebugPrint( (2, "SET_CURRENT_MODE\n") ); + + /* Ensure the mode is valid. */ + modeNumber = ((PVIDEO_MODE)(ReqPkt->InputBuffer))->RequestedMode; + + if( (modeNumber > ulAllModes) || (!VideoModes[modeNumber].bValid) ) { + status = ERROR_INVALID_PARAMETER; + break; + } + + BOXV_ext_mode_set( pExt, VideoModes[modeNumber].HorzRes, + VideoModes[modeNumber].VertRes, VideoModes[modeNumber].Bpp, + VideoModes[modeNumber].HorzRes, VideoModes[modeNumber].VertRes ); + + pExt->CurrentModeNumber = modeNumber; + break; + + case IOCTL_VIDEO_RESET_DEVICE: + VideoDebugPrint( (2, "RESET_DEVICE\n") ); + /* Not calling the following routine avoids some visual glitches. */ + /* BOXV_ext_disable( pExt ); */ + break; + + case IOCTL_VIDEO_MAP_VIDEO_MEMORY: + { + PVIDEO_MEMORY_INFORMATION memInfo; + + VideoDebugPrint( (2, "MAP_VIDEO_MEMORY\n") ); + if( (ReqPkt->OutputBufferLength < sizeof( VIDEO_MEMORY_INFORMATION )) || + (ReqPkt->InputBufferLength < sizeof( VIDEO_MEMORY )) ) { + + status = ERROR_INSUFFICIENT_BUFFER; + break; + } + + ReqPkt->StatusBlock->Information = sizeof( VIDEO_MEMORY_INFORMATION ); + + vidMem = (PVIDEO_MEMORY)ReqPkt->InputBuffer; + memInfo = ReqPkt->OutputBuffer; + inIoSpace = FALSE; + + memInfo->VideoRamBase = vidMem->RequestedVirtualAddress; + memInfo->VideoRamLength = pExt->FramebufLen; + + status = VideoPortMapMemory( pExt, pExt->PhysicalFrameAddress, + &memInfo->VideoRamLength, &inIoSpace, + &memInfo->VideoRamBase ); + + /* The framebuffer covers the entire video memory. */ + memInfo->FrameBufferBase = memInfo->VideoRamBase; + memInfo->FrameBufferLength = memInfo->VideoRamLength; + break; + } + + case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: + VideoDebugPrint( (2, "UNMAP_VIDEO_MEMORY\n") ); + if( ReqPkt->InputBufferLength < sizeof( VIDEO_MEMORY ) ) { + status = ERROR_INSUFFICIENT_BUFFER; + } else { + vidMem = (PVIDEO_MEMORY)ReqPkt->InputBuffer; + status = VideoPortUnmapMemory( pExt, + vidMem->RequestedVirtualAddress, + 0 ); + } + break; + + /* The following request is required for palettized modes. */ + case IOCTL_VIDEO_SET_COLOR_REGISTERS: + { + PVIDEO_CLUT clutBuffer; + + VideoDebugPrint( (2, "SET_COLOR_REGISTERS\n") ); + clutBuffer = ReqPkt->InputBuffer; + + if( (ReqPkt->InputBufferLength < sizeof( VIDEO_CLUT ) - sizeof( ULONG )) || + (ReqPkt->InputBufferLength < sizeof( VIDEO_CLUT ) + + (sizeof( ULONG ) * (clutBuffer->NumEntries - 1)) ) ) { + + status = ERROR_INSUFFICIENT_BUFFER; + break; + } + + if( VideoModes[pExt->CurrentModeNumber].Bpp == 8 ) { + BOXV_dac_set( pExt, clutBuffer->FirstEntry, clutBuffer->NumEntries, + clutBuffer->LookupTable ); + } + break; + } + + /* The following requests are optional. */ + case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES: + { + PVIDEO_POINTER_CAPABILITIES ptrCaps = ReqPkt->OutputBuffer; + + VideoDebugPrint( (2, "QUERY_POINTER_CAPABILITIES\n") ); + if( ReqPkt->OutputBufferLength < sizeof( VIDEO_POINTER_CAPABILITIES ) ) { + ReqPkt->StatusBlock->Information = 0; + status = ERROR_INSUFFICIENT_BUFFER; + } + + ptrCaps->Flags = 0; /* Indicate no pointer support. */ + ptrCaps->MaxWidth = ptrCaps->MaxHeight = 0; + /* Documentation and sample code disagree on whether no display + * memory for cursor is indicated by 0 or -1. + */ + ptrCaps->HWPtrBitmapStart = ptrCaps->HWPtrBitmapEnd = ~0; + + ReqPkt->StatusBlock->Information = sizeof( VIDEO_POINTER_CAPABILITIES ); + break; + } + + /* The share/unshare IOCTLs are new for NT 3.51. */ + case IOCTL_VIDEO_SHARE_VIDEO_MEMORY: + { + PVIDEO_SHARE_MEMORY_INFORMATION pShrMemInfo; + PHYSICAL_ADDRESS shareAddress; + ULONG sharedViewSize; + + VideoDebugPrint( (2, "SHARE_VIDEO_MEMORY\n") ); + if( (ReqPkt->OutputBufferLength < sizeof( VIDEO_SHARE_MEMORY_INFORMATION )) || + (ReqPkt->InputBufferLength < sizeof( VIDEO_MEMORY )) ) { + + status = ERROR_INSUFFICIENT_BUFFER; + break; + } + + pShrMem = ReqPkt->InputBuffer; + + if( (pShrMem->ViewOffset > pExt->FramebufLen) || + ((pShrMem->ViewOffset + pShrMem->ViewSize) > pExt->FramebufLen) ) { + + status = ERROR_INVALID_PARAMETER; + break; + } + + ReqPkt->StatusBlock->Information = sizeof( VIDEO_SHARE_MEMORY_INFORMATION ); + + /* The input buffer is also the output buffer; remember the input. */ + virtualAddress = pShrMem->ProcessHandle; + sharedViewSize = pShrMem->ViewSize; + + inIoSpace = FALSE; + + /* NB: ViewOffset is not being taken into account. */ + shareAddress.QuadPart = pExt->PhysicalFrameAddress.QuadPart; + + status = VideoPortMapMemory( pExt, shareAddress, + &sharedViewSize, &inIoSpace, + &virtualAddress ); + + pShrMemInfo = ReqPkt->OutputBuffer; + pShrMemInfo->SharedViewOffset = pShrMem->ViewOffset; + pShrMemInfo->VirtualAddress = virtualAddress; + pShrMemInfo->SharedViewSize = sharedViewSize; + break; + } + + case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: + VideoDebugPrint( (2, "UNSHARE_VIDEO_MEMORY\n") ); + if( ReqPkt->InputBufferLength < sizeof( VIDEO_SHARE_MEMORY ) ) { + status = ERROR_INSUFFICIENT_BUFFER; + break; + } + + pShrMem = ReqPkt->InputBuffer; + status = VideoPortUnmapMemory( pExt, pShrMem->RequestedVirtualAddress, + pShrMem->ProcessHandle ); + break; + + + /* The child state IOCTLs are new for NT 5.0 (Windows 2000). */ + case IOCTL_VIDEO_GET_CHILD_STATE: + { + PULONG pChildIndex; + PULONG pChildState; + + VideoDebugPrint( (2, "GET_CHILD_STATE\n") ); + if( ReqPkt->InputBufferLength < sizeof( ULONG ) || + ReqPkt->OutputBufferLength < sizeof( ULONG ) ) { + status = ERROR_INSUFFICIENT_BUFFER; + break; + } + + pChildIndex = ReqPkt->InputBuffer; + pChildState = ReqPkt->OutputBuffer; + + /* Always say the child is active. */ + *pChildState = VIDEO_CHILD_ACTIVE; + break; + } + + /* Any other request is invalid and fails. */ + default: + VideoDebugPrint( (1, "Unhandled IoControlCode %08x!\n", ReqPkt->IoControlCode) ); + status = ERROR_INVALID_FUNCTION; + break; + } + + ReqPkt->StatusBlock->Status = status; + return( TRUE ); +} + +/* Validate support for a requested power state. */ +VP_STATUS HwGetPowerState( PVOID HwDevExt, ULONG HwId, + PVIDEO_POWER_MANAGEMENT VideoPowerControl ) +{ + VideoDebugPrint( (1, "videomp: HwGetPowerState\n") ); + return( NO_ERROR ); +} + +/* Set the device power state. */ +VP_STATUS HwSetPowerState( PVOID HwDevExt, ULONG HwId, + PVIDEO_POWER_MANAGEMENT VideoPowerControl ) +{ + VideoDebugPrint( (1, "videomp: HwSetPowerState\n") ); + return( NO_ERROR ); +} + +/* Return child device descriptors. In this case just a single monitor. */ +VP_STATUS HwGetChildDesc( PVOID HwDevExt, PVIDEO_CHILD_ENUM_INFO ChildEnumInfo, + PVIDEO_CHILD_TYPE VideoChildType, PUCHAR pChildDescriptor, + PULONG UId, PULONG pUnused ) +{ + PHW_DEV_EXT pExt = HwDevExt; + + VideoDebugPrint( (1, "videomp: HwGetChildDesc\n") ); + + if( ChildEnumInfo->ChildIndex > 0 ) { + if( (int)ChildEnumInfo->ChildIndex <= pExt->NumMonitors ) { + *VideoChildType = Monitor; + *UId = ChildEnumInfo->ChildIndex; + return( VIDEO_ENUM_MORE_DEVICES ); + } + } + + return( ERROR_NO_MORE_DEVICES ); +} + +/* Reset the adapter into a VGA-compatible state. */ +BOOLEAN HwVidResetHw( PVOID HwDevExt, ULONG Columns, ULONG Rows ) +{ + PHW_DEV_EXT pExt = HwDevExt; + + VideoDebugPrint( (1, "videomp: HwVidResetHw\n") ); + + BOXV_ext_disable( pExt ); + /* Indicate that we didn't actually set the requested text mode. */ + return( FALSE ); +} + +/* Standard NT driver initialization entry point. */ +ULONG DriverEntry( PVOID Context1, PVOID Context2 ) +{ + VIDEO_HW_INITIALIZATION_DATA hwInitData; + ULONG status; + + VideoDebugPrint( (1, "videomp: DriverEntry\n") ); + + /* Prepare the initialization structure. */ + VideoPortZeroMemory( &hwInitData, sizeof( VIDEO_HW_INITIALIZATION_DATA ) ); + hwInitData.HwInitDataSize = sizeof( VIDEO_HW_INITIALIZATION_DATA ); + + /* Set up driver callbacks. */ + hwInitData.HwFindAdapter = HwVidFindAdapter; + hwInitData.HwInitialize = HwVidInitialize; + hwInitData.HwStartIO = HwVidStartIO; + /* There's no interrupt or timer callback. */ + hwInitData.HwInterrupt = NULL; + hwInitData.HwTimer = NULL; + hwInitData.HwResetHw = HwVidResetHw; + + /* Power and child device management callbacks were added in NT 5.0. */ + hwInitData.HwGetPowerState = HwGetPowerState; + hwInitData.HwSetPowerState = HwSetPowerState; + hwInitData.HwGetVideoChildDescriptor = HwGetChildDesc; + + /* Report legacy resources. */ + hwInitData.HwLegacyResourceList = LegacyRanges; + hwInitData.HwLegacyResourceCount = ulNumLegacyRanges; + + /* Report the device extension size. */ + hwInitData.HwDeviceExtensionSize = sizeof( HW_DEV_EXT ); + + /* Refer to the CurrentControlSet\Services\xxx\Device0 registry key. */ + hwInitData.StartingDeviceNumber = 0; + + /* Later NT versions support PCI; recent versions ignore this entirely */ + hwInitData.AdapterInterfaceType = PCIBus; + + /* The PsGetVersion function was not available in NT 3.x. We therefore + * implement a poor man's version detection by successively reducing the + * HwInitDataSize until the video miniport (we hope) accepts it. + */ + do { + /* First try with NT 5.1 (Windows XP) structure size. */ + VideoDebugPrint( (1, "videomp: Trying DDI 5.1 HwInitDataSize\n") ); + hwInitData.HwInitDataSize = SIZE_OF_WXP_VIDEO_HW_INITIALIZATION_DATA; + PortVersion = VP_VER_XP; + status = VideoPortInitialize( Context1, Context2, &hwInitData, NULL ); + if( status != STATUS_REVISION_MISMATCH ) { + /* If status is anything other than a version mismatch, don't + * try calling VideoPortInitialize again. The call may have + * succeeded, or it failed for some reason whe can't easily fix. + */ + break; + } + + /* Try the NT 5.0 (Windows 2000) structure size. */ + VideoDebugPrint( (1, "videomp: Trying DDI 5.0 HwInitDataSize\n") ); + hwInitData.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA; + PortVersion = VP_VER_W2K; + status = VideoPortInitialize( Context1, Context2, &hwInitData, NULL ); + if( status != STATUS_REVISION_MISMATCH ) { + break; + } + + /* Try the NT 4.0 (and also NT 3.51) structure size. */ + VideoDebugPrint( (1, "videomp: Trying DDI 4.0 HwInitDataSize\n") ); + hwInitData.HwInitDataSize = SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA; + PortVersion = VP_VER_NT4; + status = VideoPortInitialize( Context1, Context2, &hwInitData, NULL ); + if( status != STATUS_REVISION_MISMATCH ) { + break; + } + + /* Try the original NT 3.1/3.5 HwInitDataSize. No PCI support. */ + VideoDebugPrint( (1, "videomp: Trying DDI 3.1 HwInitDataSize\n") ); + hwInitData.HwInitDataSize = offsetof( VIDEO_HW_INITIALIZATION_DATA, HwResetHw ); + hwInitData.AdapterInterfaceType = Isa; + PortVersion = VP_VER_NT31; + status = VideoPortInitialize( Context1, Context2, &hwInitData, NULL ); + } while( 0 ); + VideoDebugPrint( (1, "videomp: VideoPortInitialize rc=%08x\n", status ) ); + return( status ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videomp.h Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,39 @@ +/* + * Internal video miniport interfaces. + */ + +/* Video Port versions that affect miniport behavior. */ + +#define VP_VER_NT31 0x030100 +#define VP_VER_NT4 0x040000 /* Also NT 3.51 */ +#define VP_VER_W2K 0x050000 +#define VP_VER_XP 0x050100 + +/* Video mode description structure */ +typedef struct { + USHORT HorzRes; /* Horizontal resolution */ + USHORT VertRes; /* Vertical resolution */ + UCHAR Bpp; /* Bits per pixel */ + BOOLEAN bValid; /* Valid mode flag */ +} VIDEOMP_MODE, *PVIDEOMP_MODE; + +/* The device extension - private miniport data */ +typedef struct { + PVOID IoPorts; /* I/O ports mapping */ + PVOID FrameAddress; /* Framebuffer mapping */ + PHYSICAL_ADDRESS PhysicalFrameAddress; /* Physical FB address */ + ULONG FramebufLen; /* Framebuffer length */ + ULONG CurrentModeNumber; /* Current mode index */ + ULONG NumValidModes; /* Number of valid modes */ + ULONG NumMonitors; /* Number of attached monitors */ + PUCHAR IOAddrVGA; /* VGA I/O ports mapping */ + ULONG ulSlot; /* PCI slot the adapter is in. */ + ULONG PortVersion; /* Video Port version */ +} HW_DEV_EXT, *PHW_DEV_EXT; + +/* Variables defined in vidmpdat.c */ +extern VIDEOMP_MODE VideoModes[]; +extern ULONG ulAllModes; +extern VIDEO_ACCESS_RANGE LegacyRanges[]; +extern ULONG ulNumLegacyRanges; +extern ULONG PortVersion;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videomp.rc Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,33 @@ +#include <windows.h> + +#define VMP_VERSION 1,00,00,002 +VS_VERSION_INFO VERSIONINFO +FILEVERSION VMP_VERSION +PRODUCTVERSION VMP_VERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS 0 +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_DRV +FILESUBTYPE VFT2_DRV_DISPLAY +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" /* US English, Unicode codepage */ + BEGIN + VALUE "CompanyName", "OS/2 Museum" + VALUE "FileDescription", "Boxvideo Video Miniport Driver" + VALUE "FileVersion", "1.3" + VALUE "InternalName", "boxvideo.sys" + VALUE "LegalCopyright", "Copyright \251 2014 The OS/2 Museum" + VALUE "OriginalFilename","boxvideo.sys" + VALUE "ProductName", "Sample Video Miniport" + VALUE "ProductVersion", "1.3" + END + + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 0x04B0 + END +END
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vidmini.inf Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,112 @@ +; vidmini.inf +; +; Installation INF for the vidmini graphics driver. +; + +[Version] +Signature = "$WINDOWS NT$" +Provider = %BOXV% +ClassGUID = {4D36E968-E325-11CE-BFC1-08002BE10318} +Class = Display + +[DestinationDirs] +DefaultDestDir = 11 +vidmini.Miniport = 12 ; drivers +vidmini.Display = 11 ; system32 + +; +; Driver information +; + +[Manufacturer] +%BOXV% = BOXV.Mfg + +[BOXV.Mfg] +%BOXV% SVGA = vidmini, PCI\VEN_80EE&DEV_BEEF + + +; +; General installation section +; + +[vidmini] +CopyFiles = vidmini.Miniport, vidmini.Display + +; +; File sections +; + +[vidmini.Miniport] +boxvideo.sys,,,0x100 + +[vidmini.Display] +; The framebuf display driver is shipped with and pre-installed by NT 4. +; Note that earlier NT version shipped with framebuf.dll but didn't +; pre-install it. + +; +; Service (driver) Installation +; + +[vidmini.Services] +AddService = vidmini, 0x00000002, vidmini_Service_Inst, vidmini_EventLog_Inst + +[vidmini_Service_Inst] +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 1 ; SERVICE_SYSTEM_START +ErrorControl = 0 ; SERVICE_ERROR_IGNORE +LoadOrderGroup = Video +ServiceBinary = %12%\boxvideo.sys + +[vidmini_EventLog_Inst] +AddReg = vidmini_EventLog_AddReg + +[vidmini_EventLog_AddReg] +HKR,,EventMessageFile,0x00020000,"%SystemRoot%\System32\IoLogMsg.dll;%SystemRoot%\System32\drivers\boxvideo.sys" +HKR,,TypesSupported,0x00010001,7 + + +; +; Software Installation +; + +[vidmini.SoftwareSettings] +AddReg = vidmini_SoftwareDeviceSettings + +[vidmini_SoftwareDeviceSettings] +HKR,, InstalledDisplayDrivers, %REG_MULTI_SZ%, framebuf +HKR,, VgaCompatible, %REG_DWORD%, 0 + + +; +; Source file information +; + +[SourceDisksNames.x86] +1 = %DiskId%,,,"" + +[SourceDisksFiles] +vidmini.sys = 1 +; framebuf.dll = 1 ; already preinstalled by NT, no need to copy + + + +[Strings] + +; +; Non-Localizable Strings +; + +REG_SZ = 0x00000000 +REG_MULTI_SZ = 0x00010000 +REG_EXPAND_SZ = 0x00020000 +REG_BINARY = 0x00000001 +REG_DWORD = 0x00010001 + +; +; Localizable Strings +; + +DiskId = "BOXV Installation Disk" +GraphAdap = "Graphics Adapter" +BOXV = "VirtualBox"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vidmpdat.c Thu Jul 17 23:22:50 2014 +0200 @@ -0,0 +1,72 @@ +/* + * Video miniport static data. + */ + +#include <miniport.h> +#include <ntddvdeo.h> +#include <video.h> +#include "videomp.h" + +#if defined(ALLOC_PRAGMA) +#pragma data_seg("PAGE") +#endif + +/* + * Legacy resources claimed by the device. + * + * RangeStart RangeLength + * | | RangeInIoSpace + * | | | RangeVisible + * +-----+-----+ | | | RangeShareable + * low high | | | | RangePassive + * v v v v v v v + */ +VIDEO_ACCESS_RANGE LegacyRanges[] = { + { 0x000001CE, 0x00000000, 0x00000002, 1, 1, 1, 0 }, /* 0x1CE-0x1CF */ + { 0x000003B0, 0x00000000, 0x0000000C, 1, 1, 1, 0 }, /* 0x3B0-0x3BB */ + { 0x000003C0, 0x00000000, 0x00000020, 1, 1, 1, 0 }, /* 0x3C0-0x3DF */ + { 0x000A0000, 0x00000000, 0x00020000, 0, 0, 1, 0 } /* 0xA0000-0xBFFFF */ +}; + +ULONG ulNumLegacyRanges = sizeof( LegacyRanges ) / sizeof( VIDEO_ACCESS_RANGE ); + +/* Define a resolution for all supported color depths. */ +#define MODE_RES( x, y ) \ + { x, y, 8 }, { x, y, 15 }, { x, y, 16 }, { x, y, 24 }, { x, y, 32 } + + +/* Table of supported modes. Note that the resolutions we can set are + * quite arbitrary, but there's no point in reporting a massive list. + * All modes start out as unsupported and must be validated. + */ +VIDEOMP_MODE VideoModes[] = { + MODE_RES( 640, 480 ), + MODE_RES( 800, 600 ), + MODE_RES( 1024, 768 ), + MODE_RES( 1152, 864 ), + MODE_RES( 1280, 720 ), + MODE_RES( 1280, 800 ), + MODE_RES( 1280, 960 ), + MODE_RES( 1360, 768 ), + MODE_RES( 1360, 1024 ), + MODE_RES( 1366, 768 ), + MODE_RES( 1400, 1050 ), + MODE_RES( 1440, 900 ), + MODE_RES( 1600, 1200 ), + MODE_RES( 1680, 1050 ), + MODE_RES( 1920, 1080 ), + MODE_RES( 1920, 1200 ), + MODE_RES( 2048, 1152 ), + MODE_RES( 2048, 1536 ), + MODE_RES( 2560, 1600 ) +}; + +ULONG ulAllModes = sizeof( VideoModes ) / sizeof( VideoModes[0] ); + +/* Video Port interface version. Needs to be global because DriverEntry can + * no longer pass context information to HwVidFindAdapter. */ +ULONG PortVersion; + +#if defined( ALLOC_PRAGMA ) +#pragma data_seg() +#endif