sis_main.c

来自「讲述linux的初始化过程」· C语言 代码 · 共 2,375 行 · 第 1/4 页

C
2,375
字号
		}			else if ((pohThis->ulOffset + pohThis->ulSize) ==				 ulLower) {			pohPrev = pohThis;		}		pohThis = pohThis->pohNext;	}	delete_node(pohFreed);	if (pohPrev && pohNext) {		pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize);		delete_node(pohNext);		free_node(pohFreed);		free_node(pohNext);		return (pohPrev);	}	if (pohPrev) {		pohPrev->ulSize += pohFreed->ulSize;		free_node(pohFreed);		return (pohPrev);	}	if (pohNext) {		pohNext->ulSize += pohFreed->ulSize;		pohNext->ulOffset = pohFreed->ulOffset;		free_node(pohFreed);		return (pohNext);	}	insert_node(&heap.ohFree, pohFreed);	return (pohFreed);}/* *  Frees our basic data structure allocation unit by adding it to a free *  list. */static void free_node(struct OH *poh){	if (poh == NULL) {		return;	}	poh->pohNext = heap.pohFreeList;	heap.pohFreeList = poh;	return;}void sis_malloc(struct sis_memreq *req){	struct OH *poh;	poh = poh_allocate(req->size);	if (poh == NULL) {		req->offset = 0;		req->size = 0;		DPRINTK("sisfb: VMEM Allocation Failed\n");	} else {		DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",			(char *) (poh->ulOffset +				  (unsigned long) ivideo.video_vbase));		req->offset = poh->ulOffset;		req->size = poh->ulSize;	}}void sis_free(unsigned long base){	struct OH *poh;	poh = poh_free(base);	if (poh == NULL) {		DPRINTK("sisfb: poh_free() failed at base 0x%x\n",			(unsigned int) base);	}}void sis_dispinfo(struct ap_data *rec){	rec->minfo.bpp    = ivideo.video_bpp;	rec->minfo.xres   = ivideo.video_width;	rec->minfo.yres   = ivideo.video_height;	rec->minfo.v_xres = ivideo.video_vwidth;	rec->minfo.v_yres = ivideo.video_vheight;	rec->minfo.org_x  = ivideo.org_x;	rec->minfo.org_y  = ivideo.org_y;	rec->minfo.vrate  = ivideo.refresh_rate;	rec->iobase       = ivideo.vga_base - 0x30;	rec->mem_size     = ivideo.video_size;	rec->disp_state   = ivideo.disp_state; 	switch(HwExt.jChipID)	{	case SIS_Glamour:		rec->chip = SiS_300;		break;	case SIS_Trojan:		if((HwExt.revision_id & 0xf0) == 0x30)			rec->chip = SiS_630S;		else			rec->chip = SiS_630;		break;	case SIS_Spartan:		rec->chip = SiS_540;		break;	case SIS_730:		rec->chip = SiS_730;		break;	default:		rec->chip = SiS_UNKNOWN;		break;	}}/* ---------------------- SetMode Routines -------------------------- */void SetReg1(u16 port, u16 index, u16 data){	outb((u8) (index & 0xff), port);	port++;	outb((u8) (data & 0xff), port);}void SetReg3(u16 port, u16 data){	outb((u8) (data & 0xff), port);}void SetReg4(u16 port, unsigned long data){	outl((u32) (data & 0xffffffff), port);}u8 GetReg1(u16 port, u16 index){	u8 data;	outb((u8) (index & 0xff), port);	port += 1;	data = inb(port);	return (data);}u8 GetReg2(u16 port){	u8 data;	data = inb(port);	return (data);}u32 GetReg3(u16 port){	u32 data;	data = inl(port);	return (data);}void ClearDAC(u16 port){	int i,j;	vgawb(DAC_ADR, 0x00);	for(i=0; i<256; i++)		for(j=0; j<3; j++)			vgawb(DAC_DATA, 0);}void ClearBuffer(PHW_DEVICE_EXTENSION pHwExt){	memset((char *) ivideo.video_vbase, 0,		video_linelength * ivideo.video_height);}static void pre_setmode(void){	unsigned char  uCR30=0, uCR31=0;	switch(uDispType & MASK_DISPTYPE_DISP2)	{	case MASK_DISPTYPE_CRT2:		uCR30 = 0x41;		uCR31 = 0x40; 		break;	case MASK_DISPTYPE_LCD:		uCR30 = 0x21;		uCR31 = 0x40;		break;	case MASK_DISPTYPE_TV:		if(ivideo.TV_type == TVMODE_HIVISION)			uCR30 = 0x81;		else if(ivideo.TV_plug == TVPLUG_SVIDEO)			uCR30 = 0x09;		else if(ivideo.TV_plug == TVPLUG_COMPOSITE)			uCR30 = 0x05;		else if(ivideo.TV_plug == TVPLUG_SCART)			uCR30 = 0x11;		uCR31 = 0x40;  /* CR31[0] will be set in setmode() */		break;	default:		uCR30 = 0x00;		uCR31 = 0x60;	}	vgawb(CRTC_ADR, 0x30);	vgawb(CRTC_DATA, uCR30);	vgawb(CRTC_ADR, 0x31);	vgawb(CRTC_DATA, uCR31);    vgawb(CRTC_ADR, 0x33);    vgawb(CRTC_DATA, rate_idx & 0x0f);}static void post_setmode(void){	u8 uTemp;	vgawb(CRTC_ADR, 0x17);	uTemp = vgarb(CRTC_DATA);	if(crt1off)	  /* turn off CRT1 */		uTemp &= ~0x80;	else 	      /* turn on CRT1 */		uTemp |= 0x80;	vgawb(CRTC_DATA, uTemp);	/* disable 24-bit palette RAM and Gamma correction */	vgawb(SEQ_ADR, 0x07);	uTemp = vgarb(SEQ_DATA);	uTemp &= ~0x04;	vgawb(SEQ_DATA, uTemp);}static void search_mode(const char *name){	int i = 0;	if (name == NULL)		return;	while (sisbios_mode[i].mode_no != 0) {		if (!strcmp(name, sisbios_mode[i].name)) {			mode_idx = i;			break;		}		i++;	}	if (mode_idx < 0)		DPRINTK("Invalid user mode : %s\n", name);}static u8 search_refresh_rate(unsigned int rate){	u16 xres, yres;	int i = 0;	xres = sisbios_mode[mode_idx].xres;	yres = sisbios_mode[mode_idx].yres;	while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) {		if ((vrate[i].xres == xres) && (vrate[i].yres == yres)		    && (vrate[i].refresh == rate)) {			rate_idx = vrate[i].idx;			return rate_idx;		}		i++;	}	DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres,		yres);	return 0;}/* ------------------ Public Routines ------------------------------- *//* *    Get the Fixed Part of the Display */static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,			 struct fb_info *info){	DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con);	memset(fix, 0, sizeof(struct fb_fix_screeninfo));	strcpy(fix->id, fb_info.modename);	fix->smem_start = ivideo.video_base;	if(ivideo.video_size > 0x800000)		fix->smem_len = RESERVED_MEM_SIZE_8M;	/* reserved for Xserver */	else		fix->smem_len = RESERVED_MEM_SIZE_4M;	/* reserved for Xserver */	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;	fix->ypanstep = 0;	fix->ywrapstep = 0;	fix->line_length = video_linelength;	fix->mmio_start = ivideo.mmio_base;	fix->mmio_len = 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] = caps;	/* capabilities */	return 0;}/* *    Get the User Defined Part of the Display */static int sisfb_get_var(struct fb_var_screeninfo *var, int con,			 struct fb_info *info){	DPRINTK("sisfb: sisfb_get_var:[%d]\n", con);	if (con == -1)		memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));	else		*var = fb_display[con].var;	return 0;}/* *    Set the User Defined Part of the Display */static int sisfb_set_var(struct fb_var_screeninfo *var, int con,			 struct fb_info *info){	int err;	unsigned int cols, rows;	fb_display[con].var.activate = FB_ACTIVATE_NOW;	/* Set mode */	if (do_set_var(var, con == currcon, info)) {		crtc_to_var(var);	/* return current mode to user */		return -EINVAL;	}	/* get actual setting value */	crtc_to_var(var);	/* update display of current console */	sisfb_set_disp(con, var);	if (info->changevar)		(*info->changevar) (con);	if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))		return err;	do_install_cmap(con, info);	/* inform console to update struct display */	cols = sisbios_mode[mode_idx].cols;	rows = sisbios_mode[mode_idx].rows;	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);	return 0;}/* *    Get the Colormap */static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,			  struct fb_info *info){	DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con);	if (con == currcon)		return fb_get_cmap(cmap, kspc, sis_getcolreg, info);	else if (fb_display[con].cmap.len)	/* non default colormap? */		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);	else		fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);	return 0;}/* *    Set the Colormap */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) {	/* no colormap allocated */		err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);		if (err)			return err;	}	if (con == currcon)	/* current console */		return fb_set_cmap(cmap, kspc, sis_setcolreg, info);	else		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);	return 0;}static int sisfb_ioctl(struct inode *inode, struct file *file,		       unsigned int cmd, unsigned long arg, int con,		       struct fb_info *info){	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((struct GlyInfo *) arg);		break;	case FBIOGET_HWCINFO:		{			unsigned long *hwc_offset = (unsigned long *) arg;			if (caps & HW_CURSOR_CAP)				*hwc_offset = hwcursor_vbase -				    (unsigned long) ivideo.video_vbase;			else				*hwc_offset = 0;			break;		}	case FBIOPUT_MODEINFO:		{    			struct mode_info *x = (struct mode_info *)arg;			/* Set Mode Parameters by XServer */        			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;						break;		}	case FBIOGET_DISPINFO:		sis_dispinfo((struct ap_data *)arg);		break;	default:		return -EINVAL;	}	return 0;}static int sisfb_mmap(struct fb_info *info, struct file *file,		      struct vm_area_struct *vma){	struct fb_var_screeninfo var;	unsigned long start;	unsigned long off;	u32 len;	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))		return -EINVAL;	off = vma->vm_pgoff << PAGE_SHIFT;	/* frame buffer memory */	start = (unsigned long) ivideo.video_base;	len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);	if (off >= len) {		/* memory mapped io */		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) + 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__)	if (boot_cpu_data.x86 > 3)		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;#endif	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,				vma->vm_page_prot)) 		return -EAGAIN;	return 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_ioctl:	sisfb_ioctl,	fb_mmap:	sisfb_mmap,};int sisfb_setup(char *options){	char *this_opt;	fb_info.fontname[0] = '\0';	ivideo.refresh_rate = 0;	if (!options || !*options)		return 0;	for (this_opt = strtok(options, ","); this_opt;	     this_opt = strtok(NULL, ",")) {		if (!*this_opt)			continue;		if (!strcmp(this_opt, "inverse")) {			inverse = 1;			fb_invert_cmaps();		} else if (!strncmp(this_opt, "font:", 5)) {			strcpy(fb_info.fontname, this_opt + 5);		} else if (!strncmp(this_opt, "mode:", 5)) {			search_mode(this_opt + 5);		} else if (!strncmp(this_opt, "vrate:", 6)) {			ivideo.refresh_rate =			    simple_strtoul(this_opt + 6, NULL, 0);		} else if (!strncmp(this_opt, "off", 3)) {			sisfb_off = 1;		} else if (!strncmp(this_opt, "crt1off", 7)) {			crt1off = 1;		} else			DPRINTK("invalid parameter %s\n", this_opt);	}	return 0;}static int sisfb_update_var(int con, struct fb_info *info){	return 0;}/* *    Switch Console (called by fbcon.c) */static int sisfb_switch(int con, struct fb_info *info){	int cols, rows;	DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con);	/* update colormap of current console */	if (fb_display[currcon].cmap.len)		fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);	fb_display[con].var.activate = FB_ACTIVATE_NOW;	/* same mode, needn't change mode actually */	if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo))) 	{		currcon = con;		return 1;	}	currcon = con;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?