tridentfb.c
来自「linux 内核源代码」· C语言 代码 · 共 1,427 行 · 第 1/3 页
C
1,427 行
/* * Accel functions called by the upper layers */#ifdef CONFIG_FB_TRIDENT_ACCELstatic void tridentfb_fillrect(struct fb_info *info, const struct fb_fillrect *fr){ int bpp = info->var.bits_per_pixel; int col = 0; switch (bpp) { default: case 8: col |= fr->color; col |= col << 8; col |= col << 16; break; case 16: col = ((u32 *)(info->pseudo_palette))[fr->color]; break; case 32: col = ((u32 *)(info->pseudo_palette))[fr->color]; break; } acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop); acc->wait_engine();}static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca){ acc->copy_rect(ca->sx, ca->sy, ca->dx, ca->dy, ca->width, ca->height); acc->wait_engine();}#else /* !CONFIG_FB_TRIDENT_ACCEL */#define tridentfb_fillrect cfb_fillrect#define tridentfb_copyarea cfb_copyarea#endif /* CONFIG_FB_TRIDENT_ACCEL *//* * Hardware access functions */static inline unsigned char read3X4(int reg){ struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par; writeb(reg, par->io_virt + CRT + 4); return readb(par->io_virt + CRT + 5);}static inline void write3X4(int reg, unsigned char val){ struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par; writeb(reg, par->io_virt + CRT + 4); writeb(val, par->io_virt + CRT + 5);}static inline unsigned char read3C4(int reg){ t_outb(reg, 0x3C4); return t_inb(0x3C5);}static inline void write3C4(int reg, unsigned char val){ t_outb(reg, 0x3C4); t_outb(val, 0x3C5);}static inline unsigned char read3CE(int reg){ t_outb(reg, 0x3CE); return t_inb(0x3CF);}static inline void writeAttr(int reg, unsigned char val){ readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); /* flip-flop to index */ t_outb(reg, 0x3C0); t_outb(val, 0x3C0);}static inline void write3CE(int reg, unsigned char val){ t_outb(reg, 0x3CE); t_outb(val, 0x3CF);}static inline void enable_mmio(void){ /* Goto New Mode */ outb(0x0B, 0x3C4); inb(0x3C5); /* Unprotect registers */ outb(NewMode1, 0x3C4); outb(0x80, 0x3C5); /* 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 __devinit get_nativex(void){ int x, y, tmp; if (nativex) return nativex; tmp = (read3CE(VertStretch) >> 4) & 3; switch (tmp) { case 0: x = 1280; y = 1024; break; case 2: x = 1024; y = 768; break; case 3: x = 800; y = 600; break; case 4: x = 1400; y = 1050; break; case 1: default: x = 640; y = 480; 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){ if (chip_id != CYBERBLADEXPAi1) write3CE(BiosReg, 0); else write3CE(BiosReg, 8); write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1); write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1);}/* For resolutions smaller than FP resolution center */static void screen_center(void){ 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));}/* Use 20.12 fixed-point for NTSC value and frequency calculation */#define calc_freq(n, m, k) ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 )/* 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; } } if (chip3D) { write3C4(ClockHigh, hi); write3C4(ClockLow, lo); } else { outb(lo, 0x43C8); outb(hi, 0x43C9); } 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 > 1024) tmp |= 0x50; else 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 __devinit get_displaytype(void){ if (fp) return DISPLAY_FP; if (crt || !chipcyber) return DISPLAY_CRT; return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;}/* Try detecting the video memory size */static unsigned int __devinit get_memsize(void){ unsigned char tmp, tmp2; unsigned int k; /* If memory size provided by user */ if (memsize) k = memsize * Kb; else switch (chip_id) { case CYBER9525DVD: k = 2560 * Kb; break; default: tmp = read3X4(SPR) & 0x0F; switch (tmp) { case 0x01: k = 512; break; case 0x02: k = 6 * Mb; /* XP */ break; case 0x03: k = 1 * Mb; break; case 0x04: k = 8 * Mb; break; case 0x06: k = 10 * Mb; /* XP */ break; case 0x07: k = 2 * Mb; break; case 0x08: k = 12 * Mb; /* XP */ break; case 0x0A: k = 14 * Mb; /* XP */ break; case 0x0C: k = 16 * Mb; /* XP */ break; case 0x0E: /* XP */ tmp2 = read3C4(0xC1); switch (tmp2) { case 0x00: k = 20 * Mb; break; case 0x01: k = 24 * Mb; break; case 0x10: k = 28 * Mb; break; case 0x11: k = 32 * Mb; break; default: k = 1 * Mb; break; } break; case 0x0F: k = 4 * Mb; break; default: k = 1 * Mb; break; } } k -= memdiff * Kb; output("framebuffer size = %d Kb\n", k / Kb); return k;}/* See if we can handle the video mode described in var */static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ int bpp = var->bits_per_pixel; debug("enter\n"); /* check color depth */ if (bpp == 24) bpp = var->bits_per_pixel = 32; /* check whether resolution fits on panel and in memory */ if (flatpanel && nativex && var->xres > nativex) return -EINVAL; if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len) return -EINVAL; switch (bpp) { case 8: var->red.offset = 0; var->green.offset = 0; var->blue.offset = 0; var->red.length = 6; var->green.length = 6; var->blue.length = 6; break; case 16: var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; var->red.length = 5; var->green.length = 6; var->blue.length = 5; break; case 32: var->red.offset = 16; var->green.offset = 8; var->blue.offset = 0; var->red.length = 8; var->green.length = 8; var->blue.length = 8; break; default: return -EINVAL; } debug("exit\n"); return 0;}/* Pan the display */static int tridentfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){ unsigned int offset; debug("enter\n"); offset = (var->xoffset + (var->yoffset * var->xres)) * var->bits_per_pixel / 32; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; set_screen_start(offset); debug("exit\n"); return 0;}#define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81)#define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E)/* Set the hardware to the requested video mode */static int tridentfb_set_par(struct fb_info *info){ struct tridentfb_par *par = (struct tridentfb_par *)(info->par); u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend; u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend; struct fb_var_screeninfo *var = &info->var; int bpp = var->bits_per_pixel; unsigned char tmp; debug("enter\n"); hdispend = var->xres / 8 - 1; hsyncstart = (var->xres + var->right_margin) / 8; hsyncend = var->hsync_len / 8; htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len) / 8 - 10; hblankstart = hdispend + 1; hblankend = htotal + 5; vdispend = var->yres - 1; vsyncstart = var->yres + var->lower_margin; vsyncend = var->vsync_len; vtotal = var->upper_margin + vsyncstart + vsyncend - 2; vblankstart = var->yres; vblankend = vtotal + 2; enable_mmio(); crtc_unlock(); write3CE(CyberControl, 8); if (flatpanel && var->xres < nativex) { /* * on flat panels with native size larger * than requested resolution decide whether * we stretch or center */ t_outb(0xEB, 0x3C2); shadowmode_on(); if (center) screen_center(); else if (stretch) screen_stretch(); } else { t_outb(0x2B, 0x3C2); write3CE(CyberControl, 8); } /* vertical timing values */ write3X4(CRTVTotal, vtotal & 0xFF); write3X4(CRTVDispEnd, vdispend & 0xFF); write3X4(CRTVSyncStart, vsyncstart & 0xFF); write3X4(CRTVSyncEnd, (vsyncend & 0x0F)); write3X4(CRTVBlankStart, vblankstart & 0xFF); write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ ); /* horizontal timing values */ write3X4(CRTHTotal, htotal & 0xFF); write3X4(CRTHDispEnd, hdispend & 0xFF); write3X4(CRTHSyncStart, hsyncstart & 0xFF); write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); write3X4(CRTHBlankStart, hblankstart & 0xFF); write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ ); /* higher bits of vertical timing values */ tmp = 0x10; if (vtotal & 0x100) tmp |= 0x01; if (vdispend & 0x100) tmp |= 0x02; if (vsyncstart & 0x100) tmp |= 0x04; if (vblankstart & 0x100) tmp |= 0x08; if (vtotal & 0x200) tmp |= 0x20; if (vdispend & 0x200) tmp |= 0x40; if (vsyncstart & 0x200) tmp |= 0x80; write3X4(CRTOverflow, tmp); tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */ if (vtotal & 0x400) tmp |= 0x80; if (vblankstart & 0x400) tmp |= 0x40; if (vsyncstart & 0x400) tmp |= 0x20; if (vdispend & 0x400) tmp |= 0x10; write3X4(CRTHiOrd, tmp); tmp = 0; if (htotal & 0x800) tmp |= 0x800 >> 11; if (hblankstart & 0x800) tmp |= 0x800 >> 7; write3X4(HorizOverflow, tmp);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?