📄 sis_main.c
字号:
{ unsigned int htotal = 0, vtotal = 0, myrateindex = 0; double drate = 0, hrate = 0; 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) && (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(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) { 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(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_301BDH) && (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 = 1E12 / pixclock; hrate = drate / htotal; refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); } else if( ( (ivideo.current_htotal != htotal) || /* x!=x | y!=y & c=c -> invalid pixclock */ (ivideo.current_vtotal != vtotal) ) && (ivideo.current_pixclock == var->pixclock) ) { if(sisfb_lastrates[sisbios_mode[search_idx].mode_no]) { refresh_rate = sisfb_lastrates[sisbios_mode[search_idx].mode_no]; } else if(sisfb_parm_rate != -1) { refresh_rate = sisfb_parm_rate; } else { refresh_rate = 60; } recalc_clock = TRUE; } else if((pixclock) && (htotal) && (vtotal)) { drate = 1E12 / pixclock; hrate = drate / htotal; refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); } else if(ivideo.current_refresh_rate) { refresh_rate = ivideo.current_refresh_rate; recalc_clock = TRUE; } else { refresh_rate = 60; recalc_clock = TRUE; } /* Eventually recalculate timing and clock */ if(recalc_clock) { myrateindex = sisfb_search_refresh_rate(refresh_rate, search_idx); if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx; var->pixclock = (u32) (1E12 / sisfb_mode_rate_to_dclock(&SiS_Pr, &sishw_ext, sisbios_mode[search_idx].mode_no, myrateindex)); sisfb_mode_rate_to_ddata(&SiS_Pr, &sishw_ext, sisbios_mode[search_idx].mode_no, myrateindex, &var->left_margin, &var->right_margin, &var->upper_margin, &var->lower_margin, &var->hsync_len, &var->vsync_len, &var->sync, &var->vmode); if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { var->pixclock <<= 1; } } /* Adapt RGB settings */ sisfb_bpp_to_var(var); /* Sanity check for offsets */ if (var->xoffset < 0) var->xoffset = 0; if (var->yoffset < 0) var->yoffset = 0; /* Horiz-panning not supported */ if(var->xres != var->xres_virtual) var->xres_virtual = var->xres; if(sisfb_ypan) { /* TW: Now patch yres_virtual if we use panning */ /* *** May I do this? *** */ var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3)); if(var->yres_virtual <= var->yres) { /* TW: Paranoia check */ 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 int sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info){ 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) { if (var->yoffset < 0 || var->yoffset >= info->var.yres_virtual || var->xoffset) return -EINVAL; } else { 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(var)) < 0) return err; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) info->var.vmode |= FB_VMODE_YWRAP; else info->var.vmode &= ~FB_VMODE_YWRAP; return 0;}static int sisfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma){ unsigned long start; unsigned long off; u32 len, mmio_off; if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; start = (unsigned long) ivideo.video_base; len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);#if 0 if (off >= len) { off -= len;#endif /* By Jake Page: Treat mmap request with offset beyond heapstart * as request for mapping the mmio area */ mmio_off = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.heapstart); if(off >= mmio_off) { off -= mmio_off; if(info->var.accel_flags) return -EINVAL; start = (unsigned long) ivideo.mmio_base; len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size); } start &= PAGE_MASK; if((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; off += start; vma->vm_pgoff = off >> PAGE_SHIFT; vma->vm_flags |= VM_IO; /* by Jake Page; is that really needed? */#if defined(__i386__) || defined(__x86_64__) if (boot_cpu_data.x86 > 3) pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;#endif if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0;}static int sisfb_blank(int blank, struct fb_info *info){ u8 reg; if(sisfb_bridgeisslave()) return 1; inSISIDXREG(SISCR, 0x17, reg); if(blank > 0) reg &= 0x7f; else reg |= 0x80; outSISIDXREG(SISCR, 0x17, reg); outSISIDXREG(SISSR, 0x00, 0x01); /* Synchronous Reset */ outSISIDXREG(SISSR, 0x00, 0x03); /* End Reset */ return(0);}#endif/* ----------- FBDev related routines for all series ---------- */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static int sisfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, struct fb_info *info)#elsestatic int sisfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info)#endif{ struct sis_memreq req; struct ap_data ap; unsigned long a; switch (cmd) { case FBIO_ALLOC: if (!capable(CAP_SYS_RAWIO)) return -EPERM; if (copy_from_user(&req, (void *)arg, sizeof(req))) return -EFAULT; sis_malloc(&req); if (copy_to_user((void *)arg, &req, sizeof(req))) return -EFAULT; break; case FBIO_FREE: if (!capable(CAP_SYS_RAWIO)) return -EPERM; if(get_user(a, (unsigned long *) arg)) return -EFAULT; sis_free(a); break;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) case FBIOGET_GLYPH: sis_get_glyph(info,(SIS_GLYINFO *) arg); break; case FBIOPUT_MODEINFO: { struct mode_info x; if(copy_from_user(&x, (void *)arg, sizeof(struct mode_info))) return -EFAULT; ivideo.video_bpp = x.bpp; ivideo.video_width = x.xres; ivideo.video_height = x.yres; ivideo.video_vwidth = x.v_xres; ivideo.video_vheight = x.v_yres; ivideo.org_x = x.org_x; ivideo.org_y = x.org_y; ivideo.refresh_rate = x.vrate; ivideo.video_linelength = ivideo.video_vwidth * (ivideo.video_bpp >> 3); sisfb_set_vparms(); break; }#endif case FBIOGET_HWCINFO: { unsigned long *hwc_offset = (unsigned long *) arg; if (sisfb_caps & HW_CURSOR_CAP) return put_user(sisfb_hwcursor_vbase - (unsigned long) ivideo.video_vbase, hwc_offset); else return put_user(0, hwc_offset); } case FBIOGET_DISPINFO: if(copy_from_user(&ap, (void *)arg, sizeof(struct ap_data))) return -EFAULT; sis_dispinfo(&ap); if(copy_to_user((void *)arg, &ap, sizeof(struct ap_data))) return -EFAULT; break; case SISFB_GET_INFO: /* TW: New for communication with X driver */ { sisfb_info x; 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; x.fbvidmode = sisfb_mode_no; x.sisfb_caps = sisfb_caps; x.sisfb_tqlen = 512; /* yet unused */ x.sisfb_pcibus = ivideo.pcibus; x.sisfb_pcislot = ivideo.pcislot; x.sisfb_pcifunc = ivideo.pcifunc; x.sisfb_lcdpdc = sisfb_detectedpdc; x.sisfb_lcda = sisfb_detectedlcda; x.sisfb_vbflags = ivideo.vbflags; x.sisfb_currentvbflags = ivideo.currentvbflags; if(copy_to_user((void *)arg, &x, sizeof(sisfb_info))) return -EFAULT; break; } case SISFB_GET_VBRSTATUS: { unsigned long *vbrstatus = (unsigned long *) arg; if(sisfb_CheckVBRetrace()) return put_user(1, vbrstatus); else return put_user(0, vbrstatus); } default: return -EINVAL; } return 0;}static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ memset(fix, 0, sizeof(struct fb_fix_screeninfo));#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) strcpy(fix->id, sis_fb_info.modename);#else strcpy(fix->id, myid);#endif fix->smem_start = ivideo.video_base; if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) { if (ivideo.video_size > 0x1000000) { fix->smem_len = 0xc00000; } else if (ivideo.video_size > 0x800000) fix->smem_len = 0x800000; else fix->smem_len = 0x400000; } else fix->smem_len = sisfb_mem * 1024; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; if(ivideo.video_bpp == 8) fix->visual = FB_VISUAL_PSEUDOCOLOR; else fix->visual = FB_VISUAL_TRUECOLOR; fix->xpanstep = 0; if(sisfb_ypan) fix->ypanstep = 1; fix->ywrapstep = 0; fix->line_length = ivideo.video_linelength; fix->mmio_start = ivideo.mmio_base; fix->mmio_len = sisfb_mmio_size; if(sisvga_engine == SIS_300_VGA) fix->accel = FB_ACCEL_SIS_GLAMOUR; else if(ivideo.chip == SIS_330) fix->accel = FB_ACCEL_SIS_XABRE; else fix->accel = FB_ACCEL_SIS_GLAMOUR_2; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) fix->reserved[0] = ivideo.video_size & 0xFFFF; fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF; fix->reserved[2] = sisfb_caps;#endif 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, fb_mmap: sisfb_mmap,};#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, .fb_mmap = sisfb_mmap,};#endif/* ---------------- Chip generation dependent routines ---------------- */#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */static int sisfb_get_dram_size_300(void){ struct pci_dev *pdev = NULL; int pdev_valid = 0; u8 pci_data, reg; u16 nbridge_id; switch (ivideo.chip) { case SIS_540: nbridge_id = PCI_DEVICE_ID_SI_540; break; case SIS_630: nbridge_id = PCI_DEVICE_ID_SI_630; break; case SIS_730: nbridge_id = PCI_DEVICE_ID_SI_730; break; default: nbridge_id = 0; break; } if (nbridge_id == 0) { /* 300 */ inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE,reg); ivideo.video_size = ((unsigned int) ((reg & SIS_DRAM_SIZE_MASK) + 1) << 20); } else { /* 540, 630, 730 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -