📄 banshee.c
字号:
/*3dfx Voodoo Banshee driver */#include <stdlib.h>#include <stdio.h> /* for printf */#include <string.h> /* for memset */#include <unistd.h>#include "vga.h"#include "libvga.h"#include "driver.h"/* New style driver interface. */#include "timing.h"#include "vgaregs.h"#include "interface.h"#include "accel.h"#include "vgapci.h"#define BANSHEEREG_SAVE(i) (VGA_TOTAL_REGS+i)#define BANSHEE_TOTAL_REGS (VGA_TOTAL_REGS + 2 + 40)static int banshee_init(int, int, int);static void banshee_unlock(void);static void banshee_lock(void);void __svgalib_bansheeaccel_init(AccelSpecs * accelspecs, int bpp, int width_in_pixels);static int banshee_memory,banshee_chiptype;static int banshee_is_linear, banshee_linear_base, banshee_io_base;static CardSpecs *cardspecs;static void banshee_setpage(int page){ page<<=1; outl(banshee_io_base+0x2c,(inl(banshee_io_base+0x2c)&0xfff00000)|(page)|(page<<10));}static int __svgalib_banshee_inlinearmode(void){return banshee_is_linear;}/* Fill in chipset specific mode information */static void banshee_getmodeinfo(int mode, vga_modeinfo *modeinfo){ if(modeinfo->colors==16)return; modeinfo->maxpixels = banshee_memory*1024/modeinfo->bytesperpixel; modeinfo->maxlogicalwidth = 4088; modeinfo->startaddressrange = banshee_memory * 1024 - 1; modeinfo->haveblit = 0; modeinfo->flags &= ~HAVE_RWPAGE; if (modeinfo->bytesperpixel >= 1) { if(banshee_linear_base)modeinfo->flags |= CAPABLE_LINEAR; if (__svgalib_banshee_inlinearmode()) modeinfo->flags |= IS_LINEAR; }}/* Read and save chipset-specific registers */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(); /* May be locked again by other programs (e.g. X) */ 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;}/* Set chipset-specific registers */static void banshee_setregs(const unsigned char regs[], int mode){ HWRecPtr restore; banshee_unlock(); /* May be locked again by other programs (eg. X) */ restore=(HWRecPtr)(regs+62); __svgalib_outCR(0x1a,regs[BANSHEEREG_SAVE(0)]); __svgalib_outCR(0x1b,regs[BANSHEEREG_SAVE(1)]); outl(banshee_io_base+0x40,restore->pllCtrl0); outl(banshee_io_base+0x44,restore->pllCtrl1); outl(banshee_io_base+0x4c,restore->dacMode); outl(banshee_io_base+0x50,restore->dacAddr); outl(banshee_io_base+0x5c,restore->vidProcCfg); outl(banshee_io_base+0x98,restore->vidScreenSize); outl(banshee_io_base+0x28,restore->vgaInit0); outl(banshee_io_base+0x2c,restore->vgaInit1); outl(banshee_io_base+0xe4,restore->vidDesktopStartAddr); outl(banshee_io_base+0xe8,restore->vidDesktopOverlayStride); outl(banshee_io_base+0x5c,restore->vidProcCfg&0xfffffffe); outl(banshee_io_base+0x5c,restore->vidProcCfg|1); outl(banshee_io_base+0x5c,restore->vidProcCfg);}/* Return nonzero if mode is available */static int banshee_modeavailable(int mode){ struct info *info; ModeTiming *modetiming; ModeInfo *modeinfo; if ((mode < G640x480x256 ) || mode == G720x348x2) return __svgalib_vga_driverspecs.modeavailable(mode); info = &__svgalib_infotable[mode]; if (banshee_memory * 1024 < info->ydim * info->xbytes) return 0; modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode); if((modeinfo->bitsPerPixel==16)&&(modeinfo->greenWeight==5)) { free(modeinfo); return 0; } modetiming = malloc(sizeof(ModeTiming)); if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) { free(modetiming); return 0; } free(modetiming); free(modeinfo); return SVGADRV;}static unsigned comp_lmn(int freq) ;/* Set a mode *//* Local, called by banshee_setmode(). */static void banshee_initializemode(unsigned char *moderegs, ModeTiming * modetiming, ModeInfo * modeinfo, int mode){ /* long k; */ int vd,vt,vbs,vbe,ht,hd,hss,hse; HWRecPtr banshee_regs; banshee_regs=(HWRecPtr)(moderegs+62); banshee_saveregs(moderegs); __svgalib_setup_VGA_registers(moderegs, modetiming, modeinfo); hd = (modetiming->CrtcHDisplay>>3)-1; hss = (modetiming->CrtcHSyncStart>>3); hse = (modetiming->CrtcHSyncEnd>>3); ht = (modetiming->CrtcHTotal>>3)-5; moderegs[BANSHEEREG_SAVE(0)]=((ht&0x100)>>8) | ((hd&0x100)>>6) | ((hd&0x100)>>4) | ((ht&0x40)>>1) | ((hss&0x100)>>2) | ((hse&0x20)<<2) ; vd = modetiming->CrtcVDisplay - 1; vt = modetiming->CrtcVTotal - 2; vbs = modetiming->CrtcVSyncStart - 1; vbe = vt; moderegs[BANSHEEREG_SAVE(1)]=((vt & 0x400)>>10) | ((vd & 0x400)>>8) | ((vbs & 0x400)>>6) | ((vbe & 0x400)>>4);/* if (modetiming->flags & INTERLACED) moderegs[MXREG_SAVE(3)] |= 0x8;*/ banshee_regs->vidProcCfg&=0xf7e30000; banshee_regs->vidProcCfg|=0x00000c81; banshee_regs->vidScreenSize=modeinfo->width|(modeinfo->height<<12); if (modetiming->flags & DOUBLESCAN) banshee_regs->vidProcCfg |= 0x10; switch (modeinfo->bitsPerPixel) { case 8: banshee_regs->vidProcCfg|=0<<18; break; case 15: case 16:if(modeinfo->greenWeight==5){ banshee_regs->vidProcCfg|=1<<18; } else banshee_regs->vidProcCfg|=1<<18; break; case 24: banshee_regs->vidProcCfg|=2<<18; break; case 32: banshee_regs->vidProcCfg|=3<<18; break; default: break; } banshee_regs->vgaInit0&=0xfffffffb; if(modeinfo->bitsPerPixel!=8){ banshee_regs->vgaInit0|=4; }; banshee_regs->pllCtrl0=comp_lmn(modetiming->pixelClock); moderegs[VGA_MISCOUTPUT]|=0x0c; banshee_regs->vidDesktopStartAddr=0; banshee_regs->vidDesktopOverlayStride=modeinfo->lineWidth; banshee_regs->vgaInit0=0x1140; banshee_regs->vgaInit1=0x00100000; moderegs[41]=0; if(modeinfo->bitsPerPixel==8){ moderegs[79]=0; }; banshee_is_linear=0;return ;}static int banshee_setmode(int mode, int prv_mode){ unsigned char *moderegs; ModeTiming modetiming; ModeInfo *modeinfo; if ((mode < G640x480x256 /*&& mode != G320x200x256*/) || mode == G720x348x2) { return __svgalib_vga_driverspecs.setmode(mode, prv_mode); } if (!banshee_modeavailable(mode)) return 1; modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode); if (__svgalib_getmodetiming(&modetiming, modeinfo, cardspecs)) { free(modeinfo); return 1; } moderegs = malloc(BANSHEE_TOTAL_REGS); banshee_initializemode(moderegs, &modetiming, modeinfo, mode); __svgalib_setregs(moderegs); /* Set standard regs. */ banshee_setregs(moderegs, mode); /* Set extended regs. */ free(moderegs); __svgalib_InitializeAcceleratorInterface(modeinfo); free(modeinfo); return 0;}/* Unlock chipset-specific registers */static void banshee_unlock(void){ int vgaIOBase, temp; vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0; outb(vgaIOBase + 4, 0x11); temp = inb(vgaIOBase + 5); outb(vgaIOBase + 5, temp & 0x7F); outl(banshee_io_base+0x28,(inl(banshee_io_base+0x28)&0xffffffbf)|(1<<6));}static void banshee_lock(void){ int vgaIOBase, temp; vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0; outb(vgaIOBase + 4, 0x11); temp = inb(vgaIOBase + 5); outb(vgaIOBase + 5, temp & 0x7F); outl(banshee_io_base+0x28,(inl(banshee_io_base+0x28)&0xffffffbf));}/* Indentify chipset, initialize and return non-zero if detected */static int banshee_test(void){ int found,_ioperm=0; unsigned long buf[64]; if (getenv("IOPERM") == NULL) { _ioperm=1; if (iopl(3) < 0) { printf("svgalib: banshee: cannot get I/O permissions\n"); exit(1); } } found=(!__svgalib_pci_find_vendor_vga(0x121a,buf,0))&& (((buf[0]>>16)==0x0003)|| ((buf[0]>>16)==0x0009)|| ((buf[0]>>16)==0x0005)); if (_ioperm) iopl(0); if(found)banshee_init(0,0,0); return found;}/* Set display start address (not for 16 color modes) *//* Cirrus supports any address in video memory (up to 2Mb) */static void banshee_setdisplaystart(int address){ outw(CRT_IC, ((address>>2) & 0x00FF00) | 0x0C); outw(CRT_IC, (((address>>2) & 0x00FF) << 8) | 0x0D); outl(banshee_io_base+0xe4,address);}/* Set logical scanline length (usually multiple of 8) */static void banshee_setlogicalwidth(int width){ int offset = width >> 3; __svgalib_outCR(0x13,offset&0xff); outl(banshee_io_base+0xe8,width);}static int banshee_linear(int op, int param){if (op==LINEAR_ENABLE || op==LINEAR_DISABLE){ banshee_is_linear=1-banshee_is_linear; return 0;}if (op==LINEAR_QUERY_BASE) return banshee_linear_base;if (op == LINEAR_QUERY_RANGE || op == LINEAR_QUERY_GRANULARITY) return 0; /* No granularity or range. */ else return -1; /* Unknown function. */}static int banshee_match_programmable_clock(int clock){return clock ;}static int banshee_map_clock(int bpp, int clock){return clock ;}static int banshee_map_horizontal_crtc(int bpp, int pixelclock, int htiming){return htiming;}/* Function table (exported) */DriverSpecs __svgalib_banshee_driverspecs ={ banshee_saveregs, banshee_setregs, banshee_unlock, banshee_lock, banshee_test, banshee_init, banshee_setpage, NULL, NULL, banshee_setmode, banshee_modeavailable, banshee_setdisplaystart, banshee_setlogicalwidth, banshee_getmodeinfo, 0, /* old blit funcs */ 0, 0, 0, 0, 0, /* ext_set */ 0, /* accel */ banshee_linear, 0, /* accelspecs, filled in during init. */ NULL, /* Emulation */};/* Initialize chipset (called after detection) */static int banshee_init(int force, int par1, int par2){ unsigned long buf[64]; int found=0; int _ioperm=0; if (force) { banshee_memory = par1; banshee_chiptype = par2; } else { }; if (getenv("IOPERM") == NULL) { _ioperm=1; if (iopl(3) < 0) { printf("svgalib: banshee: cannot get I/O permissions\n"); exit(1); } } found=(!__svgalib_pci_find_vendor_vga(0x121a,buf,0))&& (((buf[0]>>16)==0x0003)|| ((buf[0]>>16)==0x0009)|| ((buf[0]>>16)==0x0005)); /* if (_ioperm) iopl(0);*/ if (found){ banshee_linear_base=buf[5]&0xffffff00; banshee_io_base=buf[6]&0xff00; }; if(banshee_memory==0) { unsigned int draminit0,draminit1; draminit0=inl(banshee_io_base+0x18); draminit1=inl(banshee_io_base+0x1c); if(draminit1&0x40000000) { /* SDRAM */ banshee_memory=16*1024; } else { /* SGRAM */ banshee_memory=1024*4* (1+((draminit0>>27)&1))* /* SGRAM type - 8MBIT or 16MBIT */ (1+((draminit0>>26)&1)); /* Number of sgram chips (4 or 8) */ } } banshee_unlock(); if (__svgalib_driver_report) { printf("Using Banshee / Voodoo3 driver, %iKB.\n",banshee_memory); } cardspecs = malloc(sizeof(CardSpecs)); cardspecs->videoMemory = banshee_memory; cardspecs->maxPixelClock4bpp = 270000; cardspecs->maxPixelClock8bpp = 270000; cardspecs->maxPixelClock16bpp = 270000; cardspecs->maxPixelClock24bpp = 270000; cardspecs->maxPixelClock32bpp = 270000; cardspecs->flags = INTERLACE_DIVIDE_VERT | CLOCK_PROGRAMMABLE; cardspecs->maxHorizontalCrtc = 4088; cardspecs->maxPixelClock4bpp = 0; cardspecs->nClocks =0; cardspecs->mapClock = banshee_map_clock; cardspecs->mapHorizontalCrtc = banshee_map_horizontal_crtc; cardspecs->matchProgrammableClock=banshee_match_programmable_clock; __svgalib_driverspecs = &__svgalib_banshee_driverspecs; __svgalib_banked_mem_base=0xa0000; __svgalib_banked_mem_size=0x10000; __svgalib_linear_mem_base=banshee_linear_base; __svgalib_linear_mem_size=banshee_memory*0x400; return 0;}#define REFFREQ 14318.18static unsignedcomp_lmn(int freq){ int m, n, k, best_m, best_n, best_k, f_cur, best_error; best_error=freq; best_n=best_m=best_k=0; for (n=1; n<256; n++) { f_cur=REFFREQ*(n+2); if (f_cur<freq) { f_cur=f_cur/3; if (freq-f_cur<best_error) { best_error=freq-f_cur; best_n=n; best_m=1; best_k=0; continue; } } for (m=1; m<64; m++) { for (k=0; k<4; k++) { f_cur=REFFREQ*(n+2)/(m+2)/(1<<k); if (abs(f_cur-freq)<best_error) { best_error=abs(f_cur-freq); best_n=n; best_m=m; best_k=k; } } } } return (best_n << 8) | (best_m<<2) | best_k;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -