Here are some tips on writing a new chipset svgalib driver. They don't require knowledge of direct vga programming, even though that helps. The instructions assume: 1- A super vga card, that is a card which is extended, but also fully compatible to standard vga. Of the cards available today (in the mass market), all are, with the possible exception of Permedia chipsets. 2- A PCI (or AGP) connected card. This is useful for detction of the card, and for finding the linear aperture, as well as knowing its always there. 3- Knowledge of the extended features of the chipset: Usually either as the spec, or a source of a driver for the chipset (xfree86). as a start, get the following: 1- vgadoc4b.zip[1] (or a later version), includes information on the vga hardware registers, as well as on many chipsets. 2- the latest svgalib[2]. 3- If the card is supported by xfree86, either the link kit (Xlkit.tgz[3]) if the card is supported by the XF86_SVGA server, or the Xfree source ([4]), if it is supported by a special server. 1. in the src subdir of the svgalib distribution, cp skeleton.c to some other name, chipset.c, where chipset is the name of the chipset you intend to support. 2. now you have to fill the blanks. The functions that need to be are sk_setpage sk_saveregs sk_setregs sk_initializemode sk_unlock sk_test sk_setdisplaystart sk_setlogicalwidth sk_init 3. When that is done, change all sk_ in the driver to chipset_ (where chipset is the name of the chipset you write the driver for). Then the driver needs to be integrated into svgalib. The files that need to be edited are: Makefile.cfg src/Makefile src/driver.h src/vga.c src/vga.h (It's easy to see what changes are needed in those files, by simply seeing how its done for another driver). 4. Now is the most interesting time - debugging. Usually (in my experience, in all cases), the driver won't work right immediately. Here are a few debugging tips: Setting modes is made of two things: setting the timings, and setting the memory organisation. You can usually tell which is the problem, by noticing if the wrong screen is seen as if some/all pixels are not set to the color they should (memory organisation), or the display looks "stormy" (timings problem). If the problem is timing problem, a digital monitor taht displays horizontal and vertical timings helps. If the horizontal freq is right, but vertical is wrong, then the problem is in the vertical timing. If both horiz and vert are wrong, then either the clock frequency, or the horizontal frequency is wrong. If the problem is in memory organisation, It might work in linear mode, so try running testlinear and lineart. If the driver fails to restore text mode properly, then usually starting X will work. It won't help restoring text mode, but then you might be able to see the output of the program (using /dev/vcs?, /dev/vcsa?). The program mode3 (in lrmi-0.6m subdir) might be able to restore text mode, corrupted by a bad driver. The same mode3 might be used for debugging as follows: if a mode, say 800x600x256 does not work properly, but mode3 does work, you might try the following run vgatest, select 11 (for 800x600x256), and while the wrong mode is displayed, press d (to recieve a registers dump). then, try mode3 259 ; utils/dumpreg ; mode3, and compare the register dump of vesa mode 259 (800x600x256), with the output from your driver. Try finding out what do the bits that are different mean. Here are some more details on writing the necessary functions: examples given are from the banshee.c driver, written according to the spec available from 3dfx, and the (hypotethical) milleniumII.c driver, written according to the XFree86 source. _setpage: This is a simple function. A mistake in this function is indicated by: all linear programs work fine, while in paged memory examples, the problem is that blocks (full width * ??? lines) are moved. For millenium, from freebe (this part is unavailable in X source, since X uses only linear mode). { outw(0x3de,(page<<8)|4); }; For Banshee: { page<<=1; outl(banshee_io_base+0x2c,(inl(banshee_io_base+0x2c)&0xfff00000)|(page)|(page<<10)); } _saveregs, _setregs This functions should save and restore the state of the svga card, such that it can be restored to a previous state, no matter what we do. A mistake is indicated by failure to restore text mode properly. We should save all registers that we change, or might be changed by other programs (X, SVGATextMode, etc.), here's the banshee_saveregs: typedef struct { unsigned int pllCtrl0, pllCtrl1, dacMode, dacAddr, vidProcCfg, vidScreenSize, vgaInit0, vgaInit1, vidDesktopStartAddr,vidDesktopOverlayStride; } *HWRecPtr; static int banshee_saveregs(unsigned char regs[]) { HWRecPtr save; banshee_unlock(); save=(HWRecPtr)(regs+62); regs[BANSHEEREG_SAVE(0)]=__svgalib_inCR(0x1a); regs[BANSHEEREG_SAVE(1)]=__svgalib_inCR(0x1b); save->pllCtrl0=inl(banshee_io_base+0x40); save->pllCtrl1=inl(banshee_io_base+0x44); save->dacMode=inl(banshee_io_base+0x4c); save->dacAddr=inl(banshee_io_base+0x50); save->vidProcCfg=inl(banshee_io_base+0x5c); save->vidScreenSize=inl(banshee_io_base+0x98); save->vgaInit0=inl(banshee_io_base+0x28); save->vgaInit1=inl(banshee_io_base+0x2c); save->vidDesktopStartAddr=inl(banshee_io_base+0xe4); save->vidDesktopOverlayStride=inl(banshee_io_base+0xe8); return BANSHEE_TOTAL_REGS - VGA_TOTAL_REGS; } If we use the X source, it usually in the functions XXXSave and XXXRestore. It is only needed to translate from XFree86 notation to svgalib notation, and to remember that while the X functions need to save the vga state (usually by calling the vga function to do it, in svgalib the chipset_saveregs/setregs don't need to do that, but only save extended vga info). For MilleniumII, the interesting X functions are: MGA3026Save and MGA3026Restore, here a translation of a part of MGA3026Restore to mill_setregs: MGA3026Restore: for (i = 0; i < 6; i++) outw(0x3DE, (restore->ExtVga[i] << 8) | i); /* restore DAC regs */ for (i = 0; i < sizeof(MGADACregs); i++) outMGA1064(MGADACregs[i], restore->DACreg[i]); translates to (assuming sizeof(MGADACregs)==32) for (i = 0; i < 6; i++) outw(0x3DE, (restore[60+i] << 8) | i); /* restore DAC regs */ for (i = 0; i < 32; i++){ OUTREG8(RAMDAC_OFFSET + MGA1064_INDEX, MGADACregs[i]); OUTREG8(RAMDAC_OFFSET + MGA1064_DATA, restore[66+i]); }; _initializemode - This is the trickiest function. If you use the XFree86 source, try to translate the appropriate function from X to svgalib (in the milleniumII case, MGA1064Init(mode)). For examples of this translation, see how its done for nv3.c compared to nv/nv3driver.c from X, or apm.c compared to apm/apm_driver.c. If you are working from specs, it usually explained in the spec. _unlock: simple function. The skeleton includes the vga unlocking part. If you have specs, they usually explain how to unlock the extended features, if you use the X source, its usually in the EnterLeave function. _test - If you are supporting a single chipset of a single manufacturer, on a PCI/AGP, the skeleton driver includes a test for this, just make sure to set VENDOR_ID and CARD_ID properly. Otherwise, either the specs explain how to recognize that you have the right chipset, or its in the function XXXProbe of the XFree86 source. _setdisplaystart, _setlogicalwidth: vga includes this settings, but with limited range (start<65536, width<2048 bytes). An svga chipset either defines extra bits, for increasing the range, or completely new registers for these values. In the first case, the skeleton driver includes setting the vga part, and the extra bits are either defined in the specs, or in the XXXAdjust function in XFree86 (see mx.c for example of this). In the second case, remove the vga setting part from the functions (see for example rage.c). Note that none of the demo programs test this functions, so if you want to check if they work, the only example I know of is seejpeg (try to see an image larger than the screen) _init should not need much changes, except for checking memory size (in the spec, or in XXXProbe), and maybe setting MMIO (if other functions use it). 1- http://www.datashopper.dk/~finth 2- http://www.cs.bgu.ac.il/~zivav/svgalib 3- ftp://ftp.xfree86.org/pub/XFree86/current/binaries/Linux-ix86-libc5/Xlkit.tgz (or mirrors) 4- ftp://ftp.xfree86.org/pub/XFree86/current/source/X333servonly.tgz (or mirrors)