📄 cyblafb.c
字号:
// enforce (h|v)sync_len limits // var->hsync_len &= ~7; if(var->hsync_len > 248) var->hsync_len = 248; var->vsync_len &= 15; // // Enforce horizontal and vertical hardware limits. // 1600x1200 is mentioned as a maximum, but higher resolutions could // work with slow refresh, small margins and short sync. // var->xres &= ~7; if (((var->xres + var->left_margin + var->right_margin + var->hsync_len) > (bpp == 32 ? 2040 : 4088)) || ((var->yres + var->upper_margin + var->lower_margin + var->vsync_len) > 2047)) return -EINVAL; if ((var->xres > 1600) || (var->yres > 1200)) output("Mode %dx%d exceeds documented limits.\n", var->xres, var->yres); // // try to be smart about (x|y)res_virtual problems. // if (var->xres > var->xres_virtual) var->xres_virtual = var->xres; if (var->yres > var->yres_virtual) var->yres_virtual = var->yres; if (bpp == 8 || bpp == 16) { if (var->xres_virtual > 4088) var->xres_virtual = 4088; } else { if (var->xres_virtual > 2040) var->xres_virtual = 2040; } var->xres_virtual &= ~7; while (var->xres_virtual * var->yres_virtual * bpp / 8 > info->fix.smem_len) { if (var->yres_virtual > var->yres) var->yres_virtual--; else if (var->xres_virtual > var->xres) var->xres_virtual -= 8; else 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; } return 0;}//=====================================================================//// Pan the display//// The datasheets defines crt start address to be 20 bits wide and// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use// it, so it is also safe to be used here. BTW: datasheet CR0E on page// 90 really is CR1E, the real CRE is documented on page 72.//// BUT://// As of internal version 0.60 we do not use vga panning any longer.// Vga panning did not allow us the use of all available video memory// and thus prevented ywrap scrolling. We do use the "right view"// register now.//////=====================================================================static int cyblafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){ KD_GRAPHICS_RETURN(0); info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset * var->xres_virtual)) * var->bits_per_pixel / 32)); return 0;}//============================================//// This will really help in case of a bug ...// dump most gaphics core registers.////============================================static void regdump(struct cyblafb_par *par){ int i; if (verbosity < 2) return; printk("\n"); for (i = 0; i <= 0xff; i++) { outb(i, 0x3d4); printk("CR%02x=%02x ", i, inb(0x3d5)); if (i % 16 == 15) printk("\n"); } outb(0x30, 0x3ce); outb(inb(0x3cf) | 0x40, 0x3cf); for (i = 0; i <= 0x1f; i++) { if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11 || i == 0x16) { outb(i, 0x3d4); printk("CR%02x=%02x ", i, inb(0x3d5)); } else printk("------- "); if (i % 16 == 15) printk("\n"); } outb(0x30, 0x3ce); outb(inb(0x3cf) & 0xbf, 0x3cf); printk("\n"); for (i = 0; i <= 0x7f; i++) { outb(i, 0x3ce); printk("GR%02x=%02x ", i, inb(0x3cf)); if (i % 16 == 15) printk("\n"); } printk("\n"); for (i = 0; i <= 0xff; i++) { outb(i, 0x3c4); printk("SR%02x=%02x ", i, inb(0x3c5)); if (i % 16 == 15) printk("\n"); } printk("\n"); for (i = 0; i <= 0x1F; i++) { inb(0x3da); // next access is index! outb(i, 0x3c0); printk("AR%02x=%02x ", i, inb(0x3c1)); if (i % 16 == 15) printk("\n"); } printk("\n"); inb(0x3DA); // reset internal flag to 3c0 index outb(0x20, 0x3C0); // enable attr return;}//=======================================================================//// Save State//// This function is called while a switch to KD_TEXT is in progress,// before any of the other functions are called.////=======================================================================static void cyblafb_save_state(struct fb_info *info){ struct cyblafb_par *par = info->par; if (verbosity > 0) output("Switching to KD_TEXT\n"); disabled = 0; regdump(par); enable_mmio(); return;}//=======================================================================//// Restore State//// This function is called while a switch to KD_GRAPHICS is in progress,// We have to turn on vga style panning registers again because the// trident driver of X does not know about GE10.////=======================================================================static void cyblafb_restore_state(struct fb_info *info){ if (verbosity > 0) output("Switching to KD_GRAPHICS\n"); out32(GE10, 0); disabled = 1; return;}//======================================//// Set hardware to requested video mode////======================================static int cyblafb_set_par(struct fb_info *info){ struct cyblafb_par *par = info->par; u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend, preendfetch, vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend; struct fb_var_screeninfo *var = &info->var; int bpp = var->bits_per_pixel; int i; KD_GRAPHICS_RETURN(0); if (verbosity > 0) output("Switching to new mode: " "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n", var->xres, var->yres, var->xres_virtual, var->yres_virtual, var->bits_per_pixel, var->pixclock, var->left_margin, var->right_margin, var->upper_margin, var->lower_margin, var->hsync_len, var->vsync_len); htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len) / 8 - 5; hdispend = var->xres / 8 - 1; hsyncstart = (var->xres + var->right_margin) / 8; hsyncend = var->hsync_len / 8; hblankstart = hdispend + 1; hblankend = htotal + 3; // should be htotal + 5, bios does it this way preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3); vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2; vdispend = var->yres - 1; vsyncstart = var->yres + var->lower_margin; vblankstart = var->yres; vblankend = vtotal; // should be vtotal + 2, but bios does it this way vsyncend = var->vsync_len; enable_mmio(); // necessary! ... check X ... write3X4(CR11, read3X4(CR11) & 0x7F); // unlock cr00 .. cr07 write3CE(GR30, 8); if ((displaytype == DISPLAY_FP) && var->xres < nativex) { // stretch or center ? out8(0x3C2, 0xEB); write3CE(GR30, read3CE(GR30) | 0x81); // shadow mode on if (center) { write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80); write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80); } else if (stretch) { write3CE(GR5D, 0); write3CE(GR52, (read3CE(GR52) & 0x7C) | 1); write3CE(GR53, (read3CE(GR53) & 0x7C) | 1); } } else { out8(0x3C2, 0x2B); write3CE(GR30, 8); } // // Setup CRxx regs // write3X4(CR00, htotal & 0xFF); write3X4(CR01, hdispend & 0xFF); write3X4(CR02, hblankstart & 0xFF); write3X4(CR03, hblankend & 0x1F); write3X4(CR04, hsyncstart & 0xFF); write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); write3X4(CR06, vtotal & 0xFF); write3X4(CR07, (vtotal & 0x100) >> 8 | (vdispend & 0x100) >> 7 | (vsyncstart & 0x100) >> 6 | (vblankstart & 0x100) >> 5 | 0x10 | (vtotal & 0x200) >> 4 | (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2); write3X4(CR08, 0); write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 | // FIX !!! ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0)); write3X4(CR0A, 0); // Init to some reasonable default write3X4(CR0B, 0); // Init to some reasonable default write3X4(CR0C, 0); // Offset 0 write3X4(CR0D, 0); // Offset 0 write3X4(CR0E, 0); // Init to some reasonable default write3X4(CR0F, 0); // Init to some reasonable default write3X4(CR10, vsyncstart & 0xFF); write3X4(CR11, (vsyncend & 0x0F)); write3X4(CR12, vdispend & 0xFF); write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF); write3X4(CR14, 0x40); // double word mode write3X4(CR15, vblankstart & 0xFF); write3X4(CR16, vblankend & 0xFF); write3X4(CR17, 0xE3); write3X4(CR18, 0xFF); // CR19: needed for interlaced modes ... ignore it for now write3X4(CR1A, 0x07); // Arbitration Control Counter 1 write3X4(CR1B, 0x07); // Arbitration Control Counter 2 write3X4(CR1C, 0x07); // Arbitration Control Counter 3 write3X4(CR1D, 0x00); // Don't know, doesn't hurt ; -) write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80); // CR1F: do not set, contains BIOS info about memsize write3X4(CR20, 0x20); // enabe wr buf, disable 16bit planar mode write3X4(CR21, 0x20); // enable linear memory access // CR22: RO cpu latch readback // CR23: ??? // CR24: RO AR flag state // CR25: RAMDAC rw timing, pclk buffer tristate control ???? // CR26: ??? write3X4(CR27, (vdispend & 0x400) >> 6 | (vsyncstart & 0x400) >> 5 | (vblankstart & 0x400) >> 4 | (vtotal & 0x400) >> 3 | 0x8); // CR28: ??? write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual * bpp) / (4 * 16)) & 0x300) >> 4)); write3X4(CR2A, read3X4(CR2A) | 0x40); write3X4(CR2B, (htotal & 0x100) >> 8 | (hdispend & 0x100) >> 7 | // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ??? (hsyncstart & 0x100) >> 5 | (hblankstart & 0x100) >> 4); // CR2C: ??? // CR2D: initialized in cyblafb_setup_GE() write3X4(CR2F, 0x92); // conservative, better signal quality // CR30: reserved // CR31: reserved // CR32: reserved // CR33: reserved // CR34: disabled in CR36 // CR35: disabled in CR36 // CR36: initialized in cyblafb_setup_GE // CR37: i2c, ignore for now write3X4(CR38, (bpp == 8) ? 0x00 : // (bpp == 16) ? 0x05 : // highcolor (bpp == 24) ? 0x29 : // packed 24bit truecolor (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus write3X4(CR39, 0x01 | // MMIO enable (pcirb ? 0x02 : 0) | // pci read burst enable (pciwb ? 0x04 : 0)); // pci write burst enable write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase (pcirr ? 0x40 : 0) | // pci read retry enable (pciwr ? 0x80 : 0)); // pci write retry enable write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2 : 0); write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0); write3X4(CR58, 0x82); // Bios does this .... don't know more // // Setup SRxx regs // write3C4(SR00, 3); write3C4(SR01, 1); //set char clock 8 dots wide write3C4(SR02, 0x0F); //enable 4 maps needed in chain4 mode write3C4(SR03, 0); //no character map select write3C4(SR04, 0x0E); //memory mode: ext mem, even, chain4 out8(0x3C4, 0x0b); in8(0x3C5); // Set NEW mode write3C4(SR0D, 0x00); // test ... check set_vclk(par, (bpp == 32 ? 200000000 : 100000000) / info->var.pixclock); //SR18, SR19 // // Setup GRxx regs // write3CE(GR00, 0x00); // test ... check write3CE(GR01, 0x00); // test ... check write3CE(GR02, 0x00); // test ... check write3CE(GR03, 0x00); // test ... check write3CE(GR04, 0x00); // test ... check write3CE(GR05, 0x40); // no CGA compat, allow 256 col write3CE(GR06, 0x05); // graphics mode write3CE(GR07, 0x0F); // planes? write3CE(GR08, 0xFF); // test ... check write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4 write3CE(GR20, 0xC0); // test ... check write3CE(GR2F, 0xA0); // PCLK = VCLK, no skew, // // Setup ARxx regs // for (i = 0; i < 0x10; i++) // set AR00 .. AR0f write3C0(i, i); write3C0(AR10, 0x41); // graphics mode and support 256 color modes write3C0(AR12, 0x0F); // planes write3C0(AR13, 0); // horizontal pel panning in8(0x3DA); // reset internal flag to 3c0 index out8(0x3C0, 0x20); // enable attr // // Setup hidden RAMDAC command register // in8(0x3C8); // these reads are in8(0x3C6); // necessary to in8(0x3C6); // unmask the RAMDAC in8(0x3C6); // command reg, otherwise in8(0x3C6); // we would write the pixelmask reg! out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors (bpp == 15) ? 0x10 : // (bpp == 16) ? 0x30 : // hicolor (bpp == 24) ? 0xD0 : // truecolor (bpp == 32) ? 0xD0 : 0); // truecolor in8(0x3C8); // // GR31 is not mentioned in the datasheet // if (displaytype == DISPLAY_FP) write3CE(GR31, (read3CE(GR31) & 0x8F) | ((info->var.yres > 1024) ? 0x50 : (info->var.yres > 768) ? 0x30 : (info->var.yres > 600) ? 0x20 : (info->var.yres > 480) ? 0x10 : 0)); info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; info->fix.line_length = info->var.xres_virtual * (bpp >> 3); info->cmap.len = (bpp == 8) ? 256 : 16; // // init acceleration engine // cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel); // // Set/clear flags to allow proper scroll mode selection. // if (var->xres == var->xres_virtual) info->flags &= ~FBINFO_HWACCEL_XPAN; else info->flags |= FBINFO_HWACCEL_XPAN; if (var->yres == var->yres_virtual) info->flags &= ~FBINFO_HWACCEL_YPAN; else info->flags |= FBINFO_HWACCEL_YPAN; if (info->fix.smem_len != var->xres_virtual * var->yres_virtual * bpp / 8) info->flags &= ~FBINFO_HWACCEL_YWRAP; else info->flags |= FBINFO_HWACCEL_YWRAP; regdump(par); return 0;}//========================//// Set one color register////========================static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info){ int bpp = info->var.bits_per_pixel; KD_GRAPHICS_RETURN(0); if (regno >= info->cmap.len) return 1; if (bpp == 8) { out8(0x3C6, 0xFF); out8(0x3C8, regno); out8(0x3C9, red >> 10); out8(0x3C9, green >> 10); out8(0x3C9, blue >> 10); } else if (regno < 16) { if (bpp == 16) // RGB 565 ((u32 *) info->pseudo_palette)[regno] = (red & 0xF800) | ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); else if (bpp == 32) // ARGB 8888 ((u32 *) info->pseudo_palette)[regno] = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) | ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); } return 0;}//==========================================================//// Try blanking the screen. For flat panels it does nothing////==========================================================static int cyblafb_blank(int blank_mode, struct fb_info *info){ unsigned char PMCont, DPMSCont; KD_GRAPHICS_RETURN(0); if (displaytype == DISPLAY_FP) return 0; out8(0x83C8, 0x04); // DPMS Control PMCont = in8(0x83C6) & 0xFC; DPMSCont = read3CE(GR23) & 0xFC; switch (blank_mode) { case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On PMCont |= 0x03; DPMSCont |= 0x00; break; case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On PMCont |= 0x02; DPMSCont |= 0x01; break; case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off PMCont |= 0x02; DPMSCont |= 0x02; break; case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off PMCont |= 0x00; DPMSCont |= 0x03; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -