sis_main.c
来自「讲述linux的初始化过程」· C语言 代码 · 共 2,375 行 · 第 1/4 页
C
2,375 行
struct display *display; struct display_switch *sw; u32 flags; if (con >= 0) display = &fb_display[con]; else display = &disp; /* used during initialization */ sisfb_get_fix(&fix, con, 0); display->screen_base = 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->next_line = fix.line_length; /*display->can_soft_blank = 1; */ display->can_soft_blank = 0; display->inverse = inverse; display->var = *var; save_flags(flags); switch (ivideo.video_bpp) {#ifdef FBCON_HAS_CFB8 case 8: sw = &fbcon_cfb8; break;#endif#ifdef FBCON_HAS_CFB16 case 15: case 16: sw = &fbcon_cfb16; display->dispsw_data = fbcon_cmap.cfb16; break;#endif#ifdef FBCON_HAS_CFB24 case 24: sw = &fbcon_cfb24; display->dispsw_data = fbcon_cmap.cfb24; break;#endif#ifdef FBCON_HAS_CFB32 case 32: sw = &fbcon_cfb32; display->dispsw_data = fbcon_cmap.cfb32; break;#endif default: sw = &fbcon_dummy; return; } memcpy(&sisfb_sw, sw, sizeof(*sw)); display->dispsw = &sisfb_sw; restore_flags(flags); display->scrollmode = SCROLL_YREDRAW; sisfb_sw.bmove = fbcon_redraw_bmove;}/* * Read a single color register and split it into colors/transparent. * Return != 0 for invalid regno. */static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, unsigned *transp, struct fb_info *fb_info){ if (regno >= video_cmap_len) return 1; *red = palette[regno].red; *green = palette[regno].green; *blue = palette[regno].blue; *transp = 0; return 0;}/* * Set a single color register. The values supplied are already * rounded down to the hardware's capabilities (according to the * entries in the var structure). Return != 0 for invalid regno. */static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fb_info){ if (regno >= video_cmap_len) return 1; palette[regno].red = red; palette[regno].green = green; palette[regno].blue = blue; switch (ivideo.video_bpp) {#ifdef FBCON_HAS_CFB8 case 8: vgawb(DAC_ADR, regno); vgawb(DAC_DATA, red >> 10); vgawb(DAC_DATA, green >> 10); vgawb(DAC_DATA, blue >> 10); if(uDispType & MASK_DISPTYPE_DISP2) { /* VB connected */ vgawb(DAC2_ADR, regno); vgawb(DAC2_DATA, red >> 8); vgawb(DAC2_DATA, green >> 8); vgawb(DAC2_DATA, blue >> 8); } break;#endif#ifdef FBCON_HAS_CFB16 case 15: case 16: fbcon_cmap.cfb16[regno] = ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); break;#endif#ifdef FBCON_HAS_CFB24 case 24: red >>= 8; green >>= 8; blue >>= 8; fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | (blue); break;#endif#ifdef FBCON_HAS_CFB32 case 32: red >>= 8; green >>= 8; blue >>= 8; fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue); break;#endif } return 0;}static void do_install_cmap(int con, struct fb_info *info){ if (con != currcon) return; if (fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info); else fb_set_cmap(fb_default_cmap(video_cmap_len), 1, sis_setcolreg, info);}static int do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info){ unsigned int htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len; unsigned int vtotal = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; double drate = 0, hrate = 0; int found_mode = 0; int old_mode; if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) vtotal <<= 1; else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) vtotal <<= 2; else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) var->yres <<= 1; if (!htotal || !vtotal) { DPRINTK("Invalid 'var' Information!\n"); return 1; } drate = 1E12 / var->pixclock; hrate = drate / htotal; ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); old_mode = mode_idx; mode_idx = 0; while ((sisbios_mode[mode_idx].mode_no != 0) && (sisbios_mode[mode_idx].xres <= var->xres)) { if ((sisbios_mode[mode_idx].xres == var->xres) && (sisbios_mode[mode_idx].yres == var->yres) && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) { mode_no = sisbios_mode[mode_idx].mode_no; found_mode = 1; break; } mode_idx++; } if(found_mode) { switch(uDispType & MASK_DISPTYPE_DISP2) { case MASK_DISPTYPE_LCD: switch(HwExt.usLCDType) { case LCD1024: if(var->xres > 1024) found_mode = 0; break; case LCD1280: if(var->xres > 1280) found_mode = 0; break; case LCD2048: if(var->xres > 2048) found_mode = 0; break; case LCD1920: if(var->xres > 1920) found_mode = 0; break; case LCD1600: if(var->xres > 1600) found_mode = 0; break; case LCD800: if(var->xres > 800) found_mode = 0; break; case LCD640: if(var->xres > 640) found_mode = 0; break; default: found_mode = 0; } if(var->xres == 720) /* mode only for TV */ found_mode = 0; break; case MASK_DISPTYPE_TV: switch(var->xres) { case 800: case 640: break; case 720: if(ivideo.TV_type == TVMODE_NTSC) { if(sisbios_mode[mode_idx].yres != 480) found_mode = 0; } else if(ivideo.TV_type == TVMODE_PAL) { if(sisbios_mode[mode_idx].yres != 576) found_mode = 0; } break; default: /* illegal mode */ found_mode = 0; } break; } } if (!found_mode) { printk("sisfb does not support mode %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel); mode_idx = old_mode; return 1; } if (search_refresh_rate(ivideo.refresh_rate) == 0) { /* not supported rate */ rate_idx = sisbios_mode[mode_idx].rate_idx; ivideo.refresh_rate = 60; } if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) { pre_setmode(); if (SiSSetMode(&HwExt, mode_no)) { DPRINTK("sisfb: set mode[0x%x]: failed\n", mode_no); return 1; } post_setmode(); printk(KERN_DEBUG "Current Mode: %dx%dx%d-%d \n", sisbios_mode[mode_idx].xres, sisbios_mode[mode_idx].yres, sisbios_mode[mode_idx].bpp, ivideo.refresh_rate); ivideo.video_bpp = sisbios_mode[mode_idx].bpp; ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres; ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres; ivideo.org_x = ivideo.org_y = 0; video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3); DPRINTK("Current Mode: %dx%d-%d line_length=%d\n", ivideo.video_width, ivideo.video_height, ivideo.video_bpp, video_linelength); } return 0;}/* ---------------------- Draw Funtions ----------------------------- */static void sis_get_glyph(struct GlyInfo *gly){ struct display *p = &fb_display[currcon]; u16 c; u8 *cdat; int widthb; u8 *gbuf = gly->gmask; int size; gly->fontheight = fontheight(p); gly->fontwidth = fontwidth(p); widthb = (fontwidth(p) + 7) / 8; c = gly->ch & p->charmask; if (fontwidth(p) <= 8) cdat = p->fontdata + c * fontheight(p); else cdat = p->fontdata + (c * fontheight(p) << 1); size = fontheight(p) * widthb; memcpy(gbuf, cdat, size); gly->ngmask = size;}/* ---------------------- HEAP Routines ----------------------------- *//* * Heap Initialization */static int sisfb_heap_init(void){ struct OH *poh; u8 jTemp, tq_state; if(ivideo.video_size > 0x800000) /* video ram is large than 8M */ heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M; else heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M; heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size; heap_size = heap_end - heap_start; /* Setting for Turbo Queue */ if (heap_size >= TURBO_QUEUE_AREA_SIZE) { tqueue_pos = (ivideo.video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024); jTemp = (u8) (tqueue_pos & 0xff); vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET); tq_state = vgarb(SEQ_DATA); tq_state |= 0xf0; tq_state &= 0xfc; tq_state |= (u8) (tqueue_pos >> 8); vgawb(SEQ_DATA, tq_state); vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR); vgawb(SEQ_DATA, jTemp); caps |= TURBO_QUEUE_CAP; heap_end -= TURBO_QUEUE_AREA_SIZE; heap_size -= TURBO_QUEUE_AREA_SIZE; } /* Setting for HW cursor(4K) */ if (heap_size >= HW_CURSOR_AREA_SIZE) { heap_end -= HW_CURSOR_AREA_SIZE; heap_size -= HW_CURSOR_AREA_SIZE; hwcursor_vbase = heap_end; caps |= HW_CURSOR_CAP; } heap.pohaChain = NULL; heap.pohFreeList = NULL; poh = poh_new_node(); if (poh == NULL) return 1; /* The first node describles the entire heap size */ poh->pohNext = &heap.ohFree; poh->pohPrev = &heap.ohFree; poh->ulSize = heap_end - heap_start + 1; poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase; DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n", (char *) heap_start, (char *) heap_end, (unsigned int) poh->ulSize / 1024); DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n", (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024); /* The second node in our free list sentinel */ heap.ohFree.pohNext = poh; heap.ohFree.pohPrev = poh; heap.ohFree.ulSize = 0; heap.ulMaxFreeSize = poh->ulSize; /* Initialize the discardable list */ heap.ohUsed.pohNext = &heap.ohUsed; heap.ohUsed.pohPrev = &heap.ohUsed; heap.ohUsed.ulSize = SENTINEL; return 0;}/* * Allocates a basic memory unit in which we'll pack our data structures. */static struct OH *poh_new_node(void){ int i; unsigned long cOhs; struct OHALLOC *poha; struct OH *poh; if (heap.pohFreeList == NULL) { poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL); poha->pohaNext = heap.pohaChain; heap.pohaChain = poha; cOhs = (OH_ALLOC_SIZE - sizeof(struct OHALLOC)) / sizeof(struct OH) + 1; poh = &poha->aoh[0]; for (i = cOhs - 1; i != 0; i--) { poh->pohNext = poh + 1; poh = poh + 1; } poh->pohNext = NULL; heap.pohFreeList = &poha->aoh[0]; } poh = heap.pohFreeList; heap.pohFreeList = poh->pohNext; return (poh);}/* * Allocates space, return NULL when failed */static struct OH *poh_allocate(unsigned long size){ struct OH *pohThis; struct OH *pohRoot; int bAllocated = 0; if (size > heap.ulMaxFreeSize) { DPRINTK("sisfb: Can't allocate %dk size on offscreen\n", (unsigned int) size / 1024); return (NULL); } pohThis = heap.ohFree.pohNext; while (pohThis != &heap.ohFree) { if (size <= pohThis->ulSize) { bAllocated = 1; break; } pohThis = pohThis->pohNext; } if (!bAllocated) { DPRINTK("sisfb: Can't allocate %dk size on offscreen\n", (unsigned int) size / 1024); return (NULL); } if (size == pohThis->ulSize) { pohRoot = pohThis; delete_node(pohThis); } else { pohRoot = poh_new_node(); if (pohRoot == NULL) { return (NULL); } pohRoot->ulOffset = pohThis->ulOffset; pohRoot->ulSize = size; pohThis->ulOffset += size; pohThis->ulSize -= size; } heap.ulMaxFreeSize -= size; pohThis = &heap.ohUsed; insert_node(pohThis, pohRoot); return (pohRoot);}/* * To remove a node from a list. */static void delete_node(struct OH *poh){ struct OH *pohPrev; struct OH *pohNext; pohPrev = poh->pohPrev; pohNext = poh->pohNext; pohPrev->pohNext = pohNext; pohNext->pohPrev = pohPrev; return;}/* * To insert a node into a list. */static void insert_node(struct OH *pohList, struct OH *poh){ struct OH *pohTemp; pohTemp = pohList->pohNext; pohList->pohNext = poh; pohTemp->pohPrev = poh; poh->pohPrev = pohList; poh->pohNext = pohTemp;}/* * Frees an off-screen heap allocation. */static struct OH *poh_free(unsigned long base){ struct OH *pohThis; struct OH *pohFreed; struct OH *pohPrev; struct OH *pohNext; unsigned long ulUpper; unsigned long ulLower; int foundNode = 0; pohFreed = heap.ohUsed.pohNext; while (pohFreed != &heap.ohUsed) { if (pohFreed->ulOffset == base) { foundNode = 1; break; } pohFreed = pohFreed->pohNext; } if (!foundNode) return (NULL); heap.ulMaxFreeSize += pohFreed->ulSize; pohPrev = pohNext = NULL; ulUpper = pohFreed->ulOffset + pohFreed->ulSize; ulLower = pohFreed->ulOffset; pohThis = heap.ohFree.pohNext; while (pohThis != &heap.ohFree) { if (pohThis->ulOffset == ulUpper) { pohNext = pohThis;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?