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 + -
显示快捷键?