📄 sis_main.c
字号:
static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fb_info){ if (regno >= ivideo.video_cmap_len) return 1; sis_palette[regno].red = red; sis_palette[regno].green = green; sis_palette[regno].blue = blue; switch (ivideo.video_bpp) {#ifdef FBCON_HAS_CFB8 case 8: outSISREG(SISDACA, regno); outSISREG(SISDACD, (red >> 10)); outSISREG(SISDACD, (green >> 10)); outSISREG(SISDACD, (blue >> 10)); if (ivideo.disp_state & DISPTYPE_DISP2) { outSISREG(SISDAC2A, regno); outSISREG(SISDAC2D, (red >> 8)); outSISREG(SISDAC2D, (green >> 8)); outSISREG(SISDAC2D, (blue >> 8)); } break;#endif#ifdef FBCON_HAS_CFB16 case 15: case 16: sis_fbcon_cmap.cfb16[regno] = ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); break;#endif#ifdef FBCON_HAS_CFB24 case 24: red >>= 8; green >>= 8; blue >>= 8; sis_fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | (blue); break;#endif#ifdef FBCON_HAS_CFB32 case 32: red >>= 8; green >>= 8; blue >>= 8; sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue); break;#endif } return 0;}static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info){ unsigned int htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; unsigned int vtotal = 0; /* TW */ /* var->upper_margin + var->yres + var->lower_margin + var->vsync_len; */ double drate = 0, hrate = 0; int found_mode = 0; int old_mode; TWDEBUG("Inside do_set_var"); if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { vtotal = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; /* TW */ vtotal <<= 1; } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { vtotal = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; /* TW */ vtotal <<= 2; } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { vtotal = var->upper_margin + (var->yres/2) + var->lower_margin + var->vsync_len; /* TW */ /* var->yres <<= 1; */ /* TW */ } else vtotal = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; if(!(htotal) || !(vtotal)) { DPRINTK("sisfb: Invalid 'var' information\n"); return -EINVAL; } drate = 1E12 / var->pixclock; hrate = drate / htotal; ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); /* TW: Calculation wrong for 1024x600 - force it to 60Hz */ if((var->xres == 1024) && (var->yres == 600)) ivideo.refresh_rate = 60; printk("sisfb: Change mode to %dx%dx%d-%dHz\n", var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate); old_mode = sisfb_mode_idx; sisfb_mode_idx = 0; while( (sisbios_mode[sisfb_mode_idx].mode_no != 0) && (sisbios_mode[sisfb_mode_idx].xres <= var->xres) ) { if( (sisbios_mode[sisfb_mode_idx].xres == var->xres) && (sisbios_mode[sisfb_mode_idx].yres == var->yres) && (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) { sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no; found_mode = 1; break; } sisfb_mode_idx++; } if(found_mode) sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx); else sisfb_mode_idx = -1; if(sisfb_mode_idx < 0) { printk("sisfb: Mode %dx%dx%d not supported\n", var->xres, var->yres, var->bits_per_pixel); sisfb_mode_idx = old_mode; return -EINVAL; } if(sisfb_search_refresh_rate(ivideo.refresh_rate) == 0) { sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; ivideo.refresh_rate = 60; }#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33) if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {#else if(isactive) {#endif sisfb_pre_setmode(); if(SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) { printk("sisfb: Setting mode[0x%x] failed\n", sisfb_mode_no); return -EINVAL; } outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); sisfb_post_setmode(); DPRINTK("sisfb: Set new mode: %dx%dx%d-%d \n", sisbios_mode[sisfb_mode_idx].xres, sisbios_mode[sisfb_mode_idx].yres, sisbios_mode[sisfb_mode_idx].bpp, ivideo.refresh_rate); ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp; ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres; ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres; ivideo.org_x = ivideo.org_y = 0; ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3); switch(ivideo.video_bpp) { case 8: ivideo.DstColor = 0x0000; ivideo.SiS310_AccelDepth = 0x00000000; ivideo.video_cmap_len = 256; break; case 16: ivideo.DstColor = 0x8000; ivideo.SiS310_AccelDepth = 0x00010000; ivideo.video_cmap_len = 16; break; case 32: ivideo.DstColor = 0xC000; ivideo.SiS310_AccelDepth = 0x00020000; ivideo.video_cmap_len = 16; break; default: ivideo.video_cmap_len = 16; printk(KERN_ERR "sisfb: Unsupported accel depth %d", ivideo.video_bpp); break; } } TWDEBUG("End of do_set_var"); return 0;}/* ------ Internal functions only for 2.4 series ------- */#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)static void sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info){ struct fb_fix_screeninfo fix; long flags; struct display *display; struct display_switch *sw; if(con >= 0) display = &fb_display[con]; else display = &sis_disp; sisfb_get_fix(&fix, con, 0);#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,23) display->screen_base = ivideo.video_vbase;#endif display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; display->ypanstep = fix.ypanstep; display->ywrapstep = fix.ywrapstep; display->line_length = fix.line_length; display->next_line = fix.line_length; display->can_soft_blank = 0; display->inverse = sisfb_inverse; display->var = *var; save_flags(flags); switch (ivideo.video_bpp) {#ifdef FBCON_HAS_CFB8 case 8:#ifdef SISFBACCEL sw = sisfb_accel ? &fbcon_sis8 : &fbcon_cfb8;#else sw = &fbcon_cfb8;#endif break;#endif#ifdef FBCON_HAS_CFB16 case 15: case 16:#ifdef SISFBACCEL sw = sisfb_accel ? &fbcon_sis16 : &fbcon_cfb16;#else sw = &fbcon_cfb16;#endif display->dispsw_data = sis_fbcon_cmap.cfb16; break;#endif#ifdef FBCON_HAS_CFB24 case 24: sw = &fbcon_cfb24; display->dispsw_data = sis_fbcon_cmap.cfb24; break;#endif#ifdef FBCON_HAS_CFB32 case 32:#ifdef SISFBACCEL sw = sisfb_accel ? &fbcon_sis32 : &fbcon_cfb32;#else sw = &fbcon_cfb32;#endif display->dispsw_data = sis_fbcon_cmap.cfb32; break;#endif default: sw = &fbcon_dummy; return; } memcpy(&sisfb_sw, sw, sizeof(*sw)); display->dispsw = &sisfb_sw; restore_flags(flags);#ifdef SISFB_PAN if(sisfb_ypan) { /* display->scrollmode = SCROLL_YPAN; - not defined */ } else { display->scrollmode = SCROLL_YREDRAW; sisfb_sw.bmove = fbcon_redraw_bmove; }#else display->scrollmode = SCROLL_YREDRAW; sisfb_sw.bmove = fbcon_redraw_bmove;#endif}static void sisfb_do_install_cmap(int con, struct fb_info *info){#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23) if (con != info->currcon) return; if (fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, 1, info); else fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1, info);#else if (con != currcon) return; if (fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info); else fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1, sisfb_setcolreg, info);#endif}#endif/* ------ functions for all series ------ */#ifdef SISFB_PANstatic void sisfb_pan_var(struct fb_var_screeninfo *var){ unsigned int base; TWDEBUG("Inside pan_var"); base = var->yoffset * var->xres_virtual + var->xoffset; /* calculate base bpp dep. */ switch(var->bits_per_pixel) { case 16: base >>= 1; break; case 32: break; case 8: default: base >>= 2; break; } outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); outSISIDXREG(SISCR, 0x0D, base & 0xFF); outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF); outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF); if(sisvga_engine == SIS_315_VGA) { setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01); } if(ivideo.disp_state & DISPTYPE_DISP2) { orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01); outSISIDXREG(SISPART1, 0x06, (base & 0xFF)); outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF)); outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF)); if(sisvga_engine == SIS_315_VGA) { setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7); } } TWDEBUG("End of pan_var");}#endifstatic void sisfb_crtc_to_var(struct fb_var_screeninfo *var){ u16 VRE, VBE, VRS, VBS, VDE, VT; u16 HRE, HBE, HRS, HBS, HDE, HT; u8 sr_data, cr_data, cr_data2, cr_data3, mr_data; int A, B, C, D, E, F, temp; double hrate, drate; TWDEBUG("Inside crtc_to_var"); inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data); if (sr_data & SIS_INTERLACED_MODE) var->vmode = FB_VMODE_INTERLACED; else var->vmode = FB_VMODE_NONINTERLACED; switch ((sr_data & 0x1C) >> 2) { case SIS_8BPP_COLOR_MODE: var->bits_per_pixel = 8; break; case SIS_16BPP_COLOR_MODE: var->bits_per_pixel = 16; break; case SIS_32BPP_COLOR_MODE: var->bits_per_pixel = 32; break; } switch (var->bits_per_pixel) { case 8: var->red.length = 6; var->green.length = 6; var->blue.length = 6; ivideo.video_cmap_len = 256; break; case 16: var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; ivideo.video_cmap_len = 16; break; case 24: var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; ivideo.video_cmap_len = 16; break; case 32: var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; ivideo.video_cmap_len = 16; break; } inSISIDXREG(SISSR, 0x0A, sr_data); inSISIDXREG(SISCR, 0x06, cr_data); inSISIDXREG(SISCR, 0x07, cr_data2); VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) | ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) << 10); A = VT + 2; inSISIDXREG(SISCR, 0x12, cr_data); VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) | ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9); E = VDE + 1; inSISIDXREG(SISCR, 0x10, cr_data); VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) | ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7); F = VRS + 1 - E; inSISIDXREG(SISCR, 0x15, cr_data); inSISIDXREG(SISCR, 0x09, cr_data3); VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) | ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8); inSISIDXREG(SISCR, 0x16, cr_data); VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4); temp = VBE - ((E - 1) & 511); B = (temp > 0) ? temp : (temp + 512); inSISIDXREG(SISCR, 0x11, cr_data); VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); temp = VRE - ((E + F - 1) & 31); C = (temp > 0) ? temp : (temp + 32); D = B - F - C; var->yres = E;#ifndef SISFB_PAN var->yres_virtual = E;#endif /* TW: We have to report the physical dimension to the console! */ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { var->yres <<= 1;#ifndef SISFB_PAN var->yres_virtual <<= 1;#endif } /* TW end */ var->upper_margin = D; var->lower_margin = F; var->vsync_len = C; inSISIDXREG(SISSR, 0x0b, sr_data); inSISIDXREG(SISCR, 0x00, cr_data); HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8); A = HT + 5; inSISIDXREG(SISCR, 0x01, cr_data); HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6); E = HDE + 1; inSISIDXREG(SISCR, 0x04, cr_data); HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2); F = HRS - E - 3; inSISIDXREG(SISCR, 0x02, cr_data); HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4); inSISIDXREG(SISSR, 0x0c, sr_data); inSISIDXREG(SISCR, 0x03, cr_data); inSISIDXREG(SISCR, 0x15, cr_data2); HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) | ((u16) (sr_data & 0x03) << 6); HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); temp = HBE - ((E - 1) & 255); B = (temp > 0) ? temp : (temp + 256); temp = HRE - ((E + F + 3) & 63); C = (temp > 0) ? temp : (temp + 64); D = B - F - C;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -