📄 sis_main.c
字号:
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); /* 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; sisfb_info x; u32 gpu32 = 0; static int count = 0; u32 __user *argp = (u32 __user *) arg; switch (cmd) { case FBIO_ALLOC: if(!capable(CAP_SYS_RAWIO)) { return -EPERM; } if(copy_from_user(&sismemreq, argp, sizeof(sismemreq))) { return -EFAULT; } sis_malloc(&sismemreq); if(copy_to_user(argp, &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(argp, &sisvbblank, sizeof(sisvbblank))) { return -EFAULT; } break; case SISFB_GET_INFO_SIZE: return put_user(sizeof(sisfb_info), argp); case SISFB_GET_INFO_OLD: if(++count < 50) { printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); } case SISFB_GET_INFO: /* For communication with X driver */ x.sisfb_id = SISFB_ID; x.sisfb_version = VER_MAJOR; x.sisfb_revision = VER_MINOR; x.sisfb_patchlevel = VER_LEVEL; x.chip_id = ivideo->chip_id; x.memory = ivideo->video_size / 1024; x.heapstart = ivideo->heapstart / 1024; if(ivideo->modechanged) { x.fbvidmode = ivideo->mode_no; } else { x.fbvidmode = ivideo->modeprechange; } x.sisfb_caps = ivideo->caps; x.sisfb_tqlen = 512; /* yet fixed */ x.sisfb_pcibus = ivideo->pcibus; x.sisfb_pcislot = ivideo->pcislot; x.sisfb_pcifunc = ivideo->pcifunc; x.sisfb_lcdpdc = ivideo->detectedpdc; x.sisfb_lcdpdca = ivideo->detectedpdca; x.sisfb_lcda = ivideo->detectedlcda; x.sisfb_vbflags = ivideo->vbflags; x.sisfb_currentvbflags = ivideo->currentvbflags; x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler; x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT; x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0; x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0; x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30; x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31; x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32; x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33; x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32); x.sisfb_tvypos = (u16)(ivideo->tvypos + 32); if(copy_to_user(argp, &x, sizeof(x))) { return -EFAULT; } break; case SISFB_GET_VBRSTATUS_OLD: if(++count < 50) { 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(++count < 50) { 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(++count < 50) { printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n"); } case SISFB_SET_AUTOMAXIMIZE: if(copy_from_user(&gpu32, argp, sizeof(gpu32))) { return -EFAULT; } ivideo->sisfb_max = (gpu32) ? 1 : 0; break; case SISFB_SET_TVPOSOFFSET: if(copy_from_user(&gpu32, argp, sizeof(gpu32))) { 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_SET_LOCK: if(copy_from_user(&gpu32, argp, sizeof(gpu32))) { return -EFAULT; } ivideo->sisfblocked = (gpu32) ? 1 : 0; break; default: return -EINVAL; } return 0;}static intsisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ struct sis_video_info *ivideo = (struct sis_video_info *)info->par; memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, ivideo->myid); fix->smem_start = ivideo->video_base; fix->smem_len = ivideo->sisfb_mem; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; fix->xpanstep = 1; fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0; fix->ywrapstep = 0; fix->line_length = ivideo->video_linelength; fix->mmio_start = ivideo->mmio_base; fix->mmio_len = ivideo->mmio_size; if(ivideo->sisvga_engine == SIS_300_VGA) { fix->accel = FB_ACCEL_SIS_GLAMOUR; } else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) { fix->accel = FB_ACCEL_SIS_XABRE; } else { fix->accel = FB_ACCEL_SIS_GLAMOUR_2; } return 0;}/* ---------------- fb_ops structures ----------------- */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)static struct fb_ops sisfb_ops = { .owner = THIS_MODULE, .fb_get_fix = sisfb_get_fix, .fb_get_var = sisfb_get_var, .fb_set_var = sisfb_set_var, .fb_get_cmap = sisfb_get_cmap, .fb_set_cmap = sisfb_set_cmap, .fb_pan_display = sisfb_pan_display, .fb_ioctl = sisfb_ioctl};#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static struct fb_ops sisfb_ops = { .owner = THIS_MODULE, .fb_open = sisfb_open, .fb_release = sisfb_release, .fb_check_var = sisfb_check_var, .fb_set_par = sisfb_set_par, .fb_setcolreg = sisfb_setcolreg, .fb_pan_display = sisfb_pan_display, .fb_blank = sisfb_blank, .fb_fillrect = fbcon_sis_fillrect, .fb_copyarea = fbcon_sis_copyarea, .fb_imageblit = cfb_imageblit, .fb_cursor = soft_cursor, .fb_sync = fbcon_sis_sync, .fb_ioctl = sisfb_ioctl};#endif/* ---------------- Chip generation dependent routines ---------------- */static struct pci_dev * sisfb_get_northbridge(int basechipid){ struct pci_dev *pdev = NULL; int nbridgenum, nbridgeidx, i; const unsigned short nbridgeids[] = { PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */ PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */ PCI_DEVICE_ID_SI_730, PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */ PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */ PCI_DEVICE_ID_SI_651, PCI_DEVICE_ID_SI_740, PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760 VGA */ PCI_DEVICE_ID_SI_741, PCI_DEVICE_ID_SI_660, PCI_DEVICE_ID_SI_760 }; switch(basechipid) {#ifdef CONFIG_FB_SIS_300 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break; case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;#endif#ifdef CONFIG_FB_SIS_315 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break; case SIS_650: nbridgeidx = 4; nbridgenum = 3; break; case SIS_660: nbridgeidx = 7; nbridgenum = 4; break;#endif default: return NULL; } for(i = 0; i < nbridgenum; i++) { if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break; } return pdev;}static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo){#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315) u8 reg;#endif ivideo->video_size = 0; switch(ivideo->chip) {#ifdef CONFIG_FB_SIS_300 case SIS_300: inSISIDXREG(SISSR, 0x14, reg); ivideo->video_size = ((reg & 0x3F) + 1) << 20; break; case SIS_540: case SIS_630: case SIS_730: if(!ivideo->nbridge) return -1; pci_read_config_byte(ivideo->nbridge, 0x63, ®); ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21); break;#endif#ifdef CONFIG_FB_SIS_315 case SIS_315H: case SIS_315PRO: case SIS_315: inSISIDXREG(SISSR, 0x14, reg); ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; switch((reg >> 2) & 0x03) { case 0x01: case 0x03: ivideo->video_size <<= 1; break; case 0x02: ivideo->video_size += (ivideo->video_size/2); } break; case SIS_330: inSISIDXREG(SISSR, 0x14, reg); ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; if(reg & 0x0c) ivideo->video_size <<= 1; break; case SIS_550: case SIS_650: case SIS_740: inSISIDXREG(SISSR, 0x14, reg); ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20; break; case SIS_661: case SIS_741: inSISIDXREG(SISCR, 0x79, reg); ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20; break; case SIS_660: case SIS_760: inSISIDXREG(SISCR, 0x79, reg); reg = (reg & 0xf0) >> 4; if(reg) ivideo->video_size = (1 << reg) << 20; inSISIDXREG(SISCR, 0x78, reg); reg &= 0x30; if(reg) { if(reg == 0x10) ivideo->video_size += (32 << 20); else ivideo->video_size += (64 << 20); } break;#endif default: return -1; } return 0;}/* -------------- video bridge device detection --------------- */static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo){ u8 cr32, temp;#ifdef CONF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -