📄 matroxfb_base.c
字号:
if (!bppshft2) { return 8; } if (isInterleave(MINFO)) bppshft2 >>= 1; if (ACCESS_FBINFO(devflags.video64bits)) bppshft2 >>= 1; return bppshft2;}static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) { int over; int rounding; DBG(__FUNCTION__) switch (bpp) { case 0: return xres; case 4: rounding = 128; break; case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */ break; case 16: rounding = 32; break; case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */ break; default: rounding = 16; /* on G400, 16 really does not work */ if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) rounding = 32; break; } if (isInterleave(MINFO)) { rounding *= 2; } over = xres % rounding; if (over) xres += rounding-over; return xres;}static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { const int* width; int xres_new; DBG(__FUNCTION__) if (!bpp) return xres; width = ACCESS_FBINFO(capable.vxres); if (ACCESS_FBINFO(devflags.precise_width)) { while (*width) { if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) { break; } width++; } xres_new = *width; } else { xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp); } return xres_new;}static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { DBG(__FUNCTION__) switch (var->bits_per_pixel) { case 4: return 16; /* pseudocolor... 16 entries HW palette */ case 8: return 256; /* pseudocolor... 256 entries HW palette */ case 16: return 16; /* directcolor... 16 entries SW palette */ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ case 24: return 16; /* directcolor... 16 entries SW palette */ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ case 32: return 16; /* directcolor... 16 entries SW palette */ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ } return 16; /* return something reasonable... or panic()? */}static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) { struct RGBT { unsigned char bpp; struct { unsigned char offset, length; } red, green, blue, transp; signed char visual; }; static const struct RGBT table[]= { { 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR}, {15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR}, {16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR}, {24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR}, {32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR} }; struct RGBT const *rgbt; unsigned int bpp = var->bits_per_pixel; unsigned int vramlen; unsigned int memlen; DBG(__FUNCTION__) switch (bpp) { case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL; break; case 8: break; case 16: break; case 24: break; case 32: break; default: return -EINVAL; } *ydstorg = 0; vramlen = ACCESS_FBINFO(video.len_usable); if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp); memlen = var->xres_virtual * bpp * var->yres_virtual / 8; if (memlen > vramlen) { var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp); memlen = var->xres_virtual * bpp * var->yres_virtual / 8; } /* There is hardware bug that no line can cross 4MB boundary */ /* give up for CFB24, it is impossible to easy workaround it */ /* for other try to do something */ if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) { if (bpp == 24) { /* sorry */ } else { unsigned int linelen; unsigned int m1 = linelen = var->xres_virtual * bpp / 8; unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */ unsigned int max_yres; while (m1) { int t; while (m2 >= m1) m2 -= m1; t = m1; m1 = m2; m2 = t; } m2 = linelen * PAGE_SIZE / m2; *ydstorg = m2 = 0x400000 % m2; max_yres = (vramlen - m2) / linelen; if (var->yres_virtual > max_yres) var->yres_virtual = max_yres; } } /* YDSTLEN contains only signed 16bit value */ if (var->yres_virtual > 32767) var->yres_virtual = 32767; /* we must round yres/xres down, we already rounded y/xres_virtual up if it was possible. We should return -EINVAL, but I disagree */ if (var->yres_virtual < var->yres) var->yres = var->yres_virtual; if (var->xres_virtual < var->xres) var->xres = var->xres_virtual; if (var->xoffset + var->xres > var->xres_virtual) var->xoffset = var->xres_virtual - var->xres; if (var->yoffset + var->yres > var->yres_virtual) var->yoffset = var->yres_virtual - var->yres; if (bpp == 16 && var->green.length == 5) { bpp--; /* an artifical value - 15 */ } for (rgbt = table; rgbt->bpp < bpp; rgbt++);#define SETCLR(clr)\ var->clr.offset = rgbt->clr.offset;\ var->clr.length = rgbt->clr.length SETCLR(red); SETCLR(green); SETCLR(blue); SETCLR(transp);#undef SETCLR *visual = rgbt->visual; if (bpp > 8) dprintk("matroxfb: truecolor: " "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", var->transp.length, var->red.length, var->green.length, var->blue.length, var->transp.offset, var->red.offset, var->green.offset, var->blue.offset); *video_cmap_len = matroxfb_get_cmap_len(var); dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel, var->xres_virtual, var->yres_virtual); return 0;}static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fb_info){#ifdef CONFIG_FB_MATROX_MULTIHEAD struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon);#endif DBG(__FUNCTION__) /* * Set a single color register. The values supplied are * already rounded down to the hardware's capabilities * (according to the entries in the `var' structure). Return * != 0 for invalid regno. */ if (regno >= ACCESS_FBINFO(curr.cmap_len)) return 1; if (ACCESS_FBINFO(fbcon).var.grayscale) { /* gray = 0.30*R + 0.59*G + 0.11*B */ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; } red = CNVT_TOHW(red, ACCESS_FBINFO(fbcon).var.red.length); green = CNVT_TOHW(green, ACCESS_FBINFO(fbcon).var.green.length); blue = CNVT_TOHW(blue, ACCESS_FBINFO(fbcon).var.blue.length); transp = CNVT_TOHW(transp, ACCESS_FBINFO(fbcon).var.transp.length); switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { case 4: case 8: mga_outb(M_DAC_REG, regno); mga_outb(M_DAC_VAL, red); mga_outb(M_DAC_VAL, green); mga_outb(M_DAC_VAL, blue); break; case 16: { u_int16_t col = (red << ACCESS_FBINFO(fbcon).var.red.offset) | (green << ACCESS_FBINFO(fbcon).var.green.offset) | (blue << ACCESS_FBINFO(fbcon).var.blue.offset) | (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* for 1:5:5:5 */ ACCESS_FBINFO(cmap[regno]) = col | (col << 16); } break; case 24: case 32: ACCESS_FBINFO(cmap[regno]) = (red << ACCESS_FBINFO(fbcon).var.red.offset) | (green << ACCESS_FBINFO(fbcon).var.green.offset) | (blue << ACCESS_FBINFO(fbcon).var.blue.offset) | (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* 8:8:8:8 */ break; } return 0;}static void matroxfb_init_fix(WPMINFO2){ struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; DBG(__FUNCTION__) strcpy(fix->id,"MATROX"); fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */ fix->ypanstep = 1; fix->ywrapstep = 0; fix->mmio_start = ACCESS_FBINFO(mmio.base); fix->mmio_len = ACCESS_FBINFO(mmio.len); fix->accel = ACCESS_FBINFO(devflags.accelerator);}static void matroxfb_update_fix(WPMINFO2){ struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; DBG(__FUNCTION__) fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);}static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ int err; int visual; int cmap_len; unsigned int ydstorg; MINFO_FROM_INFO(info); if (ACCESS_FBINFO(dead)) { return -ENXIO; } if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0) return err; return 0;}static int matroxfb_set_par(struct fb_info *info){ int err; int visual; int cmap_len; unsigned int ydstorg; struct fb_var_screeninfo *var; MINFO_FROM_INFO(info); DBG(__FUNCTION__) if (ACCESS_FBINFO(dead)) { return -ENXIO; } var = &info->var; if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0) return err; ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg; matroxfb_update_fix(PMINFO2); ACCESS_FBINFO(fbcon).fix.visual = visual; ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_PACKED_PIXELS; ACCESS_FBINFO(fbcon).fix.type_aux = 0; ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; { unsigned int pos; ACCESS_FBINFO(curr.cmap_len) = cmap_len; ydstorg += ACCESS_FBINFO(devflags.ydstorg); ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg; ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2); if (var->bits_per_pixel == 4) ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg; else ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel; ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel); { struct my_timming mt; struct matrox_hw_state* hw; int out; matroxfb_var2my(var, &mt); mt.crtc = MATROXFB_SRC_CRTC1; /* CRTC1 delays */ switch (var->bits_per_pixel) { case 0: mt.delay = 31 + 0; break; case 16: mt.delay = 21 + 8; break; case 24: mt.delay = 17 + 8; break; case 32: mt.delay = 16 + 8; break; default: mt.delay = 31 + 8; break; } hw = &ACCESS_FBINFO(hw); down_read(&ACCESS_FBINFO(altout).lock); for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 && ACCESS_FBINFO(outputs[out]).output->compute) { ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt); } } up_read(&ACCESS_FBINFO(altout).lock); ACCESS_FBINFO(crtc1).pixclock = mt.pixclock; ACCESS_FBINFO(crtc1).mnp = mt.mnp; ACCESS_FBINFO(hw_switch->init(PMINFO &mt)); pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; pos += ACCESS_FBINFO(curr.ydstorg.chunks); hw->CRTC[0x0D] = pos & 0xFF; hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); hw->CRTCEXT[8] = pos >> 21; ACCESS_FBINFO(hw_switch->restore(PMINFO2)); update_crtc2(PMINFO pos); down_read(&ACCESS_FBINFO(altout).lock); for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 && ACCESS_FBINFO(outputs[out]).output->program) { ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data); } } for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 && ACCESS_FBINFO(outputs[out]).output->start) { ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data); } } up_read(&ACCESS_FBINFO(altout).lock); matrox_cfbX_init(PMINFO2); } } ACCESS_FBINFO(initialized) = 1; return 0;}static int matroxfb_get_vblank(WPMINFO struct fb_vblank *vblank){ unsigned int sts1; matroxfb_enable_irq(PMINFO 0); memset(vblank, 0, sizeof(*vblank)); vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC | FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK; sts1 = mga_inb(M_INSTS1); vblank->vcount = mga_inl(M_VCOUNT); /* BTW, on my PIII/450 with G400, reading M_INSTS1 byte makes this call about 12% slower (1.70 vs. 2.05 us per ioctl()) */ if (sts1 & 1) vblank->flags |= FB_VBLANK_HBLANKING; if (sts1 & 8) vblank->flags |= FB_VBLANK_VSYNCING; if (vblank->vcount >= ACCESS_FBINFO(fbcon).var.yres) vblank->flags |= FB_VBLANK_VBLANKING; if (test_bit(0, &ACCESS_FBINFO(irq_flags))) { vblank->flags |= FB_VBLANK_HAVE_COUNT; /* Only one writer, aligned int value... it should work without lock and without atomic_t */ vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt; } return 0;}static struct matrox_altout panellink_output = { .name = "Panellink output",};static int matroxfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, struct fb_info *info){ void __user *argp = (void __user *)arg; MINFO_FROM_INFO(info); DBG(__FUNCTION__)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -