Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be383bd3 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (5904): ivtv-fb: cleanups

parent 32db7754
Loading
Loading
Loading
Loading
+204 −235
Original line number Diff line number Diff line
@@ -232,12 +232,13 @@ static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
static int ivtv_fb_get_osd_coords(struct ivtv *itv,
				      struct ivtv_osd_coords *osd)
{
	struct osd_info *oi = itv->osd_info;
	u32 data[CX2341X_MBOX_MAX_DATA];

	ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);

	osd->offset = data[0] - itv->osd_info->video_rbase;
	osd->max_offset = itv->osd_info->display_width * itv->osd_info->display_height * 4;
	osd->offset = data[0] - oi->video_rbase;
	osd->max_offset = oi->display_width * oi->display_height * 4;
	osd->pixel_stride = data[1];
	osd->lines = data[2];
	osd->x = data[3];
@@ -247,20 +248,21 @@ static int ivtv_fb_get_osd_coords(struct ivtv *itv,

static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
{
	itv->osd_info->display_width = osd->pixel_stride;
	itv->osd_info->display_byte_stride = osd->pixel_stride * itv->osd_info->bytes_per_pixel;
	itv->osd_info->set_osd_coords_x += osd->x;
	itv->osd_info->set_osd_coords_y = osd->y;
	struct osd_info *oi = itv->osd_info;

	oi->display_width = osd->pixel_stride;
	oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
	oi->set_osd_coords_x += osd->x;
	oi->set_osd_coords_y = osd->y;

	return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
			osd->offset + itv->osd_info->video_rbase,
			osd->offset + oi->video_rbase,
			osd->pixel_stride,
			osd->lines, osd->x, osd->y);
}

static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
{

	int osd_height_limit = itv->is_50hz ? 576 : 480;

	/* Only fail if resolution too high, otherwise fudge the start coords. */
@@ -344,7 +346,8 @@ static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv,
	return ret;
}

static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsigned long dest_offset, int count)
static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
			      unsigned long dest_offset, int count)
{
	DEFINE_WAIT(wait);

@@ -356,16 +359,15 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, un

	/* Check Total FB Size */
	if ((dest_offset + count) > itv->osd_info->video_buffer_size) {
		IVTV_FB_WARN(
			"ivtv_fb_prep_frame: Overflowing the framebuffer %ld, "
			"only %d available\n",
			(dest_offset + count), itv->osd_info->video_buffer_size);
		IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
			dest_offset + count, itv->osd_info->video_buffer_size);
		return -E2BIG;
	}

	/* Not fatal, but will have undesirable results */
	if ((unsigned long)source & 3)
		IVTV_FB_WARN ("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",(unsigned long)source);
		IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
			(unsigned long)source);

	if (dest_offset & 3)
		IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
@@ -375,12 +377,10 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source, un

	/* Check Source */
	if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
		IVTV_FB_WARN(
			"Invalid userspace pointer!!! 0x%08lx\n",
		IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n",
			(unsigned long)source);

		IVTV_FB_DEBUG_WARN(
			"access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
		IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
			dest_offset, (unsigned long)source,
			count);
		return -EINVAL;
@@ -400,7 +400,6 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
	int rc = 0;

	switch (cmd) {

		case FBIOGET_VBLANK: {
			struct fb_vblank vblank;
			u32 trace;
@@ -419,12 +418,11 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
			return 0;
		}

		case FBIO_WAITFORVSYNC: {
		case FBIO_WAITFORVSYNC:
			prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
			if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT;
			finish_wait(&itv->vsync_waitq, &wait);
			return rc;
		}

		case IVTVFB_IOCTL_PREP_FRAME: {
			struct ivtvfb_ioctl_dma_host_to_ivtv_args args;
@@ -447,7 +445,6 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar

static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
{

	struct ivtv_osd_coords ivtv_osd;
	struct v4l2_rect ivtv_window;

@@ -535,48 +532,36 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
	/* Force update of yuv registers */
	itv->yuv_info.yuv_forced_update = 1;

	IVTV_FB_INFO("=== Display mode change ===\n");
	IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n",
		var->xres,
		var->yres,
		var->xres_virtual,
		var->yres_virtual,
	IVTV_FB_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);

	IVTV_FB_INFO("Display position %d,%d\n",
		var->left_margin,
		var->upper_margin);
	IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
		      var->left_margin, var->upper_margin);

	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
		IVTV_FB_INFO("Display filter : on\n");
	}
	else {
		IVTV_FB_INFO("Display filter : off\n");
	}

	if (var->nonstd) {
		IVTV_FB_INFO("Color space : YUV\n");
	}
	else {
		IVTV_FB_INFO("Color space : RGB\n");
	}
	IVTV_FB_DEBUG_INFO("Display filter: %s\n",
			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
	IVTV_FB_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;

	IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n");
	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
	strcpy(fix->id, "cx23415 TV out");
	fix->smem_start = itv->osd_info->video_pbase;
	fix->smem_len = itv->osd_info->video_buffer_size;
	fix->smem_start = oi->video_pbase;
	fix->smem_len = oi->video_buffer_size;
	fix->type = FB_TYPE_PACKED_PIXELS;
	fix->visual = (itv->osd_info->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
	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 = itv->osd_info->display_byte_stride;
	fix->line_length = oi->display_byte_stride;
	fix->accel = FB_ACCEL_NONE;
	return 0;
}
@@ -586,6 +571,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)

static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
{
	struct osd_info *oi = itv->osd_info;
	int osd_height_limit = itv->is_50hz ? 576 : 480;

	IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
@@ -609,11 +595,12 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
		var->blue.length = 8;
	}
	else if (var->bits_per_pixel == 16) {
		var->transp.offset = 0;
		var->transp.length = 0;

		/* To find out the true mode, check green length */
		switch (var->green.length) {
			case 4:
				var->transp.offset = 0;
				var->transp.length = 0;
				var->red.offset = 8;
				var->red.length = 4;
				var->green.offset = 4;
@@ -622,8 +609,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
				var->blue.length = 4;
				break;
			case 5:
				var->transp.offset = 0;
				var->transp.length = 0;
				var->red.offset = 10;
				var->red.length = 5;
				var->green.offset = 5;
@@ -632,8 +617,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
				var->blue.length = 5;
				break;
			default:
				var->transp.offset = 0;
				var->transp.length = 0;
				var->red.offset = 11;
				var->red.length = 5;
				var->green.offset = 5;
@@ -650,10 +633,11 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)

	/* Check the resolution */
	if (osd_compat) {
		if (var->xres != itv->osd_info->ivtvfb_defined.xres || var->yres != itv->osd_info->ivtvfb_defined.yres ||
		    var->xres_virtual !=  itv->osd_info->ivtvfb_defined.xres_virtual || var->yres_virtual !=
		    itv->osd_info->ivtvfb_defined.yres_virtual) {
			IVTV_FB_DEBUG_WARN ("Invalid resolution: %d x %d (%d x %d Virtual)\n",
		if (var->xres != oi->ivtvfb_defined.xres ||
		    var->yres != oi->ivtvfb_defined.yres ||
		    var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
		    var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
			IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
				var->xres, var->yres, var->xres_virtual, var->yres_virtual);
			return -EINVAL;
		}
@@ -667,7 +651,7 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)

		/* 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) > itv->osd_info->video_buffer_size ||
		    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) {
			IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
@@ -702,8 +686,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)

	/* Now check the offsets */
	if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
		IVTV_FB_DEBUG_WARN ("Invalid offset: %d (%d) %d (%d)\n",var->xoffset,var->xres_virtual,
					var->yoffset,var->yres_virtual);
		IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
			var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
		return -EINVAL;
	}

@@ -732,8 +716,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
	}

	/* Maintain overall 'size' for a constant refresh rate */
	var->right_margin = itv->osd_info->hlimit - var->left_margin - var->xres;
	var->lower_margin = itv->osd_info->vlimit - var->upper_margin - var->yres;
	var->right_margin = oi->hlimit - var->left_margin - var->xres;
	var->lower_margin = oi->vlimit - var->upper_margin - var->yres;

	/* Fixed sync times */
	var->hsync_len = 24;
@@ -742,37 +726,21 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
	/* 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. */
	var->pixclock = itv->osd_info->pixclock;
	var->pixclock = oi->pixclock;
	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
		var->pixclock /= 2;

	IVTV_FB_DEBUG_INFO ("ivtvfb_check_var - Parameters validated\n");

	IVTV_FB_INFO("=== Validated display mode  ===\n");
	IVTV_FB_INFO("Display size %dx%d (%dx%d Virtual) @ %dbpp\n",
		      var->xres,
		      var->yres,
		      var->xres_virtual,
		      var->yres_virtual,
	IVTV_FB_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);

	IVTV_FB_INFO("Display position %d,%d\n",
		      var->left_margin,
		      var->upper_margin);

	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
		IVTV_FB_INFO("Display filter : on\n");
	}
	else {
		IVTV_FB_INFO("Display filter : off\n");
	}
	IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
		      var->left_margin, var->upper_margin);

	if (var->nonstd) {
		IVTV_FB_INFO("Color space : YUV\n");
	}
	else {
		IVTV_FB_INFO("Color space : RGB\n");
	}
	IVTV_FB_DEBUG_INFO("Display filter: %s\n",
			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
	IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
	return 0;
}

@@ -826,8 +794,8 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
	if (info->var.bits_per_pixel <= 8) {
		write_reg(regno, 0x02a30);
		write_reg(color, 0x02a34);
		return 0;
	}
	else {
	if (regno >= 16)
		return -EINVAL;

@@ -852,8 +820,6 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
		}
	}
	palette[regno] = color;
	}

	return 0;
}

@@ -898,27 +864,28 @@ static struct fb_ops ivtvfb_ops = {
/* Setup our initial video mode */
static int ivtvfb_init_vidmode(struct ivtv *itv)
{
	int max_height;
	struct osd_info *oi = itv->osd_info;
	struct v4l2_rect start_window;
	int max_height;

	/* Set base references for mode calcs. */
	if (itv->is_50hz) {
		itv->osd_info->pixclock = 84316;
		itv->osd_info->hlimit = 776;
		itv->osd_info->vlimit = 591;
		oi->pixclock = 84316;
		oi->hlimit = 776;
		oi->vlimit = 591;
	}
	else {
		itv->osd_info->pixclock = 83926;
		itv->osd_info->hlimit = 776;
		itv->osd_info->vlimit = 495;
		oi->pixclock = 83926;
		oi->hlimit = 776;
		oi->vlimit = 495;
	}

	/* Color mode */

	if (osd_compat) osd_depth = 32;
	if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
	itv->osd_info->bits_per_pixel = osd_depth;
	itv->osd_info->bytes_per_pixel = itv->osd_info->bits_per_pixel / 8;
	oi->bits_per_pixel = osd_depth;
	oi->bytes_per_pixel = oi->bits_per_pixel / 8;

	/* Horizontal size & position */

@@ -944,26 +911,22 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
	/* Hardware coords start at 0, user coords start at 1. */
	osd_left--;

	start_window.left =
			osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
	start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);

	itv->osd_info->display_byte_stride =
			start_window.width * itv->osd_info->bytes_per_pixel;
	oi->display_byte_stride =
			start_window.width * oi->bytes_per_pixel;

	/* Vertical size & position */

	max_height = itv->is_50hz ? 576 : 480;

	if ( osd_yres > max_height) osd_yres = max_height;
	if (osd_yres > max_height)
		osd_yres = max_height;

	if (osd_yres)
		start_window.height = osd_yres;
	else {
		if (itv->is_50hz)
			start_window.height = osd_compat ? max_height : 480;
	else
			start_window.height = osd_compat ? max_height : 400;
	}
		start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);

	/* Check vertical start (osd_upper). */
	if (osd_upper + start_window.height > max_height + 1) {
@@ -976,57 +939,57 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)

	start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);

	itv->osd_info->display_width = start_window.width;
	itv->osd_info->display_height = start_window.height;
	oi->display_width = start_window.width;
	oi->display_height = start_window.height;

	/* Generate a valid fb_var_screeninfo */

	itv->osd_info->ivtvfb_defined.xres = itv->osd_info->display_width;
	itv->osd_info->ivtvfb_defined.yres = itv->osd_info->display_height;
	itv->osd_info->ivtvfb_defined.xres_virtual = itv->osd_info->display_width;
	itv->osd_info->ivtvfb_defined.yres_virtual = itv->osd_info->display_height;
	itv->osd_info->ivtvfb_defined.bits_per_pixel = itv->osd_info->bits_per_pixel;
	itv->osd_info->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
	itv->osd_info->ivtvfb_defined.left_margin = start_window.left + 1;
	itv->osd_info->ivtvfb_defined.upper_margin = start_window.top + 1;
	itv->osd_info->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
	itv->osd_info->ivtvfb_defined.nonstd = 0;
	oi->ivtvfb_defined.xres = oi->display_width;
	oi->ivtvfb_defined.yres = oi->display_height;
	oi->ivtvfb_defined.xres_virtual = oi->display_width;
	oi->ivtvfb_defined.yres_virtual = oi->display_height;
	oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
	oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
	oi->ivtvfb_defined.left_margin = start_window.left + 1;
	oi->ivtvfb_defined.upper_margin = start_window.top + 1;
	oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
	oi->ivtvfb_defined.nonstd = 0;

	/* We've filled in the most data, let the usual mode check
	   routine fill in the rest. */
	_ivtvfb_check_var (&itv->osd_info->ivtvfb_defined,itv);
	_ivtvfb_check_var(&oi->ivtvfb_defined, itv);

	/* Generate valid fb_fix_screeninfo */

	ivtvfb_get_fix(itv,&itv->osd_info->ivtvfb_fix);
	ivtvfb_get_fix(itv, &oi->ivtvfb_fix);

	/* Generate valid fb_info */

	itv->osd_info->ivtvfb_info.node = -1;
	itv->osd_info->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
	itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops;
	itv->osd_info->ivtvfb_info.par = itv;
	itv->osd_info->ivtvfb_info.var = itv->osd_info->ivtvfb_defined;
	itv->osd_info->ivtvfb_info.fix = itv->osd_info->ivtvfb_fix;
	itv->osd_info->ivtvfb_info.screen_base = (u8 __iomem *)itv->osd_info->video_vbase;
	itv->osd_info->ivtvfb_info.fbops = &ivtvfb_ops;
	oi->ivtvfb_info.node = -1;
	oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
	oi->ivtvfb_info.fbops = &ivtvfb_ops;
	oi->ivtvfb_info.par = itv;
	oi->ivtvfb_info.var = oi->ivtvfb_defined;
	oi->ivtvfb_info.fix = oi->ivtvfb_fix;
	oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
	oi->ivtvfb_info.fbops = &ivtvfb_ops;

	/* Supply some monitor specs. Bogus values will do for now */
	itv->osd_info->ivtvfb_info.monspecs.hfmin = 8000;
	itv->osd_info->ivtvfb_info.monspecs.hfmax = 70000;
	itv->osd_info->ivtvfb_info.monspecs.vfmin = 10;
	itv->osd_info->ivtvfb_info.monspecs.vfmax = 100;
	oi->ivtvfb_info.monspecs.hfmin = 8000;
	oi->ivtvfb_info.monspecs.hfmax = 70000;
	oi->ivtvfb_info.monspecs.vfmin = 10;
	oi->ivtvfb_info.monspecs.vfmax = 100;

	/* Allocate color map */
	if (fb_alloc_cmap(&itv->osd_info->ivtvfb_info.cmap, 256, 1)) {
	if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
		IVTV_FB_ERR("abort, unable to alloc cmap\n");
		return -ENOMEM;
	}

	/* Allocate the pseudo palette */
	itv->osd_info->ivtvfb_info.pseudo_palette = kmalloc(sizeof (u32) * 16, GFP_KERNEL);
	oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);

	if (!itv->osd_info->ivtvfb_info.pseudo_palette) {
	if (!oi->ivtvfb_info.pseudo_palette) {
		IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n");
		return -ENOMEM;
	}
@@ -1038,51 +1001,53 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)

static int ivtvfb_init_io(struct ivtv *itv)
{
	ivtv_fb_get_framebuffer(itv, &itv->osd_info->video_rbase, &itv->osd_info->video_buffer_size);
	struct osd_info *oi = itv->osd_info;

	ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);

	/* The osd buffer size depends on the number of video buffers allocated
	   on the PVR350 itself. For now we'll hardcode the smallest osd buffer
	   size to prevent any overlap. */
	itv->osd_info->video_buffer_size = 1704960;
	oi->video_buffer_size = 1704960;

	itv->osd_info->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
	itv->osd_info->video_vbase = itv->dec_mem + itv->osd_info->video_rbase;
	oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
	oi->video_vbase = itv->dec_mem + oi->video_rbase;

	if (!itv->osd_info->video_vbase) {
	if (!oi->video_vbase) {
		IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
		     itv->osd_info->video_buffer_size, itv->osd_info->video_pbase);
		     oi->video_buffer_size, oi->video_pbase);
		return -EIO;
	}

	IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
			itv->osd_info->video_pbase, itv->osd_info->video_vbase,
			itv->osd_info->video_buffer_size / 1024);
			oi->video_pbase, oi->video_vbase,
			oi->video_buffer_size / 1024);

#ifdef CONFIG_MTRR
	{
		/* Find the largest power of two that maps the whole buffer */
		int size_shift = 31;

		while (!(itv->osd_info->video_buffer_size & (1 << size_shift))) {
		while (!(oi->video_buffer_size & (1 << size_shift))) {
			size_shift--;
		}
		size_shift++;
		itv->osd_info->fb_start_aligned_physaddr = itv->osd_info->video_pbase & ~((1 << size_shift) - 1);
		itv->osd_info->fb_end_aligned_physaddr = itv->osd_info->video_pbase + itv->osd_info->video_buffer_size;
		itv->osd_info->fb_end_aligned_physaddr += (1 << size_shift) - 1;
		itv->osd_info->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
		if (mtrr_add(itv->osd_info->fb_start_aligned_physaddr,
			itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr,
		oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
		oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
		oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
		oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
		if (mtrr_add(oi->fb_start_aligned_physaddr,
			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
			     MTRR_TYPE_WRCOMB, 1) < 0) {
			IVTV_FB_ERR("warning: mtrr_add() failed to add write combining region 0x%08x-0x%08x\n",
				 (unsigned int)itv->osd_info->fb_start_aligned_physaddr,
				 (unsigned int)itv->osd_info->fb_end_aligned_physaddr);
			IVTV_FB_WARN("cannot use mttr\n");
			oi->fb_start_aligned_physaddr = 0;
			oi->fb_end_aligned_physaddr = 0;
		}
	}
#endif /* CONFIG_MTRR */
#endif

	/* Blank the entire osd. */
	memset_io(itv->osd_info->video_vbase, 0, itv->osd_info->video_buffer_size);
	memset_io(oi->video_vbase, 0, oi->video_buffer_size);

	return 0;
}
@@ -1090,20 +1055,24 @@ static int ivtvfb_init_io(struct ivtv *itv)
/* Release any memory we've grabbed & remove mtrr entry */
static void ivtvfb_release_buffers (struct ivtv *itv)
{
	struct osd_info *oi = itv->osd_info;

	/* Release cmap */
	if (itv->osd_info->ivtvfb_info.cmap.len);
	fb_dealloc_cmap(&itv->osd_info->ivtvfb_info.cmap);
	if (oi->ivtvfb_info.cmap.len);
	fb_dealloc_cmap(&oi->ivtvfb_info.cmap);

	/* Release pseudo palette */
	if (itv->osd_info->ivtvfb_info.pseudo_palette)
		kfree(itv->osd_info->ivtvfb_info.pseudo_palette);
	if (oi->ivtvfb_info.pseudo_palette)
		kfree(oi->ivtvfb_info.pseudo_palette);

#ifdef CONFIG_MTRR
	mtrr_del(-1, itv->osd_info->fb_start_aligned_physaddr,
		  (itv->osd_info->fb_end_aligned_physaddr - itv->osd_info->fb_start_aligned_physaddr));
#endif /* CONFIG_MTRR */
	if (oi->fb_end_aligned_physaddr) {
		mtrr_del(-1, oi->fb_start_aligned_physaddr,
			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
	}
#endif

	kfree(itv->osd_info);
	kfree(oi);
	itv->osd_info = NULL;
}