📄 sis_main.c
字号:
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;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) sisfb_get_fix(&info->fix, info->currcon, info);#else sisfb_get_fix(&info->fix, -1, info);#endif 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, tidx; 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((tidx = sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags)) > 0) { found_mode = 1; search_idx = tidx; 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((tidx = sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags)) > 0) { found_mode = 1; search_idx = tidx; 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->vbflags2 & VB2_LVDS) || ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) && (var->bits_per_pixel == 8) ) { /* Slave modes on LVDS and 301B-DH */ refresh_rate = 60; recalc_clock = TRUE; } else if( (ivideo->current_htotal == htotal) && (ivideo->current_vtotal == vtotal) && (ivideo->current_pixclock == pixclock) ) { /* x=x & y=y & c=c -> assume depth change */ drate = 1000000000 / pixclock; hrate = (drate * 1000) / htotal; refresh_rate = (unsigned int) (hrate * 2 / vtotal); } else if( ( (ivideo->current_htotal != htotal) || (ivideo->current_vtotal != vtotal) ) && (ivideo->current_pixclock == var->pixclock) ) { /* x!=x | y!=y & c=c -> invalid 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, sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex)); sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, 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); /* Sanity check for offsets */ if(var->xoffset < 0) var->xoffset = 0; if(var->yoffset < 0) var->yoffset = 0; if(var->xres > var->xres_virtual) var->xres_virtual = var->xres; if(ivideo->sisfb_ypan) { maxyres = sisfb_calc_maxyres(ivideo, var); if(ivideo->sisfb_max) { var->yres_virtual = maxyres; } else { if(var->yres_virtual > maxyres) { var->yres_virtual = maxyres; } } if(var->yres_virtual <= var->yres) { var->yres_virtual = var->yres; } } else { if(var->yres != var->yres_virtual) { var->yres_virtual = var->yres; } var->xoffset = 0; var->yoffset = 0; } /* Truncate offsets to maximum if too high */ if(var->xoffset > var->xres_virtual - var->xres) { var->xoffset = var->xres_virtual - var->xres - 1; } if(var->yoffset > var->yres_virtual - var->yres) { var->yoffset = var->yres_virtual - var->yres - 1; } /* Set everything else to 0 */ var->red.msb_right = var->green.msb_right = var->blue.msb_right = var->transp.offset = var->transp.length = var->transp.msb_right = 0; return 0;}static intsisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; int err; if(var->xoffset > (var->xres_virtual - var->xres)) return -EINVAL; if(var->yoffset > (var->yres_virtual - var->yres)) return -EINVAL; if(var->vmode & FB_VMODE_YWRAP) return -EINVAL; if(var->xoffset + info->var.xres > info->var.xres_virtual || var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; if((err = sisfb_pan_var(ivideo, var)) < 0) return err; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; return 0;}static intsisfb_blank(int blank, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; return sisfb_myblank(ivideo, blank);}#endif/* ----------- FBDev related routines for all series ---------- */static intsisfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg,#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) int con,#endif struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; struct sis_memreq sismemreq; struct fb_vblank sisvbblank; u32 gpu32 = 0;#ifndef __user#define __user#endif u32 __user *argp = (u32 __user *)arg; switch(cmd) { case FBIO_ALLOC: if(!capable(CAP_SYS_RAWIO)) return -EPERM; if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq))) return -EFAULT; sis_malloc(&sismemreq); if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) { sis_free((u32)sismemreq.offset); return -EFAULT; } break; case FBIO_FREE: if(!capable(CAP_SYS_RAWIO)) return -EPERM; if(get_user(gpu32, argp)) return -EFAULT; sis_free(gpu32); break; case FBIOGET_VBLANK: sisvbblank.count = 0; sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount); if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank))) return -EFAULT; break; case SISFB_GET_INFO_SIZE: return put_user(sizeof(struct sisfb_info), argp); case SISFB_GET_INFO_OLD: if(ivideo->warncount++ < 10) printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); case SISFB_GET_INFO: /* For communication with X driver */ ivideo->sisfb_infoblock.sisfb_id = SISFB_ID; ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR; ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR; ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL; ivideo->sisfb_infoblock.chip_id = ivideo->chip_id; ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor; ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024; ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024; if(ivideo->modechanged) { ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no; } else { ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange; } ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps; ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024; ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus; ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot; ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc; ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc; ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca; ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda; ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags; ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags; ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler; ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT; ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0; ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0; ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30; ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31; ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32; ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33; ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32); ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32); ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024; ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset; ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN; ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN; ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2; ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0; ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0; ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0; if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock, sizeof(ivideo->sisfb_infoblock))) return -EFAULT; break; case SISFB_GET_VBRSTATUS_OLD: if(ivideo->warncount++ < 10) printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); case SISFB_GET_VBRSTATUS: if(sisfb_CheckVBRetrace(ivideo)) return put_user((u32)1, argp); else return put_user((u32)0, argp); case SISFB_GET_AUTOMAXIMIZE_OLD: if(ivideo->warncount++ < 10) printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); case SISFB_GET_AUTOMAXIMIZE: if(ivideo->sisfb_max) return put_user((u32)1, argp); else return put_user((u32)0, argp); case SISFB_SET_AUTOMAXIMIZE_OLD: if(ivideo->warncount++ < 10) printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); case SISFB_SET_AUTOMAXIMIZE: if(get_user(gpu32, argp)) return -EFAULT; ivideo->sisfb_max = (gpu32) ? 1 : 0; break; case SISFB_SET_TVPOSOFFSET: if(get_user(gpu32, argp)) return -EFAULT; sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32); sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32); break; case SISFB_GET_TVPOSOFFSET: return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)), argp); case SISFB_COMMAND: if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg, sizeof(struct sisfb_cmd))) return -EFAULT; sisfb_handle_command(ivideo, &ivideo->sisfb_command); if(copy_to_user((void __user *)arg, &ivideo->sisfb_command, sizeof(struct sisfb_cmd))) return -EFAULT; break; case SISFB_SET_LOCK: if(get_user(gpu32, argp)) return -EFAULT; ivideo->sisfblocked = (gpu32) ? 1 : 0; break; default:#ifdef SIS_NEW_CONFIG_COMPAT return -ENOIOCTLCMD;#else return -EINVAL;#endif } return 0;}#ifdef SIS_NEW_CONFIG_COMPATstatic longsisfb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg, struct fb_info *info){ int ret; lock_kernel(); ret = sisfb_ioctl(NULL, f, cmd, arg, info); unlock_kernel(); return ret;}#endifstatic int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -