📄 neofb.c
字号:
par->ref_count++; return 0;}static intneofb_release(struct fb_info *info, int user){ struct neofb_par *par = info->par; if (!par->ref_count) return -EINVAL; if (par->ref_count == 1) { restore_vga(&par->state); } par->ref_count--; return 0;}static intneofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ struct neofb_par *par = info->par; int memlen, vramlen; int mode_ok = 0; DBG("neofb_check_var"); if (PICOS2KHZ(var->pixclock) > par->maxClock) return -EINVAL; /* Is the mode larger than the LCD panel? */ if (par->internal_display && ((var->xres > par->NeoPanelWidth) || (var->yres > par->NeoPanelHeight))) { printk(KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n", var->xres, var->yres, par->NeoPanelWidth, par->NeoPanelHeight); return -EINVAL; } /* Is the mode one of the acceptable sizes? */ if (!par->internal_display) mode_ok = 1; else { switch (var->xres) { case 1280: if (var->yres == 1024) mode_ok = 1; break; case 1024: if (var->yres == 768) mode_ok = 1; break; case 800: if (var->yres == (par->libretto ? 480 : 600)) mode_ok = 1; break; case 640: if (var->yres == 480) mode_ok = 1; break; } } if (!mode_ok) { printk(KERN_INFO "Mode (%dx%d) won't display properly on LCD\n", var->xres, var->yres); return -EINVAL; } var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; var->transp.msb_right = 0; var->transp.offset = 0; var->transp.length = 0; switch (var->bits_per_pixel) { case 8: /* PSEUDOCOLOUR, 256 */ var->red.offset = 0; var->red.length = 8; var->green.offset = 0; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; break; case 16: /* DIRECTCOLOUR, 64k */ var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; break; case 24: /* TRUECOLOUR, 16m */ var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; break;#ifdef NO_32BIT_SUPPORT_YET case 32: /* TRUECOLOUR, 16m */ var->transp.offset = 24; var->transp.length = 8; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; break;#endif default: printk(KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel); return -EINVAL; } vramlen = info->fix.smem_len; if (vramlen > 4 * 1024 * 1024) vramlen = 4 * 1024 * 1024; if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual >> 3; if (memlen > vramlen) { var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel); memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; } /* 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->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; var->nonstd = 0; var->height = -1; var->width = -1; if (var->bits_per_pixel >= 24 || !par->neo2200) var->accel_flags &= ~FB_ACCELF_TEXT; return 0;}static int neofb_set_par(struct fb_info *info){ struct neofb_par *par = info->par; unsigned char temp; int i, clock_hi = 0; int lcd_stretch; int hoffset, voffset; int vsync_start, vtotal; DBG("neofb_set_par"); neoUnlock(); vgaHWProtect(1); /* Blank the screen */ vsync_start = info->var.yres + info->var.lower_margin; vtotal = vsync_start + info->var.vsync_len + info->var.upper_margin; /* * This will allocate the datastructure and initialize all of the * generic VGA registers. */ if (vgaHWInit(&info->var, par)) return -EINVAL; /* * The default value assigned by vgaHW.c is 0x41, but this does * not work for NeoMagic. */ par->Attribute[16] = 0x01; switch (info->var.bits_per_pixel) { case 8: par->CRTC[0x13] = info->var.xres_virtual >> 3; par->ExtCRTOffset = info->var.xres_virtual >> 11; par->ExtColorModeSelect = 0x11; break; case 16: par->CRTC[0x13] = info->var.xres_virtual >> 2; par->ExtCRTOffset = info->var.xres_virtual >> 10; par->ExtColorModeSelect = 0x13; break; case 24: par->CRTC[0x13] = (info->var.xres_virtual * 3) >> 3; par->ExtCRTOffset = (info->var.xres_virtual * 3) >> 11; par->ExtColorModeSelect = 0x14; break;#ifdef NO_32BIT_SUPPORT_YET case 32: /* FIXME: guessed values */ par->CRTC[0x13] = info->var.xres_virtual >> 1; par->ExtCRTOffset = info->var.xres_virtual >> 9; par->ExtColorModeSelect = 0x15; break;#endif default: break; } par->ExtCRTDispAddr = 0x10; /* Vertical Extension */ par->VerticalExt = (((vtotal - 2) & 0x400) >> 10) | (((info->var.yres - 1) & 0x400) >> 9) | (((vsync_start) & 0x400) >> 8) | (((vsync_start) & 0x400) >> 7); /* Fast write bursts on unless disabled. */ if (par->pci_burst) par->SysIfaceCntl1 = 0x30; else par->SysIfaceCntl1 = 0x00; par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */ /* Initialize: by default, we want display config register to be read */ par->PanelDispCntlRegRead = 1; /* Enable any user specified display devices. */ par->PanelDispCntlReg1 = 0x00; if (par->internal_display) par->PanelDispCntlReg1 |= 0x02; if (par->external_display) par->PanelDispCntlReg1 |= 0x01; /* If the user did not specify any display devices, then... */ if (par->PanelDispCntlReg1 == 0x00) { /* Default to internal (i.e., LCD) only. */ par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03; } /* If we are using a fixed mode, then tell the chip we are. */ switch (info->var.xres) { case 1280: par->PanelDispCntlReg1 |= 0x60; break; case 1024: par->PanelDispCntlReg1 |= 0x40; break; case 800: par->PanelDispCntlReg1 |= 0x20; break; case 640: default: break; } /* Setup shadow register locking. */ switch (par->PanelDispCntlReg1 & 0x03) { case 0x01: /* External CRT only mode: */ par->GeneralLockReg = 0x00; /* We need to program the VCLK for external display only mode. */ par->ProgramVCLK = 1; break; case 0x02: /* Internal LCD only mode: */ case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */ par->GeneralLockReg = 0x01; /* Don't program the VCLK when using the LCD. */ par->ProgramVCLK = 0; break; } /* * If the screen is to be stretched, turn on stretching for the * various modes. * * OPTION_LCD_STRETCH means stretching should be turned off! */ par->PanelDispCntlReg2 = 0x00; par->PanelDispCntlReg3 = 0x00; if (par->lcd_stretch && (par->PanelDispCntlReg1 == 0x02) && /* LCD only */ (info->var.xres != par->NeoPanelWidth)) { switch (info->var.xres) { case 320: /* Needs testing. KEM -- 24 May 98 */ case 400: /* Needs testing. KEM -- 24 May 98 */ case 640: case 800: case 1024: lcd_stretch = 1; par->PanelDispCntlReg2 |= 0xC6; break; default: lcd_stretch = 0; /* No stretching in these modes. */ } } else lcd_stretch = 0; /* * If the screen is to be centerd, turn on the centering for the * various modes. */ par->PanelVertCenterReg1 = 0x00; par->PanelVertCenterReg2 = 0x00; par->PanelVertCenterReg3 = 0x00; par->PanelVertCenterReg4 = 0x00; par->PanelVertCenterReg5 = 0x00; par->PanelHorizCenterReg1 = 0x00; par->PanelHorizCenterReg2 = 0x00; par->PanelHorizCenterReg3 = 0x00; par->PanelHorizCenterReg4 = 0x00; par->PanelHorizCenterReg5 = 0x00; if (par->PanelDispCntlReg1 & 0x02) { if (info->var.xres == par->NeoPanelWidth) { /* * No centering required when the requested display width * equals the panel width. */ } else { par->PanelDispCntlReg2 |= 0x01; par->PanelDispCntlReg3 |= 0x10; /* Calculate the horizontal and vertical offsets. */ if (!lcd_stretch) { hoffset = ((par->NeoPanelWidth - info->var.xres) >> 4) - 1; voffset = ((par->NeoPanelHeight - info->var.yres) >> 1) - 2; } else { /* Stretched modes cannot be centered. */ hoffset = 0; voffset = 0; } switch (info->var.xres) { case 320: /* Needs testing. KEM -- 24 May 98 */ par->PanelHorizCenterReg3 = hoffset; par->PanelVertCenterReg2 = voffset; break; case 400: /* Needs testing. KEM -- 24 May 98 */ par->PanelHorizCenterReg4 = hoffset; par->PanelVertCenterReg1 = voffset; break; case 640: par->PanelHorizCenterReg1 = hoffset; par->PanelVertCenterReg3 = voffset; break; case 800: par->PanelHorizCenterReg2 = hoffset; par->PanelVertCenterReg4 = voffset; break; case 1024: par->PanelHorizCenterReg5 = hoffset; par->PanelVertCenterReg5 = voffset; break; case 1280: default: /* No centering in these modes. */ break; } } } par->biosMode = neoFindMode(info->var.xres, info->var.yres, info->var.bits_per_pixel); /* * Calculate the VCLK that most closely matches the requested dot * clock. */ neoCalcVCLK(info, par, PICOS2KHZ(info->var.pixclock)); /* Since we program the clocks ourselves, always use VCLK3. */ par->MiscOutReg |= 0x0C; /* alread unlocked above */ /* BOGUS vga_wgfx(NULL, 0x09, 0x26); */ /* don't know what this is, but it's 0 from bootup anyway */ vga_wgfx(NULL, 0x15, 0x00); /* was set to 0x01 by my bios in text and vesa modes */ vga_wgfx(NULL, 0x0A, par->GeneralLockReg); /* * The color mode needs to be set before calling vgaHWRestore * to ensure the DAC is initialized properly. * * NOTE: Make sure we don't change bits make sure we don't change * any reserved bits. */ temp = vga_rgfx(NULL, 0x90); switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2070: temp &= 0xF0; /* Save bits 7:4 */ temp |= (par->ExtColorModeSelect & ~0xF0); break; case FB_ACCEL_NEOMAGIC_NM2090: case FB_ACCEL_NEOMAGIC_NM2093: case FB_ACCEL_NEOMAGIC_NM2097: case FB_ACCEL_NEOMAGIC_NM2160: case FB_ACCEL_NEOMAGIC_NM2200: case FB_ACCEL_NEOMAGIC_NM2230: case FB_ACCEL_NEOMAGIC_NM2360: case FB_ACCEL_NEOMAGIC_NM2380: temp &= 0x70; /* Save bits 6:4 */ temp |= (par->ExtColorModeSelect & ~0x70); break; } vga_wgfx(NULL, 0x90, temp); /* * In some rare cases a lockup might occur if we don't delay * here. (Reported by Miles Lane) */ //mdelay(200); /* * Disable horizontal and vertical graphics and text expansions so * that vgaHWRestore works properly. */ temp = vga_rgfx(NULL, 0x25); temp &= 0x39; vga_wgfx(NULL, 0x25, temp); /* * Sleep for 200ms to make sure that the two operations above have * had time to take effect. */ mdelay(200); /* * This function handles restoring the generic VGA registers. */ vgaHWRestore(info, par); /* linear colormap for non palettized modes */ switch (info->var.bits_per_pixel) { case 8: /* PseudoColor, 256 */ info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; case 16: /* TrueColor, 64k */ info->fix.visual = FB_VISUAL_TRUECOLOR; for (i = 0; i < 64; i++) { outb(i, 0x3c8); outb(i << 1, 0x3c9); outb(i, 0x3c9); outb(i << 1, 0x3c9); } break; case 24:#ifdef NO_32BIT_SUPPORT_YET case 32:#endif /* TrueColor, 16m */ info->fix.visual = FB_VISUAL_TRUECOLOR; for (i = 0; i < 256; i++) { outb(i, 0x3c8); outb(i, 0x3c9); outb(i, 0x3c9); outb(i, 0x3c9); } break; } vga_wgfx(NULL, 0x0E, par->ExtCRTDispAddr); vga_wgfx(NULL, 0x0F, par->ExtCRTOffset); temp = vga_rgfx(NULL, 0x10); temp &= 0x0F; /* Save bits 3:0 */ temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */ vga_wgfx(NULL, 0x10, temp); vga_wgfx(NULL, 0x11, par->SysIfaceCntl2); vga_wgfx(NULL, 0x15, 0 /*par->SingleAddrPage */ ); vga_wgfx(NULL, 0x16, 0 /*par->DualAddrPage */ ); temp = vga_rgfx(NULL, 0x20); switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2070: temp &= 0xFC; /* Save bits 7:2 */ temp |= (par->PanelDispCntlReg1 & ~0xFC); break; case FB_ACCEL_NEOMAGIC_NM2090: case FB_ACCEL_NEOMAGIC_NM2093: case FB_ACCEL_NEOMAGIC_NM2097: case FB_ACCEL_NEOMAGIC_NM2160: temp &= 0xDC; /* Save bits 7:6,4:2 */ temp |= (par->PanelDispCntlReg1 & ~0xDC); break; case FB_ACCEL_NEOMAGIC_NM2200: case FB_ACCEL_NEOMAGIC_NM2230: case FB_ACCEL_NEOMAGIC_NM2360: case FB_ACCEL_NEOMAGIC_NM2380: temp &= 0x98; /* Save bits 7,4:3 */ temp |= (par->PanelDispCntlReg1 & ~0x98); break; } vga_wgfx(NULL, 0x20, temp); temp = vga_rgfx(NULL, 0x25); temp &= 0x38; /* Save bits 5:3 */ temp |= (par->PanelDispCntlReg2 & ~0x38); vga_wgfx(NULL, 0x25, temp); if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) { temp = vga_rgfx(NULL, 0x30); temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */ temp |= (par->PanelDispCntlReg3 & ~0xEF); vga_wgfx(NULL, 0x30, temp); } vga_wgfx(NULL, 0x28, par->PanelVertCenterReg1); vga_wgfx(NULL, 0x29, par->PanelVertCenterReg2); vga_wgfx(NULL, 0x2a, par->PanelVertCenterReg3); if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) { vga_wgfx(NULL, 0x32, par->PanelVertCenterReg4); vga_wgfx(NULL, 0x33, par->PanelHorizCenterReg1); vga_wgfx(NULL, 0x34, par->PanelHorizCenterReg2); vga_wgfx(NULL, 0x35, par->PanelHorizCenterReg3); } if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160) vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4); if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 || info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 || info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 || info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) { vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4); vga_wgfx(NULL, 0x37, par->PanelVertCenterReg5); vga_wgfx(NULL, 0x38, par->PanelHorizCenterReg5); clock_hi = 1; } /* Program VCLK3 if needed. */ if (par->ProgramVCLK && ((vga_rgfx(NULL, 0x9B) != par->VCLK3NumeratorLow) || (vga_rgfx(NULL, 0x9F) != par->VCLK3Denominator) || (clock_hi && ((vga_rgfx(NULL, 0x8F) & ~0x0f)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -