📄 sis_main.c
字号:
return 0;}static voidsisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; struct display *display; struct display_switch *sw; struct fb_fix_screeninfo fix; long flags; display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp; sisfb_get_fix(&fix, con, info); display->var = *var; display->screen_base = (char *)ivideo->video_vbase; 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->can_soft_blank = 1; display->inverse = ivideo->sisfb_inverse; display->next_line = fix.line_length; save_flags(flags); switch(ivideo->video_bpp) {#ifdef FBCON_HAS_CFB8 case 8: sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8; break;#endif#ifdef FBCON_HAS_CFB16 case 16: sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16; display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16; break;#endif#ifdef FBCON_HAS_CFB32 case 32: sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32; display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32; break;#endif default: sw = &fbcon_dummy; break; } memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw)); display->dispsw = &ivideo->sisfb_sw; restore_flags(flags); if(ivideo->sisfb_ypan) { /* display->scrollmode = 0; */ } else { display->scrollmode = SCROLL_YREDRAW; ivideo->sisfb_sw.bmove = fbcon_redraw_bmove; }}static voidsisfb_do_install_cmap(int con, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; if(con != ivideo->currcon) return; if(fb_display[con].cmap.len) { fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info); } else { int size = sisfb_get_cmap_len(&fb_display[con].var); fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info); }}static intsisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; if(con == -1) { memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo)); } else { *var = fb_display[con].var; } if(ivideo->sisfb_fstn) { if(var->xres == 320 && var->yres == 480) var->yres = 240; } return 0;}static intsisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; unsigned int cols, rows; int err; fb_display[con].var.activate = FB_ACTIVATE_NOW; if(sisfb_do_set_var(var, con == ivideo->currcon, info)) { sisfb_crtc_to_var(ivideo, var); return -EINVAL; } sisfb_crtc_to_var(ivideo, var); sisfb_set_disp(con, var, info); if(info->changevar) { (*info->changevar)(con); } if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) { return err; } sisfb_do_install_cmap(con, info); cols = sisbios_mode[ivideo->sisfb_mode_idx].cols; rows = sisbios_mode[ivideo->sisfb_mode_idx].rows; #if 0 /* Why was this called here? */ vc_resize_con(rows, cols, fb_display[con].conp->vc_num); #endif return 0;}static intsisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; struct display *display; display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp; if(con == ivideo->currcon) { return fb_get_cmap(cmap, kspc, sis_getcolreg, info); } else if(display->cmap.len) { fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2); } else { int size = sisfb_get_cmap_len(&display->var); fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); } return 0;}static intsisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; struct display *display; int err, size; display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp; size = sisfb_get_cmap_len(&display->var); if(display->cmap.len != size) { err = fb_alloc_cmap(&display->cmap, size, 0); if(err) return err; } if(con == ivideo->currcon) { return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info); } else { fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1); } return 0;}static intsisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; int err; if(var->vmode & FB_VMODE_YWRAP) { if((var->yoffset < 0) || (var->yoffset >= fb_display[con].var.yres_virtual) || (var->xoffset)) { return -EINVAL; } } else { if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) || (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) { return -EINVAL; } } if(con == ivideo->currcon) { if((err = sisfb_pan_var(ivideo, var)) < 0) return err; } fb_display[con].var.xoffset = var->xoffset; fb_display[con].var.yoffset = var->yoffset; if(var->vmode & FB_VMODE_YWRAP) { fb_display[con].var.vmode |= FB_VMODE_YWRAP; } else { fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; } return 0;}static intsisfb_update_var(int con, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; return(sisfb_pan_var(ivideo, &fb_display[con].var));}static intsisfb_switch(int con, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; int cols, rows; if(fb_display[ivideo->currcon].cmap.len) { fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info); } fb_display[con].var.activate = FB_ACTIVATE_NOW; if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var, sizeof(struct fb_var_screeninfo))) { ivideo->currcon = con; return 1; } ivideo->currcon = con; sisfb_do_set_var(&fb_display[con].var, 1, info); sisfb_set_disp(con, &fb_display[con].var, info); sisfb_do_install_cmap(con, info); cols = sisbios_mode[ivideo->sisfb_mode_idx].cols; rows = sisbios_mode[ivideo->sisfb_mode_idx].rows; vc_resize_con(rows, cols, fb_display[con].conp->vc_num); sisfb_update_var(con, info); return 1;}static voidsisfb_blank(int blank, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; sisfb_myblank(ivideo, blank);}#endif/* ------------ FBDev related routines for 2.6 series ----------- */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static intsisfb_open(struct fb_info *info, int user){ return 0;}static intsisfb_release(struct fb_info *info, int user){ return 0;}static intsisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; if(regno >= sisfb_get_cmap_len(&info->var)) return 1; switch(info->var.bits_per_pixel) { case 8: outSISREG(SISDACA, regno); outSISREG(SISDACD, (red >> 10)); outSISREG(SISDACD, (green >> 10)); outSISREG(SISDACD, (blue >> 10)); if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) { outSISREG(SISDAC2A, regno); outSISREG(SISDAC2D, (red >> 8)); outSISREG(SISDAC2D, (green >> 8)); outSISREG(SISDAC2D, (blue >> 8)); } break; case 16: ((u32 *)(info->pseudo_palette))[regno] = ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); break; case 32: red >>= 8; green >>= 8; blue >>= 8; ((u32 *)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | (blue); break; } return 0;}static intsisfb_set_par(struct fb_info *info){ int err; if((err = sisfb_do_set_var(&info->var, 1, info))) { return err; } sisfb_get_fix(&info->fix, info->currcon, info); return 0;}static intsisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; unsigned int htotal = 0, vtotal = 0, myrateindex = 0; unsigned int drate = 0, hrate = 0, maxyres; int found_mode = 0; int refresh_rate, search_idx; BOOLEAN recalc_clock = FALSE; u32 pixclock; htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; vtotal = var->upper_margin + var->lower_margin + var->vsync_len; pixclock = var->pixclock; if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) { vtotal += var->yres; vtotal <<= 1; } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { vtotal += var->yres; vtotal <<= 2; } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { vtotal += var->yres; vtotal <<= 1; } else vtotal += var->yres; if(!(htotal) || !(vtotal)) { SISFAIL("sisfb: no valid timing data"); } search_idx = 0; while( (sisbios_mode[search_idx].mode_no[0] != 0) && (sisbios_mode[search_idx].xres <= var->xres) ) { if( (sisbios_mode[search_idx].xres == var->xres) && (sisbios_mode[search_idx].yres == var->yres) && (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) { if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) { found_mode = 1; break; } } search_idx++; } if(!found_mode) { search_idx = 0; while(sisbios_mode[search_idx].mode_no[0] != 0) { if( (var->xres <= sisbios_mode[search_idx].xres) && (var->yres <= sisbios_mode[search_idx].yres) && (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) { if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) { found_mode = 1; break; } } search_idx++; } if(found_mode) { printk(KERN_DEBUG "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n", var->xres, var->yres, var->bits_per_pixel, sisbios_mode[search_idx].xres, sisbios_mode[search_idx].yres, var->bits_per_pixel); var->xres = sisbios_mode[search_idx].xres; var->yres = sisbios_mode[search_idx].yres; } else { printk(KERN_ERR "sisfb: Failed to find supported mode near %dx%dx%d\n", var->xres, var->yres, var->bits_per_pixel); return -EINVAL; } } if( ((ivideo->vbflags & VB_LVDS) || /* Slave modes on LVDS and 301B-DH */ ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) && (var->bits_per_pixel == 8) ) { refresh_rate = 60; recalc_clock = TRUE; } else if( (ivideo->current_htotal == htotal) && /* x=x & y=y & c=c -> assume depth change */ (ivideo->current_vtotal == vtotal) && (ivideo->current_pixclock == pixclock) ) { drate = 1000000000 / pixclock; hrate = (drate * 1000) / htotal; refresh_rate = (unsigned int) (hrate * 2 / vtotal); } else if( ( (ivideo->current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */ (ivideo->current_vtotal != vtotal) ) && (ivideo->current_pixclock == var->pixclock) ) { if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) { refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]; } else if(ivideo->sisfb_parm_rate != -1) { /* Sic, sisfb_parm_rate - want to know originally desired rate here */ refresh_rate = ivideo->sisfb_parm_rate; } else { refresh_rate = 60; } recalc_clock = TRUE; } else if((pixclock) && (htotal) && (vtotal)) { drate = 1000000000 / pixclock; hrate = (drate * 1000) / htotal; refresh_rate = (unsigned int) (hrate * 2 / vtotal); } else if(ivideo->current_refresh_rate) { refresh_rate = ivideo->current_refresh_rate; recalc_clock = TRUE; } else { refresh_rate = 60; recalc_clock = TRUE; } myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx); /* Eventually recalculate timing and clock */ if(recalc_clock) { if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx; var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext, sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex)); sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext, sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex, var); if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { var->pixclock <<= 1; } } if(ivideo->sisfb_thismonitor.datavalid) { if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx, myrateindex, refresh_rate)) { printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); } } /* Adapt RGB settings */ sisfb_bpp_to_var(ivideo, var);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -