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

📄 ivtvfb.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* If transfer size > threshold and both src/dst	addresses are aligned, use DMA */	if (count >= 4096 &&	    ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {		/* Odd address = can't DMA. Align */		if ((unsigned long)dst & 3) {			lead = 4 - ((unsigned long)dst & 3);			if (copy_from_user(dst, buf, lead))				return -EFAULT;			buf += lead;			dst += lead;		}		/* DMA resolution is 32 bits */		if ((count - lead) & 3)			tail = (count - lead) & 3;		/* DMA the data */		dma_size = count - lead - tail;		dma_err = ivtvfb_prep_dec_dma_to_device(itv,		       p + lead + dma_offset, (void __user *)buf, dma_size);		if (dma_err)			return dma_err;		dst += dma_size;		buf += dma_size;		/* Copy any leftover data */		if (tail && copy_from_user(dst, buf, tail))			return -EFAULT;	} else if (copy_from_user(dst, buf, count)) {		return -EFAULT;	}	if  (!err)		*ppos += count;	return (err) ? err : count;}static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg){	DEFINE_WAIT(wait);	struct ivtv *itv = (struct ivtv *)info->par;	int rc = 0;	switch (cmd) {		case FBIOGET_VBLANK: {			struct fb_vblank vblank;			u32 trace;			vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |					FB_VBLANK_HAVE_VSYNC;			trace = read_reg(0x028c0) >> 16;			if (itv->is_50hz && trace > 312)				trace -= 312;			else if (itv->is_60hz && trace > 262)				trace -= 262;			if (trace == 1)				vblank.flags |= FB_VBLANK_VSYNCING;			vblank.count = itv->last_vsync_field;			vblank.vcount = trace;			vblank.hcount = 0;			if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))				return -EFAULT;			return 0;		}		case FBIO_WAITFORVSYNC:			prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);			if (!schedule_timeout(msecs_to_jiffies(50)))				rc = -ETIMEDOUT;			finish_wait(&itv->vsync_waitq, &wait);			return rc;		case IVTVFB_IOC_DMA_FRAME: {			struct ivtvfb_dma_frame args;			IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");			if (copy_from_user(&args, (void __user *)arg, sizeof(args)))				return -EFAULT;			return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);		}		default:			IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);			return -EINVAL;	}	return 0;}/* Framebuffer device handling */static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var){	struct osd_info *oi = itv->osd_info;	struct ivtv_osd_coords ivtv_osd;	struct v4l2_rect ivtv_window;	int osd_mode = -1;	IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");	/* Select color space */	if (var->nonstd) /* YUV */		write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);	else /* RGB  */		write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);	/* Set the color mode */	switch (var->bits_per_pixel) {		case 8:			osd_mode = IVTV_OSD_BPP_8;			break;		case 32:			osd_mode = IVTV_OSD_BPP_32;			break;		case 16:			switch (var->green.length) {			case 4:				osd_mode = IVTV_OSD_BPP_16_444;				break;			case 5:				osd_mode = IVTV_OSD_BPP_16_555;				break;			case 6:				osd_mode = IVTV_OSD_BPP_16_565;				break;			default:				IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");			}			break;		default:			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");	}	/* Set video mode. Although rare, the display can become scrambled even	   if we don't change mode. Always 'bounce' to osd_mode via mode 0 */	if (osd_mode != -1) {		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);	}	oi->bits_per_pixel = var->bits_per_pixel;	oi->bytes_per_pixel = var->bits_per_pixel / 8;	/* Set the flicker filter */	switch (var->vmode & FB_VMODE_MASK) {		case FB_VMODE_NONINTERLACED: /* Filter on */			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);			break;		case FB_VMODE_INTERLACED: /* Filter off */			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);			break;		default:			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");	}	/* Read the current osd info */	ivtvfb_get_osd_coords(itv, &ivtv_osd);	/* Now set the OSD to the size we want */	ivtv_osd.pixel_stride = var->xres_virtual;	ivtv_osd.lines = var->yres_virtual;	ivtv_osd.x = 0;	ivtv_osd.y = 0;	ivtvfb_set_osd_coords(itv, &ivtv_osd);	/* Can't seem to find the right API combo for this.	   Use another function which does what we need through direct register access. */	ivtv_window.width = var->xres;	ivtv_window.height = var->yres;	/* Minimum margin cannot be 0, as X won't allow such a mode */	if (!var->upper_margin) var->upper_margin++;	if (!var->left_margin) var->left_margin++;	ivtv_window.top = var->upper_margin - 1;	ivtv_window.left = var->left_margin - 1;	ivtvfb_set_display_window(itv, &ivtv_window);	/* Pass screen size back to yuv handler */	itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;	itv->yuv_info.osd_full_h = ivtv_osd.lines;	/* Force update of yuv registers */	itv->yuv_info.yuv_forced_update = 1;	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",		      var->xres, var->yres,		      var->xres_virtual, var->yres_virtual,		      var->bits_per_pixel);	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",		      var->left_margin, var->upper_margin);	IVTVFB_DEBUG_INFO("Display filter: %s\n",			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");	return 0;}static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix){	struct osd_info *oi = itv->osd_info;	IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");	memset(fix, 0, sizeof(struct fb_fix_screeninfo));	strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));	fix->smem_start = oi->video_pbase;	fix->smem_len = oi->video_buffer_size;	fix->type = FB_TYPE_PACKED_PIXELS;	fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;	fix->xpanstep = 1;	fix->ypanstep = 1;	fix->ywrapstep = 0;	fix->line_length = oi->display_byte_stride;	fix->accel = FB_ACCEL_NONE;	return 0;}/* Check the requested display mode, returning -EINVAL if we can't   handle it. */static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv){	struct osd_info *oi = itv->osd_info;	int osd_height_limit;	u32 pixclock, hlimit, vlimit;	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");	/* Set base references for mode calcs. */	if (itv->is_50hz) {		pixclock = 84316;		hlimit = 776;		vlimit = 591;		osd_height_limit = 576;	}	else {		pixclock = 83926;		hlimit = 776;		vlimit = 495;		osd_height_limit = 480;	}	if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {		var->transp.offset = 24;		var->transp.length = 8;		var->red.offset = 16;		var->red.length = 8;		var->green.offset = 8;		var->green.length = 8;		var->blue.offset = 0;		var->blue.length = 8;	}	else if (var->bits_per_pixel == 16) {		/* To find out the true mode, check green length */		switch (var->green.length) {			case 4:				var->red.offset = 8;				var->red.length = 4;				var->green.offset = 4;				var->green.length = 4;				var->blue.offset = 0;				var->blue.length = 4;				var->transp.offset = 12;				var->transp.length = 1;				break;			case 5:				var->red.offset = 10;				var->red.length = 5;				var->green.offset = 5;				var->green.length = 5;				var->blue.offset = 0;				var->blue.length = 5;				var->transp.offset = 15;				var->transp.length = 1;				break;			default:				var->red.offset = 11;				var->red.length = 5;				var->green.offset = 5;				var->green.length = 6;				var->blue.offset = 0;				var->blue.length = 5;				var->transp.offset = 0;				var->transp.length = 0;				break;		}	}	else {		IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);		return -EINVAL;	}	/* Check the resolution */	if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {		IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",				var->xres, var->yres);		return -EINVAL;	}	/* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */	if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||	    var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||	    var->xres_virtual < var->xres ||	    var->yres_virtual < var->yres) {		IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",			var->xres_virtual, var->yres_virtual);		return -EINVAL;	}	/* Some extra checks if in 8 bit mode */	if (var->bits_per_pixel == 8) {		/* Width must be a multiple of 4 */		if (var->xres & 3) {			IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);			return -EINVAL;		}		if (var->xres_virtual & 3) {			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);			return -EINVAL;		}	}	else if (var->bits_per_pixel == 16) {		/* Width must be a multiple of 2 */		if (var->xres & 1) {			IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);			return -EINVAL;		}		if (var->xres_virtual & 1) {			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);			return -EINVAL;		}	}	/* Now check the offsets */	if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {		IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",			var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);		return -EINVAL;	}	/* Check pixel format */	if (var->nonstd > 1) {		IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);		return -EINVAL;	}	/* Check video mode */	if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&		((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {		IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);		return -EINVAL;	}	/* Check the left & upper margins	   If the margins are too large, just center the screen	   (enforcing margins causes too many problems) */	if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {		var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);	}	if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {		var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);	}	/* Maintain overall 'size' for a constant refresh rate */	var->right_margin = hlimit - var->left_margin - var->xres;	var->lower_margin = vlimit - var->upper_margin - var->yres;	/* Fixed sync times */	var->hsync_len = 24;	var->vsync_len = 2;	/* Non-interlaced / interlaced mode is used to switch the OSD filter	   on or off. Adjust the clock timings to maintain a constant	   vertical refresh rate. */	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)		var->pixclock = pixclock / 2;	else		var->pixclock = pixclock;	itv->osd_rect.width = var->xres;	itv->osd_rect.height = var->yres;	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",		      var->xres, var->yres,		      var->xres_virtual, var->yres_virtual,		      var->bits_per_pixel);	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",		      var->left_margin, var->upper_margin);	IVTVFB_DEBUG_INFO("Display filter: %s\n",			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");	return 0;}static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){	struct ivtv *itv = (struct ivtv *) info->par;	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");	return _ivtvfb_check_var(var, itv);}static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){	u32 osd_pan_index;	struct ivtv *itv = (struct ivtv *) info->par;	osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;	write_reg(osd_pan_index, 0x02A0C);	/* Pass this info back the yuv handler */	itv->yuv_info.osd_x_pan = var->xoffset;	itv->yuv_info.osd_y_pan = var->yoffset;	/* Force update of yuv registers */

⌨️ 快捷键说明

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