⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uvesafb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				"for mode 0x%x failed (eax=0x%x, err=%d)\n",				*mode, (u32)task->t.regs.eax, err);			mode++;			par->vbe_modes_cnt--;			continue;		}		mib = task->buf;		mib->mode_id = *mode;		/*		 * We only want modes that are supported with the current		 * hardware configuration, color, graphics and that have		 * support for the LFB.		 */		if ((mib->mode_attr & VBE_MODE_MASK) == VBE_MODE_MASK &&				 mib->bits_per_pixel >= 8)			off++;		else			par->vbe_modes_cnt--;		mode++;		mib->depth = mib->red_len + mib->green_len + mib->blue_len;		/*		 * Handle 8bpp modes and modes with broken color component		 * lengths.		 */		if (mib->depth == 0 || (mib->depth == 24 &&					mib->bits_per_pixel == 32))			mib->depth = mib->bits_per_pixel;	}	if (par->vbe_modes_cnt > 0)		return 0;	else		return -EINVAL;}/* * The Protected Mode Interface is 32-bit x86 code, so we only run it on * x86 and not x86_64. */#ifdef CONFIG_X86_32static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task,		struct uvesafb_par *par){	int i, err;	uvesafb_reset(task);	task->t.regs.eax = 0x4f0a;	task->t.regs.ebx = 0x0;	err = uvesafb_exec(task);	if ((task->t.regs.eax & 0xffff) != 0x4f || task->t.regs.es < 0xc000) {		par->pmi_setpal = par->ypan = 0;	} else {		par->pmi_base = (u16 *)phys_to_virt(((u32)task->t.regs.es << 4)						+ task->t.regs.edi);		par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1];		par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2];		printk(KERN_INFO "uvesafb: protected mode interface info at "				 "%04x:%04x\n",				 (u16)task->t.regs.es, (u16)task->t.regs.edi);		printk(KERN_INFO "uvesafb: pmi: set display start = %p, "				 "set palette = %p\n", par->pmi_start,				 par->pmi_pal);		if (par->pmi_base[3]) {			printk(KERN_INFO "uvesafb: pmi: ports = ");			for (i = par->pmi_base[3]/2;					par->pmi_base[i] != 0xffff; i++)				printk("%x ", par->pmi_base[i]);			printk("\n");			if (par->pmi_base[i] != 0xffff) {				printk(KERN_INFO "uvesafb: can't handle memory"						 " requests, pmi disabled\n");				par->ypan = par->pmi_setpal = 0;			}		}	}	return 0;}#endif /* CONFIG_X86_32 *//* * Check whether a video mode is supported by the Video BIOS and is * compatible with the monitor limits. */static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode,		struct fb_info *info){	if (info->monspecs.gtf) {		fb_videomode_to_var(&info->var, mode);		if (fb_validate_mode(&info->var, info))			return 0;	}	if (uvesafb_vbe_find_mode(info->par, mode->xres, mode->yres, 8,				UVESAFB_EXACT_RES) == -1)		return 0;	return 1;}static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task,		struct fb_info *info){	struct uvesafb_par *par = info->par;	int err = 0;	if (noedid || par->vbe_ib.vbe_version < 0x0300)		return -EINVAL;	task->t.regs.eax = 0x4f15;	task->t.regs.ebx = 0;	task->t.regs.ecx = 0;	task->t.buf_len = 0;	task->t.flags = 0;	err = uvesafb_exec(task);	if ((task->t.regs.eax & 0xffff) != 0x004f || err)		return -EINVAL;	if ((task->t.regs.ebx & 0x3) == 3) {		printk(KERN_INFO "uvesafb: VBIOS/hardware supports both "				 "DDC1 and DDC2 transfers\n");	} else if ((task->t.regs.ebx & 0x3) == 2) {		printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC2 "				 "transfers\n");	} else if ((task->t.regs.ebx & 0x3) == 1) {		printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC1 "				 "transfers\n");	} else {		printk(KERN_INFO "uvesafb: VBIOS/hardware doesn't support "				 "DDC transfers\n");		return -EINVAL;	}	task->t.regs.eax = 0x4f15;	task->t.regs.ebx = 1;	task->t.regs.ecx = task->t.regs.edx = 0;	task->t.flags = TF_BUF_RET | TF_BUF_ESDI;	task->t.buf_len = EDID_LENGTH;	task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL);	err = uvesafb_exec(task);	if ((task->t.regs.eax & 0xffff) == 0x004f && !err) {		fb_edid_to_monspecs(task->buf, &info->monspecs);		if (info->monspecs.vfmax && info->monspecs.hfmax) {			/*			 * If the maximum pixel clock wasn't specified in			 * the EDID block, set it to 300 MHz.			 */			if (info->monspecs.dclkmax == 0)				info->monspecs.dclkmax = 300 * 1000000;			info->monspecs.gtf = 1;		}	} else {		err = -EINVAL;	}	kfree(task->buf);	return err;}static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task,		struct fb_info *info){	struct uvesafb_par *par = info->par;	int i;	memset(&info->monspecs, 0, sizeof(info->monspecs));	/*	 * If we don't get all necessary data from the EDID block,	 * mark it as incompatible with the GTF and set nocrtc so	 * that we always use the default BIOS refresh rate.	 */	if (uvesafb_vbe_getedid(task, info)) {		info->monspecs.gtf = 0;		par->nocrtc = 1;	}	/* Kernel command line overrides. */	if (maxclk)		info->monspecs.dclkmax = maxclk * 1000000;	if (maxvf)		info->monspecs.vfmax = maxvf;	if (maxhf)		info->monspecs.hfmax = maxhf * 1000;	/*	 * In case DDC transfers are not supported, the user can provide	 * monitor limits manually. Lower limits are set to "safe" values.	 */	if (info->monspecs.gtf == 0 && maxclk && maxvf && maxhf) {		info->monspecs.dclkmin = 0;		info->monspecs.vfmin = 60;		info->monspecs.hfmin = 29000;		info->monspecs.gtf = 1;		par->nocrtc = 0;	}	if (info->monspecs.gtf)		printk(KERN_INFO			"uvesafb: monitor limits: vf = %d Hz, hf = %d kHz, "			"clk = %d MHz\n", info->monspecs.vfmax,			(int)(info->monspecs.hfmax / 1000),			(int)(info->monspecs.dclkmax / 1000000));	else		printk(KERN_INFO "uvesafb: no monitor limits have been set, "				 "default refresh rate will be used\n");	/* Add VBE modes to the modelist. */	for (i = 0; i < par->vbe_modes_cnt; i++) {		struct fb_var_screeninfo var;		struct vbe_mode_ib *mode;		struct fb_videomode vmode;		mode = &par->vbe_modes[i];		memset(&var, 0, sizeof(var));		var.xres = mode->x_res;		var.yres = mode->y_res;		fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &var, info);		fb_var_to_videomode(&vmode, &var);		fb_add_videomode(&vmode, &info->modelist);	}	/* Add valid VESA modes to our modelist. */	for (i = 0; i < VESA_MODEDB_SIZE; i++) {		if (uvesafb_is_valid_mode((struct fb_videomode *)						&vesa_modes[i], info))			fb_add_videomode(&vesa_modes[i], &info->modelist);	}	for (i = 0; i < info->monspecs.modedb_len; i++) {		if (uvesafb_is_valid_mode(&info->monspecs.modedb[i], info))			fb_add_videomode(&info->monspecs.modedb[i],					&info->modelist);	}	return;}static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task,		struct uvesafb_par *par){	int err;	uvesafb_reset(task);	/*	 * Get the VBE state buffer size. We want all available	 * hardware state data (CL = 0x0f).	 */	task->t.regs.eax = 0x4f04;	task->t.regs.ecx = 0x000f;	task->t.regs.edx = 0x0000;	task->t.flags = 0;	err = uvesafb_exec(task);	if (err || (task->t.regs.eax & 0xffff) != 0x004f) {		printk(KERN_WARNING "uvesafb: VBE state buffer size "			"cannot be determined (eax=0x%x, err=%d)\n",			task->t.regs.eax, err);		par->vbe_state_size = 0;		return;	}	par->vbe_state_size = 64 * (task->t.regs.ebx & 0xffff);}static int __devinit uvesafb_vbe_init(struct fb_info *info){	struct uvesafb_ktask *task = NULL;	struct uvesafb_par *par = info->par;	int err;	task = uvesafb_prep();	if (!task)		return -ENOMEM;	err = uvesafb_vbe_getinfo(task, par);	if (err)		goto out;	err = uvesafb_vbe_getmodes(task, par);	if (err)		goto out;	par->nocrtc = nocrtc;#ifdef CONFIG_X86_32	par->pmi_setpal = pmi_setpal;	par->ypan = ypan;	if (par->pmi_setpal || par->ypan)		uvesafb_vbe_getpmi(task, par);#else	/* The protected mode interface is not available on non-x86. */	par->pmi_setpal = par->ypan = 0;#endif	INIT_LIST_HEAD(&info->modelist);	uvesafb_vbe_getmonspecs(task, info);	uvesafb_vbe_getstatesize(task, par);out:	uvesafb_free(task);	return err;}static int __devinit uvesafb_vbe_init_mode(struct fb_info *info){	struct list_head *pos;	struct fb_modelist *modelist;	struct fb_videomode *mode;	struct uvesafb_par *par = info->par;	int i, modeid;	/* Has the user requested a specific VESA mode? */	if (vbemode) {		for (i = 0; i < par->vbe_modes_cnt; i++) {			if (par->vbe_modes[i].mode_id == vbemode) {				fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,							&info->var, info);				/*				 * With pixclock set to 0, the default BIOS				 * timings will be used in set_par().				 */				info->var.pixclock = 0;				modeid = i;				goto gotmode;			}		}		printk(KERN_INFO "uvesafb: requested VBE mode 0x%x is "				 "unavailable\n", vbemode);		vbemode = 0;	}	/* Count the modes in the modelist */	i = 0;	list_for_each(pos, &info->modelist)		i++;	/*	 * Convert the modelist into a modedb so that we can use it with	 * fb_find_mode().	 */	mode = kzalloc(i * sizeof(*mode), GFP_KERNEL);	if (mode) {		i = 0;		list_for_each(pos, &info->modelist) {			modelist = list_entry(pos, struct fb_modelist, list);			mode[i] = modelist->mode;			i++;		}		if (!mode_option)			mode_option = UVESAFB_DEFAULT_MODE;		i = fb_find_mode(&info->var, info, mode_option, mode, i,			NULL, 8);		kfree(mode);	}	/* fb_find_mode() failed */	if (i == 0) {		info->var.xres = 640;		info->var.yres = 480;		mode = (struct fb_videomode *)				fb_find_best_mode(&info->var, &info->modelist);		if (mode) {			fb_videomode_to_var(&info->var, mode);		} else {			modeid = par->vbe_modes[0].mode_id;			fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,				    &info->var, info);			goto gotmode;		}	}	/* Look for a matching VBE mode. */	modeid = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres,			info->var.bits_per_pixel, UVESAFB_EXACT_RES);	if (modeid == -1)		return -EINVAL;gotmode:	uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]);	/*	 * If we are not VBE3.0+ compliant, we're done -- the BIOS will	 * ignore our timings anyway.	 */	if (par->vbe_ib.vbe_version < 0x0300 || par->nocrtc)		fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,					&info->var, info);	return modeid;}static int uvesafb_setpalette(struct uvesafb_pal_entry *entries, int count,		int start, struct fb_info *info){	struct uvesafb_ktask *task;#ifdef CONFIG_X86	struct uvesafb_par *par = info->par;	int i = par->mode_idx;#endif	int err = 0;	/*	 * We support palette modifications for 8 bpp modes only, so	 * there can never be more than 256 entries.	 */	if (start + count > 256)		return -EINVAL;#ifdef CONFIG_X86	/* Use VGA registers if mode is VGA-compatible. */	if (i >= 0 && i < par->vbe_modes_cnt &&	    par->vbe_modes[i].mode_attr & VBE_MODE_VGACOMPAT) {		for (i = 0; i < count; i++) {			outb_p(start + i,        dac_reg);			outb_p(entries[i].red,   dac_val);			outb_p(entries[i].green, dac_val);			outb_p(entries[i].blue,  dac_val);		}	}#ifdef CONFIG_X86_32	else if (par->pmi_setpal) {		__asm__ __volatile__(		"call *(%%esi)"		: /* no return value */		: "a" (0x4f09),         /* EAX */		  "b" (0),              /* EBX */		  "c" (count),          /* ECX */		  "d" (start),          /* EDX */		  "D" (entries),        /* EDI */		  "S" (&par->pmi_pal)); /* ESI */	}#endif /* CONFIG_X86_32 */	else#endif /* CONFIG_X86 */	{		task = uvesafb_prep();		if (!task)			return -ENOMEM;		task->t.regs.eax = 0x4f09;		task->t.regs.ebx = 0x0;		task->t.regs.ecx = count;		task->t.regs.edx = start;		task->t.flags = TF_BUF_ESDI;		task->t.buf_len = sizeof(struct uvesafb_pal_entry) * count;		task->buf = entries;		err = uvesafb_exec(task);		if ((task->t.regs.eax & 0xffff) != 0x004f)			err = 1;		uvesafb_free(task);	}	return err;}static int uvesafb_setcolreg(unsigned regno, unsigned red, unsigned green,		unsigned blue, unsigned transp,		struct fb_info *info){	struct uvesafb_pal_entry entry;	int shift = 16 - info->var.green.length;	int err = 0;	if (regno >= info->cmap.len)		return -EINVAL;	if (info->var.bits_per_pixel == 8) {		entry.red   = red   >> shift;		entry.green = green >> shift;		entry.blue  = blue  >> shift;		entry.pad   = 0;		err = uvesafb_setpalette(&entry, 1, regno, info);	} else if (regno < 16) {		switch (info->var.bits_per_pixel) {		case 16:			if (info->var.red.offset == 10) {				/* 1:5:5:5 */				((u32 *) (info->pseudo_palette))[regno] =						((red   & 0xf800) >>  1) |						((green & 0xf800) >>  6) |						((blue  & 0xf800) >> 11);			} else {				/* 0:5:6:5 */				((u32 *) (info->pseudo_palette))[regno] =						((red   & 0xf800)      ) |						((green & 0xfc00) >>  5) |						((blue  & 0xf800) >> 11);			}			break;		case 24:		case 32:			red   >>= 8;			green >>= 8;			blue  >>= 8;			((u32 *)(info->pseudo_palette))[regno] =				(red   << info->var.red.offset)   |

⌨️ 快捷键说明

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