📄 tridentfb.c
字号:
return t_inb(0x3CF);}static inline void writeAttr(int reg, unsigned char val){ readb(fb_info.io_virt + CRT + 0x0A); //flip-flop to index t_outb(reg, 0x3C0); t_outb(val, 0x3C0);}static inline unsigned char readAttr(int reg){ readb(fb_info.io_virt + CRT + 0x0A); //flip-flop to index t_outb(reg, 0x3C0); return t_inb(0x3C1);}static inline void write3CE(int reg, unsigned char val){ t_outb(reg, 0x3CE); t_outb(val, 0x3CF);}#define unprotect_all() write3C4(Protection, 0x92);unprotect()#define unprotect() write3C4(NewMode1,0xC2)#define bios_reg(reg) write3CE(BiosReg, reg)#define enable_mmio() outb(PCIReg, 0x3D4); \ outb(inb(0x3D5) | 0x01, 0x3D5)#define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)/* Return flat panel's maximum x resolution */static int __init get_nativex(void){ int x,y,tmp; if (nativex) return nativex; tmp = (read3CE(VertStretch) >> 4) & 3; /* detection broken on XPAi ??? misdetects 1024 for 800 */ if (pci_id == CYBERBLADEXPAi1 && tmp == 3) tmp = 2; switch (tmp) { case 0:x = 1280;y = 1024;break; case 1:x = 640;y = 480;break; case 2:x = 1024;y = 768;break; default:x = 800;y = 600;break; } output("%dx%d flat panel found\n", x, y); return x;}/* Set pitch */static void set_lwidth(int width){ write3X4(Offset, width & 0xFF); write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4));}/* For resolutions smaller than FP resolution stretch */static void screen_stretch(void){ write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1); write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1);}/* For resolutions smaller than FP resolution center */static void screen_center(void){ bios_reg(0); // no stretch write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80); write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80);}/* Address of first shown pixel in display memory */static void set_screen_start(int base){ write3X4(StartAddrLow, base & 0xFF); write3X4(StartAddrHigh, (base & 0xFF00) >>8); write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >>11)); write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | (base & 0xE0000) >> 17);}#error "Floating point maths. This needs fixing before the driver is safe"#define calc_freq(n,m,k) ((NTSC * (n+8))/((m+2)*(1<<k)))/* Set dotclock frequency */static void set_vclk(int freq){ int m,n,k; int f,fi,d,di; unsigned char lo=0,hi=0; d = 20; for(k = 2;k>=0;k--) for(m = 0;m<63;m++) for(n = 0;n<128;n++) { fi = calc_freq(n,m,k); if ((di = abs(fi - freq)) < d) { d = di; f = fi; lo = n; hi = (k<<6) | m; } } write3C4(ClockHigh,hi); write3C4(ClockLow,lo); debug("VCLK = %X %X\n",hi,lo);}/* Set number of lines for flat panels*/static void set_number_of_lines(int lines){ int tmp = read3CE(CyberEnhance) & 0x8F; if (lines > 768) tmp |= 0x30; else if (lines > 600) tmp |= 0x20; else if (lines > 480) tmp |= 0x10; write3CE(CyberEnhance, tmp);}/* * If we see that FP is active we assume we have one. * Otherwise we have a CRT display.User can override. */static unsigned int __init get_displaytype(void){ if (fp) return DISPLAY_FP; if (crt) return DISPLAY_CRT; return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT;}/* Try detecting the video memory size */static unsigned int __init get_memsize(void){ unsigned char tmp; unsigned int k; /* If memory size provided by user */ if (memsize) k = memsize * Kb; else switch (pci_id) { case CYBER9525DVD:k = 2560 * Kb;break; case CYBERBLADEXPAi1:k = 16 * Mb;break; case CYBERBLADEXPm16:k = 16 * Mb;break; case CYBERBLADEXPm8:k = 8 * Mb;break; default: tmp = read3X4(SPR) & 0x0F; switch (tmp) { case 3:k = 1 * Mb;break; case 7:k = 2 * Mb;break; case 15:k = 4 * Mb;break; case 4:k = 8 * Mb;break; default:k = 1 * Mb; } } k -= memdiff * Kb; output("framebuffer size = %d Kb\n", k/Kb); return k;}/* Fill in fix */static int trident_encode_fix(struct fb_fix_screeninfo *fix, const void *par, struct fb_info_gen *info){ struct tridentfb_info * i = (struct tridentfb_info *)info; struct tridentfb_par * p = (struct tridentfb_par *)par; debug("enter\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id,tridentfb_name); fix->smem_start = i->fbmem; fix->smem_len = i->memsize; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->visual = p->bpp==8 ? FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR; fix->xpanstep = fix->ywrapstep = 0; fix->ypanstep = 1; fix->line_length = p->linelength; fix->mmio_start = 0; fix->mmio_len = 0; fix->accel = FB_ACCEL_NONE; debug("exit\n"); return 0;}/* Fill in par from var */static int trident_decode_var(const struct fb_var_screeninfo *var, void *par, struct fb_info_gen *info){ struct tridentfb_par * p = (struct tridentfb_par *)par; struct tridentfb_info * i = (struct tridentfb_info *)info; int vres,vfront,vback,vsync; debug("enter\n"); p->var = *var; p->bpp = var->bits_per_pixel; if (p->bpp == 24 ) p->bpp = 32; p->linelength = var->xres_virtual * p->bpp/8; switch (p->bpp) { case 8: p->var.red.offset = 0; p->var.green.offset = 0; p->var.blue.offset = 0; p->var.red.length = 6; p->var.green.length = 6; p->var.blue.length = 6; break; case 16: p->var.red.offset = 11; p->var.green.offset = 5; p->var.blue.offset = 0; p->var.red.length = 5; p->var.green.length = 6; p->var.blue.length = 5; break; case 32: p->var.red.offset = 16; p->var.green.offset = 8; p->var.blue.offset = 0; p->var.red.length = 8; p->var.green.length = 8; p->var.blue.length = 8; break; default: return -EINVAL; } /* convert from picoseconds to MHz */ p->vclk = 1000000/var->pixclock; if (p->bpp == 32) p->vclk *=2; p->hres = var->xres; vres = p->vres = var->yres; /* See if requested resolution is larger than flat panel */ if (p->hres > i->nativex && flatpanel) { return -EINVAL; } /* See if requested resolution fits in available memory */ if (p->hres * p->vres * p->bpp/8 > i->memsize) { return -EINVAL; } vfront = var->upper_margin; vback = var->lower_margin; vsync = var->vsync_len; /* Compute horizontal and vertical VGA CRTC timing values */ if (var->vmode & FB_VMODE_INTERLACED) { vres /= 2; vfront /=2; vback /=2; vsync /=2; } if (var->vmode & FB_VMODE_DOUBLE) { vres *= 2; vfront *=2; vback *=2; vsync *=2; } p->htotal = (p->hres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10; p->hdispend = p->hres/8 - 1; p->hsyncstart = (p->hres + var->right_margin)/8; p->hsyncend = var->hsync_len/8; p->hblankstart = p->hdispend + 1; p->hblankend = p->htotal + 5; p->vtotal = vres + vfront + vback + vsync - 2; p->vdispend = vres - 1; p->vsyncstart = vres + vback; p->vsyncend = vsync; p->vblankstart = vres; p->vblankend = p->vtotal + 2; debug("exit\n"); return 0;}/* Fill in var from info */static int trident_encode_var(struct fb_var_screeninfo *var, const void *par, struct fb_info_gen *info){ struct tridentfb_par * p = (struct tridentfb_par *)par; debug("enter\n"); *var = p->var; var->bits_per_pixel = p->bpp; debug("exit\n"); return 0;}/* Fill in par from hardware */static void trident_get_par(void *par, struct fb_info_gen *info){ struct tridentfb_par * p = (struct tridentfb_par *)par; struct tridentfb_info * i = (struct tridentfb_info *)info; debug("enter\n"); *p = i->currentmode; debug("exit\n");}/* Pan the display */static int trident_pan_display(const struct fb_var_screeninfo *var, struct fb_info_gen *info){ unsigned int offset; struct tridentfb_info * i = (struct tridentfb_info *)info; debug("enter\n"); offset = (var->xoffset + (var->yoffset * var->xres)) * var->bits_per_pixel/32; i->currentmode.var.xoffset = var->xoffset; i->currentmode.var.yoffset = var->yoffset; set_screen_start(offset); debug("exit\n"); return 0;}/* Set the hardware from par */static void trident_set_par(const void *par, struct fb_info_gen *info){ struct tridentfb_par * p = (struct tridentfb_par *)par; struct tridentfb_info * i = (struct tridentfb_info *)info; unsigned char tmp; debug("enter\n"); i->currentmode = *p; unprotect_all(); crtc_unlock(); enable_mmio(); write3CE(CyberControl,8); if (flatpanel && p->hres < i->nativex) { /* * on flat panels with native size larger * than requested resolution decide whether * we stretch or center */ t_outb(0xEB,0x3C2); write3CE(CyberControl,0x81); if (center) //|| (p->bpp==32 && pci_id == CYBERBLADEi1D)) screen_center(); else if (stretch) screen_stretch(); } else { t_outb(0x2B,0x3C2); write3CE(CyberControl,8); } /* vertical timing values */ write3X4(CRTVTotal, p->vtotal & 0xFF); write3X4(CRTVDispEnd, p->vdispend & 0xFF); write3X4(CRTVSyncStart, p->vsyncstart & 0xFF); write3X4(CRTVSyncEnd, (p->vsyncend & 0x0F)); write3X4(CRTVBlankStart, p->vblankstart & 0xFF); write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/); /* horizontal timing values */ write3X4(CRTHTotal, p->htotal & 0xFF); write3X4(CRTHDispEnd, p->hdispend & 0xFF); write3X4(CRTHSyncStart, p->hsyncstart & 0xFF); write3X4(CRTHSyncEnd, (p->hsyncend & 0x1F) | ((p->hblankend & 0x20)<<2)); write3X4(CRTHBlankStart, p->hblankstart & 0xFF); write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/); /* higher bits of vertical timing values */ tmp = 0x10; if (p->vtotal & 0x100) tmp |= 0x01; if (p->vdispend & 0x100) tmp |= 0x02; if (p->vsyncstart & 0x100) tmp |= 0x04; if (p->vblankstart & 0x100) tmp |= 0x08; if (p->vtotal & 0x200) tmp |= 0x20; if (p->vdispend & 0x200) tmp |= 0x40; if (p->vsyncstart & 0x200) tmp |= 0x80; write3X4(CRTOverflow, tmp); tmp = read3X4(CRTHiOrd) | 0x08; //line compare bit 10 if (p->vtotal & 0x400) tmp |= 0x80; if (p->vblankstart & 0x400) tmp |= 0x40; if (p->vsyncstart & 0x400) tmp |= 0x20; if (p->vdispend & 0x400) tmp |= 0x10; write3X4(CRTHiOrd, tmp); write3X4(HorizOverflow, 0); tmp = 0x40; if (p->vblankstart & 0x200) tmp |= 0x20; if (p->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; //double scan for 200 line modes write3X4(CRTMaxScanLine, tmp); write3X4(CRTLineCompare,0xFF); write3X4(CRTPRowScan,0); write3X4(CRTModeControl,0xC3); write3X4(LinearAddReg,0x20); //enable linear addressing tmp = (p->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80; write3X4(CRTCModuleTest,tmp); //enable access extended memory write3X4(GraphEngReg, 0x80); //enable GE for text acceleration if (p->var.accel_flags & FB_ACCELF_TEXT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -