📄 s3fb.c
字号:
/* Find appropriate format */ rv = svga_match_format (s3fb_formats, var, NULL); /* 32bpp mode is not supported on VIRGE VX, 24bpp is not supported on others */ if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6)) rv = -EINVAL; if (rv < 0) { printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node); return rv; } /* Do not allow to have real resoulution larger than virtual */ if (var->xres > var->xres_virtual) var->xres_virtual = var->xres; if (var->yres > var->yres_virtual) var->yres_virtual = var->yres; /* Round up xres_virtual to have proper alignment of lines */ step = s3fb_formats[rv].xresstep - 1; var->xres_virtual = (var->xres_virtual+step) & ~step; /* Check whether have enough memory */ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; if (mem > info->screen_size) { printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); return -EINVAL; } rv = svga_check_timings (&s3_timing_regs, var, info->node); if (rv < 0) { printk(KERN_ERR "fb%d: invalid timings requested\n", info->node); return rv; } rv = svga_compute_pll(&s3_pll, PICOS2KHZ(var->pixclock), &m, &n, &r, info->node); if (rv < 0) { printk(KERN_ERR "fb%d: invalid pixclock value requested\n", info->node); return rv; } return 0;}/* Set video mode from par */static int s3fb_set_par(struct fb_info *info){ struct s3fb_info *par = info->par; u32 value, mode, hmul, offset_value, screen_size, multiplex; u32 bpp = info->var.bits_per_pixel; if (bpp != 0) { info->fix.ypanstep = 1; info->fix.line_length = (info->var.xres_virtual * bpp) / 8; info->flags &= ~FBINFO_MISC_TILEBLITTING; info->tileops = NULL; /* in 4bpp supports 8p wide tiles only, any tiles otherwise */ info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0); info->pixmap.blit_y = ~(u32)0; offset_value = (info->var.xres_virtual * bpp) / 64; screen_size = info->var.yres_virtual * info->fix.line_length; } else { info->fix.ypanstep = 16; info->fix.line_length = 0; info->flags |= FBINFO_MISC_TILEBLITTING; info->tileops = fasttext ? &s3fb_fast_tile_ops : &s3fb_tile_ops; /* supports 8x16 tiles only */ info->pixmap.blit_x = 1 << (8 - 1); info->pixmap.blit_y = 1 << (16 - 1); offset_value = info->var.xres_virtual / 16; screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64; } info->var.xoffset = 0; info->var.yoffset = 0; info->var.activate = FB_ACTIVATE_NOW; /* Unlock registers */ vga_wcrt(NULL, 0x38, 0x48); vga_wcrt(NULL, 0x39, 0xA5); vga_wseq(NULL, 0x08, 0x06); svga_wcrt_mask(0x11, 0x00, 0x80); /* Blank screen and turn off sync */ svga_wseq_mask(0x01, 0x20, 0x20); svga_wcrt_mask(0x17, 0x00, 0x80); /* Set default values */ svga_set_default_gfx_regs(); svga_set_default_atc_regs(); svga_set_default_seq_regs(); svga_set_default_crt_regs(); svga_wcrt_multi(s3_line_compare_regs, 0xFFFFFFFF); svga_wcrt_multi(s3_start_address_regs, 0); /* S3 specific initialization */ svga_wcrt_mask(0x58, 0x10, 0x10); /* enable linear framebuffer */ svga_wcrt_mask(0x31, 0x08, 0x08); /* enable sequencer access to framebuffer above 256 kB *//* svga_wcrt_mask(0x33, 0x08, 0x08); */ /* DDR ? *//* svga_wcrt_mask(0x43, 0x01, 0x01); */ /* DDR ? */ svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ? */ svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ? */ svga_wcrt_mask(0x5D, 0x00, 0x28); // Clear strange HSlen bits/* svga_wcrt_mask(0x58, 0x03, 0x03); *//* svga_wcrt_mask(0x53, 0x12, 0x13); */ /* enable MMIO *//* svga_wcrt_mask(0x40, 0x08, 0x08); */ /* enable write buffer */ /* Set the offset register */ pr_debug("fb%d: offset register : %d\n", info->node, offset_value); svga_wcrt_multi(s3_offset_regs, offset_value); vga_wcrt(NULL, 0x54, 0x18); /* M parameter */ vga_wcrt(NULL, 0x60, 0xff); /* N parameter */ vga_wcrt(NULL, 0x61, 0xff); /* L parameter */ vga_wcrt(NULL, 0x62, 0xff); /* L parameter */ vga_wcrt(NULL, 0x3A, 0x35); svga_wattr(0x33, 0x00); if (info->var.vmode & FB_VMODE_DOUBLE) svga_wcrt_mask(0x09, 0x80, 0x80); else svga_wcrt_mask(0x09, 0x00, 0x80); if (info->var.vmode & FB_VMODE_INTERLACED) svga_wcrt_mask(0x42, 0x20, 0x20); else svga_wcrt_mask(0x42, 0x00, 0x20); /* Disable hardware graphics cursor */ svga_wcrt_mask(0x45, 0x00, 0x01); /* Disable Streams engine */ svga_wcrt_mask(0x67, 0x00, 0x0C); mode = svga_match_format(s3fb_formats, &(info->var), &(info->fix)); /* S3 virge DX hack */ if (par->chip == CHIP_375_VIRGE_DX) { vga_wcrt(NULL, 0x86, 0x80); vga_wcrt(NULL, 0x90, 0x00); } /* S3 virge VX hack */ if (par->chip == CHIP_988_VIRGE_VX) { vga_wcrt(NULL, 0x50, 0x00); vga_wcrt(NULL, 0x67, 0x50); vga_wcrt(NULL, 0x63, (mode <= 2) ? 0x90 : 0x09); vga_wcrt(NULL, 0x66, 0x90); } svga_wcrt_mask(0x31, 0x00, 0x40); multiplex = 0; hmul = 1; /* Set mode-specific register values */ switch (mode) { case 0: pr_debug("fb%d: text mode\n", info->node); svga_set_textmode_vga_regs(); /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(0x50, 0x00, 0x30); svga_wcrt_mask(0x67, 0x00, 0xF0); /* Disable enhanced mode */ svga_wcrt_mask(0x3A, 0x00, 0x30); if (fasttext) { pr_debug("fb%d: high speed text mode set\n", info->node); svga_wcrt_mask(0x31, 0x40, 0x40); } break; case 1: pr_debug("fb%d: 4 bit pseudocolor\n", info->node); vga_wgfx(NULL, VGA_GFX_MODE, 0x40); /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(0x50, 0x00, 0x30); svga_wcrt_mask(0x67, 0x00, 0xF0); /* disable enhanced mode */ svga_wcrt_mask(0x3A, 0x00, 0x30); break; case 2: pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(0x50, 0x00, 0x30); svga_wcrt_mask(0x67, 0x00, 0xF0); /* disable enhanced mode */ svga_wcrt_mask(0x3A, 0x00, 0x30); break; case 3: pr_debug("fb%d: 8 bit pseudocolor\n", info->node); if (info->var.pixclock > 20000) { svga_wcrt_mask(0x50, 0x00, 0x30); svga_wcrt_mask(0x67, 0x00, 0xF0); } else { svga_wcrt_mask(0x50, 0x00, 0x30); svga_wcrt_mask(0x67, 0x10, 0xF0); multiplex = 1; } break; case 4: pr_debug("fb%d: 5/5/5 truecolor\n", info->node); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) svga_wcrt_mask(0x67, 0x20, 0xF0); else svga_wcrt_mask(0x67, 0x30, 0xF0); } else { svga_wcrt_mask(0x50, 0x10, 0x30); svga_wcrt_mask(0x67, 0x30, 0xF0); hmul = 2; } break; case 5: pr_debug("fb%d: 5/6/5 truecolor\n", info->node); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) svga_wcrt_mask(0x67, 0x40, 0xF0); else svga_wcrt_mask(0x67, 0x50, 0xF0); } else { svga_wcrt_mask(0x50, 0x10, 0x30); svga_wcrt_mask(0x67, 0x50, 0xF0); hmul = 2; } break; case 6: /* VIRGE VX case */ pr_debug("fb%d: 8/8/8 truecolor\n", info->node); svga_wcrt_mask(0x67, 0xD0, 0xF0); break; case 7: pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node); svga_wcrt_mask(0x50, 0x30, 0x30); svga_wcrt_mask(0x67, 0xD0, 0xF0); break; default: printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node); return -EINVAL; } if (par->chip != CHIP_988_VIRGE_VX) { svga_wseq_mask(0x15, multiplex ? 0x10 : 0x00, 0x10); svga_wseq_mask(0x18, multiplex ? 0x80 : 0x00, 0x80); } s3_set_pixclock(info, info->var.pixclock); svga_set_timings(&s3_timing_regs, &(info->var), hmul, 1, (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1, hmul, info->node); /* Set interlaced mode start/end register */ value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len; value = ((value * hmul) / 8) - 5; vga_wcrt(NULL, 0x3C, (value + 1) / 2); memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ svga_wcrt_mask(0x17, 0x80, 0x80); svga_wseq_mask(0x01, 0x00, 0x20); return 0;}/* Set a colour register */static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *fb){ switch (fb->var.bits_per_pixel) { case 0: case 4: if (regno >= 16) return -EINVAL; if ((fb->var.bits_per_pixel == 4) && (fb->var.nonstd == 0)) { outb(0xF0, VGA_PEL_MSK); outb(regno*16, VGA_PEL_IW); } else { outb(0x0F, VGA_PEL_MSK); outb(regno, VGA_PEL_IW); } outb(red >> 10, VGA_PEL_D); outb(green >> 10, VGA_PEL_D); outb(blue >> 10, VGA_PEL_D); break; case 8: if (regno >= 256) return -EINVAL; outb(0xFF, VGA_PEL_MSK); outb(regno, VGA_PEL_IW); outb(red >> 10, VGA_PEL_D); outb(green >> 10, VGA_PEL_D); outb(blue >> 10, VGA_PEL_D); break; case 16: if (regno >= 16) return 0; if (fb->var.green.length == 5) ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11); else if (fb->var.green.length == 6) ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) | ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); else return -EINVAL; break; case 24: case 32: if (regno >= 16) return 0; ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); break; default: return -EINVAL; } return 0;}/* Set the display blanking state */static int s3fb_blank(int blank_mode, struct fb_info *info){ switch (blank_mode) { case FB_BLANK_UNBLANK: pr_debug("fb%d: unblank\n", info->node); svga_wcrt_mask(0x56, 0x00, 0x06); svga_wseq_mask(0x01, 0x00, 0x20); break; case FB_BLANK_NORMAL: pr_debug("fb%d: blank\n", info->node); svga_wcrt_mask(0x56, 0x00, 0x06); svga_wseq_mask(0x01, 0x20, 0x20); break; case FB_BLANK_HSYNC_SUSPEND: pr_debug("fb%d: hsync\n", info->node); svga_wcrt_mask(0x56, 0x02, 0x06); svga_wseq_mask(0x01, 0x20, 0x20); break; case FB_BLANK_VSYNC_SUSPEND: pr_debug("fb%d: vsync\n", info->node); svga_wcrt_mask(0x56, 0x04, 0x06); svga_wseq_mask(0x01, 0x20, 0x20); break; case FB_BLANK_POWERDOWN: pr_debug("fb%d: sync down\n", info->node); svga_wcrt_mask(0x56, 0x06, 0x06); svga_wseq_mask(0x01, 0x20, 0x20); break; } return 0;}/* Pan the display */static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { unsigned int offset; /* Calculate the offset */ if (var->bits_per_pixel == 0) { offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2); offset = offset >> 2; } else { offset = (var->yoffset * info->fix.line_length) + (var->xoffset * var->bits_per_pixel / 8); offset = offset >> 2; } /* Set the offset */ svga_wcrt_multi(s3_start_address_regs, offset);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -