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

📄 pvr2fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		par->is_doublescan = 1;	par->hsync_total = var->left_margin + var->xres + var->right_margin +	                   var->hsync_len;	par->vsync_total = var->upper_margin + var->yres + var->lower_margin +	                   var->vsync_len;	if (var->sync & FB_SYNC_BROADCAST) {		vtotal = par->vsync_total;		if (par->is_interlaced)			vtotal /= 2;		if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) {			/* XXX: Check for start values here... */			/* XXX: Check hardware for PAL-compatibility */			par->borderstart_h = 116;			par->borderstart_v = 44;		} else {			/* NTSC video output */			par->borderstart_h = 126;			par->borderstart_v = 18;		}	} else {		/* VGA mode */		/* XXX: What else needs to be checked? */		/*		 * XXX: We have a little freedom in VGA modes, what ranges		 * should be here (i.e. hsync/vsync totals, etc.)?		 */		par->borderstart_h = 126;		par->borderstart_v = 40;	}	/* Calculate the remainding offsets */	par->diwstart_h = par->borderstart_h + var->left_margin;	par->diwstart_v = par->borderstart_v + var->upper_margin;	par->borderstop_h = par->diwstart_h + var->xres +			    var->right_margin;	par->borderstop_v = par->diwstart_v + var->yres +			    var->lower_margin;	if (!par->is_interlaced)		par->borderstop_v /= 2;	if (info->var.xres < 640)		par->is_lowres = 1;	line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);	par->disp_start = info->fix.smem_start + (line_length * var->yoffset) * line_length;	info->fix.line_length = line_length;	return 0;}static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){	struct pvr2fb_par *par = (struct pvr2fb_par *)info->par;	unsigned int vtotal, hsync_total;	unsigned long line_length;	if (var->pixclock != TV_CLK && var->pixclock != VGA_CLK) {		pr_debug("Invalid pixclock value %d\n", var->pixclock);		return -EINVAL;	}	if (var->xres < 320)		var->xres = 320;	if (var->yres < 240)		var->yres = 240;	if (var->xres_virtual < var->xres)		var->xres_virtual = var->xres;	if (var->yres_virtual < var->yres)		var->yres_virtual = var->yres;	if (var->bits_per_pixel <= 16)		var->bits_per_pixel = 16;	else if (var->bits_per_pixel <= 24)		var->bits_per_pixel = 24;	else if (var->bits_per_pixel <= 32)		var->bits_per_pixel = 32;	set_color_bitfields(var);	if (var->vmode & FB_VMODE_YWRAP) {		if (var->xoffset || var->yoffset < 0 ||		    var->yoffset >= var->yres_virtual) {			var->xoffset = var->yoffset = 0;		} else {			if (var->xoffset > var->xres_virtual - var->xres ||			    var->yoffset > var->yres_virtual - var->yres ||			    var->xoffset < 0 || var->yoffset < 0)				var->xoffset = var->yoffset = 0;		}	} else {		var->xoffset = var->yoffset = 0;	}	/*	 * XXX: Need to be more creative with this (i.e. allow doublecan for	 * PAL/NTSC output).	 */	if (var->yres < 480 && video_output == VO_VGA)		var->vmode |= FB_VMODE_DOUBLE;	if (video_output != VO_VGA) {		var->sync |= FB_SYNC_BROADCAST;		var->vmode |= FB_VMODE_INTERLACED;	} else {		var->sync &= ~FB_SYNC_BROADCAST;		var->vmode &= ~FB_VMODE_INTERLACED;		var->vmode |= FB_VMODE_NONINTERLACED;	}	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_TEST) {		var->right_margin = par->borderstop_h -				   (par->diwstart_h + var->xres);		var->left_margin  = par->diwstart_h - par->borderstart_h;		var->hsync_len    = par->borderstart_h +		                   (par->hsync_total - par->borderstop_h);		var->upper_margin = par->diwstart_v - par->borderstart_v;		var->lower_margin = par->borderstop_v -				   (par->diwstart_v + var->yres);		var->vsync_len    = par->borderstop_v +				   (par->vsync_total - par->borderstop_v);	}	hsync_total = var->left_margin + var->xres + var->right_margin +		      var->hsync_len;	vtotal = var->upper_margin + var->yres + var->lower_margin +		 var->vsync_len;	if (var->sync & FB_SYNC_BROADCAST) {		if (var->vmode & FB_VMODE_INTERLACED)			vtotal /= 2;		if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) {			/* PAL video output */			/* XXX: Should be using a range here ... ? */			if (hsync_total != PAL_HTOTAL) {				pr_debug("invalid hsync total for PAL\n");				return -EINVAL;			}		} else {			/* NTSC video output */			if (hsync_total != NTSC_HTOTAL) {				pr_debug("invalid hsync total for NTSC\n");				return -EINVAL;			}		}	}	/* Check memory sizes */	line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);	if (line_length * var->yres_virtual > info->fix.smem_len)		return -ENOMEM;	return 0;}static void pvr2_update_display(struct fb_info *info){	struct pvr2fb_par *par = (struct pvr2fb_par *) info->par;	struct fb_var_screeninfo *var = &info->var;	/* Update the start address of the display image */	fb_writel(par->disp_start, DISP_DIWADDRL);	fb_writel(par->disp_start +		  get_line_length(var->xoffset+var->xres, var->bits_per_pixel),	          DISP_DIWADDRS);}/* * Initialize the video mode.  Currently, the 16bpp and 24bpp modes aren't * very stable.  It's probably due to the fact that a lot of the 2D video * registers are still undocumented. */static void pvr2_init_display(struct fb_info *info){	struct pvr2fb_par *par = (struct pvr2fb_par *) info->par;	struct fb_var_screeninfo *var = &info->var;	unsigned int diw_height, diw_width, diw_modulo = 1;	unsigned int bytesperpixel = var->bits_per_pixel >> 3;	/* hsync and vsync totals */	fb_writel((par->vsync_total << 16) | par->hsync_total, DISP_SYNCSIZE);	/* column height, modulo, row width */	/* since we're "panning" within vram, we need to offset things based	 * on the offset from the virtual x start to our real gfx. */	if (video_output != VO_VGA && par->is_interlaced)		diw_modulo += info->fix.line_length / 4;	diw_height = (par->is_interlaced ? var->yres / 2 : var->yres);	diw_width = get_line_length(var->xres, var->bits_per_pixel) / 4;	fb_writel((diw_modulo << 20) | (--diw_height << 10) | --diw_width,	          DISP_DIWSIZE);	/* display address, long and short fields */	fb_writel(par->disp_start, DISP_DIWADDRL);	fb_writel(par->disp_start +	          get_line_length(var->xoffset+var->xres, var->bits_per_pixel),	          DISP_DIWADDRS);	/* border horizontal, border vertical, border color */	fb_writel((par->borderstart_h << 16) | par->borderstop_h, DISP_BRDRHORZ);	fb_writel((par->borderstart_v << 16) | par->borderstop_v, DISP_BRDRVERT);	fb_writel(0, DISP_BRDRCOLR);	/* display window start position */	fb_writel(par->diwstart_h, DISP_DIWHSTRT);	fb_writel((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT);	/* misc. settings */	fb_writel((0x16 << 16) | par->is_lowres, DISP_DIWCONF);	/* clock doubler (for VGA), scan doubler, display enable */	fb_writel(((video_output == VO_VGA) << 23) |	          (par->is_doublescan << 1) | 1, DISP_DIWMODE);	/* bits per pixel */	fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE);	fb_writel(bytesperpixel << 2, DISP_PIXDEPTH);	/* video enable, color sync, interlace,	 * hsync and vsync polarity (currently unused) */	fb_writel(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF);}/* Simulate blanking by making the border cover the entire screen */#define BLANK_BIT (1<<3)static void pvr2_do_blank(void){	struct pvr2fb_par *par = currentpar;	unsigned long diwconf;	diwconf = fb_readl(DISP_DIWCONF);	if (do_blank > 0)		fb_writel(diwconf | BLANK_BIT, DISP_DIWCONF);	else		fb_writel(diwconf & ~BLANK_BIT, DISP_DIWCONF);	is_blanked = do_blank > 0 ? do_blank : 0;}static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id){	struct fb_info *info = dev_id;	if (do_vmode_pan || do_vmode_full)		pvr2_update_display(info);	if (do_vmode_full)		pvr2_init_display(info);	if (do_vmode_pan)		do_vmode_pan = 0;	if (do_vmode_full)		do_vmode_full = 0;	if (do_blank) {		pvr2_do_blank();		do_blank = 0;	}	return IRQ_HANDLED;}/* * Determine the cable type and initialize the cable output format.  Don't do * anything if the cable type has been overidden (via "cable:XX"). */#define PCTRA 0xff80002c#define PDTRA 0xff800030#define VOUTC 0xa0702c00static int pvr2_init_cable(void){	if (cable_type < 0) {		fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000,	                  PCTRA);		cable_type = (fb_readw(PDTRA) >> 8) & 3;	}	/* Now select the output format (either composite or other) */	/* XXX: Save the previous val first, as this reg is also AICA	  related */	if (cable_type == CT_COMPOSITE)		fb_writel(3 << 8, VOUTC);	else if (cable_type == CT_RGB)		fb_writel(1 << 9, VOUTC);	else		fb_writel(0, VOUTC);	return cable_type;}#ifdef CONFIG_SH_DMAstatic ssize_t pvr2fb_write(struct fb_info *info, const char *buf,			    size_t count, loff_t *ppos){	unsigned long dst, start, end, len;	unsigned int nr_pages;	struct page **pages;	int ret, i;	nr_pages = (count + PAGE_SIZE - 1) >> PAGE_SHIFT;	pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);	if (!pages)		return -ENOMEM;	down_read(&current->mm->mmap_sem);	ret = get_user_pages(current, current->mm, (unsigned long)buf,			     nr_pages, WRITE, 0, pages, NULL);	up_read(&current->mm->mmap_sem);	if (ret < nr_pages) {		nr_pages = ret;		ret = -EINVAL;		goto out_unmap;	}	dma_configure_channel(shdma, 0x12c1);	dst   = (unsigned long)fb_info->screen_base + *ppos;	start = (unsigned long)page_address(pages[0]);	end   = (unsigned long)page_address(pages[nr_pages]);	len   = nr_pages << PAGE_SHIFT;	/* Half-assed contig check */	if (start + len == end) {		/* As we do this in one shot, it's either all or nothing.. */		if ((*ppos + len) > fb_info->fix.smem_len) {			ret = -ENOSPC;			goto out_unmap;		}		dma_write(shdma, start, 0, len);		dma_write(pvr2dma, 0, dst, len);		dma_wait_for_completion(pvr2dma);		goto out;	}	/* Not contiguous, writeout per-page instead.. */	for (i = 0; i < nr_pages; i++, dst += PAGE_SIZE) {		if ((*ppos + (i << PAGE_SHIFT)) > fb_info->fix.smem_len) {			ret = -ENOSPC;			goto out_unmap;		}		dma_write_page(shdma, (unsigned long)page_address(pages[i]), 0);		dma_write_page(pvr2dma, 0, dst);		dma_wait_for_completion(pvr2dma);	}out:	*ppos += count;	ret = count;out_unmap:	for (i = 0; i < nr_pages; i++)		page_cache_release(pages[i]);	kfree(pages);	return ret;}#endif /* CONFIG_SH_DMA *//** * pvr2fb_common_init * * Common init code for the PVR2 chips. * * This mostly takes care of the common aspects of the fb setup and * registration. It's expected that the board-specific init code has * already setup pvr2_fix with something meaningful at this point. * * Device info reporting is also done here, as well as picking a sane * default from the modedb. For board-specific modelines, simply define * a per-board modedb. * * Also worth noting is that the cable and video output types are likely * always going to be VGA for the PCI-based PVR2 boards, but we leave this

⌨️ 快捷键说明

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