📄 sis_main.c
字号:
var->xres = var->xres_virtual = E * 8; var->left_margin = D * 8; var->right_margin = F * 8; var->hsync_len = C * 8; var->activate = FB_ACTIVATE_NOW; var->sync = 0; mr_data = inSISREG(SISMISCR);#if 0 mr_data = vgarb(0x1C);#endif if (mr_data & 0x80) var->sync &= ~FB_SYNC_VERT_HIGH_ACT; else var->sync |= FB_SYNC_VERT_HIGH_ACT; if (mr_data & 0x40) var->sync &= ~FB_SYNC_HOR_HIGH_ACT; else var->sync |= FB_SYNC_HOR_HIGH_ACT; VT += 2; VT <<= 1; HT = (HT + 5) * 8; hrate = (double) ivideo.refresh_rate * (double) VT / 2; drate = hrate * HT; var->pixclock = (u32) (1E12 / drate);#ifdef SISFB_PAN if(sisfb_ypan) { var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3)); if(var->yres_virtual <= var->yres) { var->yres_virtual = var->yres; } } else#endif var->yres_virtual = var->yres; TWDEBUG("end of crtc_to_var");}/* ------------------ Public Routines -------------------------------- *//* -------- functions only for for 2.4 series ------- */#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)static int sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)#define currcon info->currcon#endif int err; unsigned int cols, rows; fb_display[con].var.activate = FB_ACTIVATE_NOW; if(sisfb_do_set_var(var, con == currcon, info)) { sisfb_crtc_to_var(var); return -EINVAL; } sisfb_crtc_to_var(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[sisfb_mode_idx].cols; rows = sisbios_mode[sisfb_mode_idx].rows; vc_resize_con(rows, cols, fb_display[con].conp->vc_num); return 0;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)#undef currcon#endif}static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)#define currcon info->currcon#endif if (con == currcon) return fb_get_cmap(cmap, kspc, sis_getcolreg, info); else if (fb_display[con].cmap.len) fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else fb_copy_cmap(fb_default_cmap(ivideo.video_cmap_len), cmap, kspc ? 0 : 2); return 0;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)#undef currcon#endif}static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ int err; if (!fb_display[con].cmap.len) { err = fb_alloc_cmap(&fb_display[con].cmap, ivideo.video_cmap_len, 0); if (err) return err; }#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23) if (con == info->currcon) return fb_set_cmap(cmap, kspc, info);#else if (con == currcon) return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);#endif else fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0;}#endif/* -------- functions only for 2.5 series ------- */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)static int sisfb_set_par(struct fb_info *info){ int err; TWDEBUG("inside set_par\n"); if((err = sisfb_do_set_var(&info->var, 1, info))) return err; sisfb_get_fix(&info->fix, info->currcon, info); TWDEBUG("end of set_par"); return 0;}static int sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ unsigned int htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; unsigned int vtotal = 0; double drate = 0, hrate = 0; int found_mode = 0; int refresh_rate, search_idx; TWDEBUG("Inside check_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)) { SISFAIL("sisfb: no valid timing data"); } drate = 1E12 / var->pixclock; hrate = drate / htotal; 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)) refresh_rate = 60; 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)) { found_mode = 1; break; } search_idx++; } /* TW: TODO: Check the refresh rate */ if(found_mode) search_idx = sisfb_validate_mode(search_idx); else SISFAIL("sisfb: no valid mode"); if(sisfb_mode_idx < 0) { SISFAIL("sisfb: mode not supported"); } /* TW: Horiz-panning not supported */ if(var->xres != var->xres_virtual) var->xres_virtual = var->xres; if(!sisfb_ypan) { if(var->yres != var->yres_virtual) var->yres_virtual = var->yres; } else { /* 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; } } TWDEBUG("end of check_var"); return 0;}#endif/* -------- functions for all series ------- */static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ TWDEBUG("inside get_fix"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, sis_fb_info.modename); fix->smem_start = ivideo.video_base; /* TW */ 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 = video_type; fix->type_aux = 0; if(ivideo.video_bpp == 8) fix->visual = FB_VISUAL_PSEUDOCOLOR; else fix->visual = FB_VISUAL_TRUECOLOR; fix->xpanstep = 0;#ifdef SISFB_PAN if(sisfb_ypan) fix->ypanstep = 1;#endif fix->ywrapstep = 0; fix->line_length = ivideo.video_linelength; fix->mmio_start = ivideo.mmio_base; fix->mmio_len = sisfb_mmio_size; fix->accel = FB_ACCEL_SIS_GLAMOUR; fix->reserved[0] = ivideo.video_size & 0xFFFF; fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF; fix->reserved[2] = sisfb_caps; TWDEBUG("end of get_fix"); return 0;}static int sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ TWDEBUG("inside get_var"); if(con == -1) memcpy(var, &default_var, sizeof(struct fb_var_screeninfo)); else *var = fb_display[con].var; /* JennyLee 2001126: for FSTN */ if (var->xres == 320 && var->yres == 480) var->yres = 240; /* ~JennyLee */ TWDEBUG("end of get_var"); return 0;}#ifdef SISFB_PANstatic int sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info){#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)#define currcon info->currcon#endif TWDEBUG("inside pan_display"); 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 == currcon) sisfb_pan_var(var); 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; TWDEBUG("end of pan_display"); return 0;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)#undef currcon#endif}#endifstatic int sisfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info){ TWDEBUG("inside ioctl"); switch (cmd) { case FBIO_ALLOC: if (!capable(CAP_SYS_RAWIO)) return -EPERM; sis_malloc((struct sis_memreq *) arg); break; case FBIO_FREE: if (!capable(CAP_SYS_RAWIO)) return -EPERM; sis_free(*(unsigned long *) arg); break; case FBIOGET_GLYPH: sis_get_glyph(info,(SIS_GLYINFO *) arg); break; case FBIOGET_HWCINFO: { unsigned long *hwc_offset = (unsigned long *) arg; if (sisfb_caps & HW_CURSOR_CAP) *hwc_offset = sisfb_hwcursor_vbase - (unsigned long) ivideo.video_vbase; else *hwc_offset = 0; break; } case FBIOPUT_MODEINFO: { struct mode_info *x = (struct mode_info *)arg; 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_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; } break; } case FBIOGET_DISPINFO: sis_dispinfo((struct ap_data *)arg); break; case SISFB_GET_INFO: /* TW: New for communication with X driver */ { sisfb_info *x = (sisfb_info *)arg; 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 */ break; } default: return -EINVAL; } TWDEBUG("end of ioctl"); return 0;}static int sisfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma){#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)#define currcon info->currcon#endif struct fb_var_screeninfo var; unsigned long start; unsigned long off; u32 len; TWDEBUG("inside mmap"); 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 (off >= len) { off -= len; sisfb_get_var(&var, currcon, info); if(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;#if defined(__i386__) || defined(__x86_64__) if (boot_cpu_data.x86 > 3) pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot))#else /* TW: 2.5 API */ if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot))#endif return -EAGAIN; TWDEBUG("end of mmap"); return 0;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)#undef currcon#endif}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)static struct fb_ops sisfb_ops = { .owner = THIS_MODULE, .fb_set_var = gen_set_var, .fb_get_cmap = gen_get_cmap, .fb_set_cmap = gen_set_cmap, .fb_check_var = sisfb_check_var, .fb_set_par = sisfb_set_par, .fb_setcolreg = sisfb_setcolreg, .fb_blank = sisfb_blank,#ifdef SISFB_PAN .fb_pan_display = sisfb_pan_display,#endif .fb_fillrect = fbcon_sis_fillrect, .fb_copyarea = fbcon_sis_copyarea, .fb_imageblit = my_cfb_imageblit, .fb_ioctl = sisfb_ioctl, .fb_mmap = sisfb_mmap,};#endif#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)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,#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23) fb_setcolreg: sisfb_setcolreg, fb_blank: sisfb_blank,#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -