ivtvfb.c revision 77aded6ba51f01335840ce8e18b413067810b68e
132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/*
232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    On Screen Display cx23415 Framebuffer driver
332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    This module presents the cx23415 OSD (onscreen display) framebuffer memory
532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    as a standard Linux /dev/fb style framebuffer device. The framebuffer has
6be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil    support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    mode, there is a choice of a three color depths (12, 15 or 16 bits), but no
832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    local alpha. The colorspace is selectable between rgb & yuv.
932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    Depending on the TV standard configured in the ivtv module at load time,
1032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp.
1132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL)
1232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    or 59.94 (NTSC)
1332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
1532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    Derived from drivers/video/vesafb.c
1732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
1832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    2.6 kernel port:
2032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    Copyright (C) 2004 Matthias Badaire
2132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
2232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
2332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
2432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    Copyright (C) 2006  Ian Armstrong <ian@iarmst.demon.co.uk>
2532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
2632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    This program is free software; you can redistribute it and/or modify
2732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    it under the terms of the GNU General Public License as published by
2832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    the Free Software Foundation; either version 2 of the License, or
2932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    (at your option) any later version.
3032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
3132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    This program is distributed in the hope that it will be useful,
3232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    but WITHOUT ANY WARRANTY; without even the implied warranty of
3332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    GNU General Public License for more details.
3532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
3632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    You should have received a copy of the GNU General Public License
3732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    along with this program; if not, write to the Free Software
3832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
3932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil */
4032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
4132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include <linux/module.h>
4232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include <linux/kernel.h>
4332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include <linux/fb.h>
440f45b8c57e40cca1778b0b75daab65ca139e5bb9Hans Verkuil#include <linux/ivtvfb.h>
4532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
4632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
4732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include <asm/mtrr.h>
4832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#endif
4932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
5032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include "ivtv-driver.h"
5132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include "ivtv-udma.h"
5232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include "ivtv-mailbox.h"
5332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
5432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* card parameters */
55641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_card_id = -1;
56641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_debug = 0;
5732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_laced;
5832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_depth;
5932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_upper;
6032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_left;
6132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_yres;
6232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_xres;
6332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
64641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilmodule_param(ivtvfb_card_id, int, 0444);
65641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilmodule_param_named(debug,ivtvfb_debug, int, 0644);
6632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_laced, bool, 0444);
6732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_depth, int, 0444);
6832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_upper, int, 0444);
6932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_left, int, 0444);
7032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_yres, int, 0444);
7132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_xres, int, 0444);
7232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
73641ed49db6ecf6c539a5eab50a7540542377add1Hans VerkuilMODULE_PARM_DESC(ivtvfb_card_id,
7432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Only use framebuffer of the specified ivtv card (0-31)\n"
7532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault -1: initialize all available framebuffers");
7632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
7732db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(debug,
7832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Debug level (bitmask). Default: errors only\n"
7932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t(debug = 3 gives full debugging)");
8032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Why upper, left, xres, yres, depth, laced ? To match terminology used
8232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   by fbset.
8332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
8432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8532db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_laced,
8632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Interlaced mode\n"
8732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t0=off\n"
8832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t1=on\n"
8932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault off");
9032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
9132db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_depth,
92be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		 "Bits per pixel - 8, 16, 32\n"
9332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 8");
9432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
9532db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_upper,
9632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Vertical start position\n"
9732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 0 (Centered)");
9832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
9932db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_left,
10032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Horizontal start position\n"
10132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 0 (Centered)");
10232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
10332db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_yres,
10432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Display height\n"
10532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 480 (PAL)\n"
10632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t        400 (NTSC)");
10732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
10832db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_xres,
10932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Display width\n"
11032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 640");
11132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11232db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
11332db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_LICENSE("GPL");
11432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* --------------------------------------------------------------------- */
11632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
117641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DBGFLG_WARN  (1 << 0)
118641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DBGFLG_INFO  (1 << 1)
11932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
120641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DEBUG(x, type, fmt, args...) \
12132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	do { \
122641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		if ((x) & ivtvfb_debug) \
1237b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil			printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \
12432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	} while (0)
125641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DEBUG_WARN(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
126641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DEBUG_INFO(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
12732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
12832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Standard kernel messages */
129641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_ERR(fmt, args...)   printk(KERN_ERR  "ivtvfb%d: " fmt, itv->num , ## args)
130641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtvfb%d: " fmt, itv->num , ## args)
131641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_INFO(fmt, args...)  printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args)
13232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
13332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* --------------------------------------------------------------------- */
13432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
13532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_MAX_WIDTH  720
13632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_MAX_HEIGHT 576
13732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
13832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_8      0x00
13932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_16_444 0x03
14032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_16_555 0x02
14132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_16_565 0x01
14232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_32     0x04
14332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
14432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstruct osd_info {
14532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Physical base address */
14632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long video_pbase;
14732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Relative base address (relative to start of decoder memory) */
14832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 video_rbase;
14932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Mapped base address */
15032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	volatile char __iomem *video_vbase;
15132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Buffer size */
15232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 video_buffer_size;
15332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
15432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
15532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* video_base rounded down as required by hardware MTRRs */
15632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long fb_start_aligned_physaddr;
15732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* video_base rounded up as required by hardware MTRRs */
15832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long fb_end_aligned_physaddr;
15932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#endif
16032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
16132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Store the buffer offset */
16232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int set_osd_coords_x;
16332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int set_osd_coords_y;
16432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
16532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Current dimensions (NOT VISIBLE SIZE!) */
16632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int display_width;
16732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int display_height;
16832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int display_byte_stride;
16932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
17032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Current bits per pixel */
17132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int bits_per_pixel;
17232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int bytes_per_pixel;
17332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
17432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Frame buffer stuff */
17532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct fb_info ivtvfb_info;
17632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct fb_var_screeninfo ivtvfb_defined;
17732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct fb_fix_screeninfo ivtvfb_fix;
17832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil};
17932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
18032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstruct ivtv_osd_coords {
18132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long offset;
18232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long max_offset;
18332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int pixel_stride;
18432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int lines;
18532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int x;
18632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int y;
18732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil};
18832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
18932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* --------------------------------------------------------------------- */
19032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
19132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* ivtv API calls for framebuffer related support */
19232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
193641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
19432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				       u32 *fblength)
19532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
19632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 data[CX2341X_MBOX_MAX_DATA];
19732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int rc;
19832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
19932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
20032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	*fbbase = data[0];
20132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	*fblength = data[1];
20232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return rc;
20332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
20432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
205641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_get_osd_coords(struct ivtv *itv,
20632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				      struct ivtv_osd_coords *osd)
20732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
208be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
20932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 data[CX2341X_MBOX_MAX_DATA];
21032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
21132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
21232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
213be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd->offset = data[0] - oi->video_rbase;
214be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd->max_offset = oi->display_width * oi->display_height * 4;
21532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd->pixel_stride = data[1];
21632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd->lines = data[2];
21732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd->x = data[3];
21832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd->y = data[4];
21932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
22032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
22132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
222641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
22332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
224be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
225be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
226be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_width = osd->pixel_stride;
227be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
228be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->set_osd_coords_x += osd->x;
229be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->set_osd_coords_y = osd->y;
23032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
23132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
232be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			osd->offset + oi->video_rbase,
23332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			osd->pixel_stride,
23432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			osd->lines, osd->x, osd->y);
23532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
23632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
237641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
23832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
23932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int osd_height_limit = itv->is_50hz ? 576 : 480;
24032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
24132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Only fail if resolution too high, otherwise fudge the start coords. */
24232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
24332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
24432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
24532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Ensure we don't exceed display limits */
24632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
247641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
24832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_window->top, ivtv_window->height);
24932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_window->top = osd_height_limit - ivtv_window->height;
25032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
25132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
25232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
253641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
25432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_window->left, ivtv_window->width);
25532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
25632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
25732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
25832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the OSD origin */
25932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
26032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
26132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* How much to display */
26232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
26332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
26432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Pass this info back the yuv handler */
26532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_vis_w = ivtv_window->width;
26632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_vis_h = ivtv_window->height;
26732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_x_offset = ivtv_window->left;
26832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_y_offset = ivtv_window->top;
26932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
27032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
27132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
27232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
273641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
27432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				  unsigned long ivtv_dest_addr, void __user *userbuf,
27532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				  int size_in_bytes)
27632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
27732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	DEFINE_WAIT(wait);
27832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int ret = 0;
27932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int got_sig = 0;
28032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
28132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	mutex_lock(&itv->udma.lock);
28232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Map User DMA */
28332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
28432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		mutex_unlock(&itv->udma.lock);
285641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, "
28632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			       "Error with get_user_pages: %d bytes, %d pages returned\n",
28732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			       size_in_bytes, itv->udma.page_count);
28832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
28932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* get_user_pages must have failed completely */
29032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EIO;
29132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
29232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
293641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
29432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		       size_in_bytes, itv->udma.page_count);
29532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
29632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_udma_prepare(itv);
29732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
29832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* if no UDMA is pending and no UDMA is in progress, then the DMA
29932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   is finished */
30032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
30132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* don't interrupt if the DMA is in progress but break off
30232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		   a still pending DMA. */
30332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		got_sig = signal_pending(current);
30432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
30532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
30632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		got_sig = 0;
30732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		schedule();
30832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
30932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	finish_wait(&itv->dma_waitq, &wait);
31032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
31132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Unmap Last DMA Xfer */
31232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_udma_unmap(itv);
31332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	mutex_unlock(&itv->udma.lock);
31432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (got_sig) {
31532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		IVTV_DEBUG_INFO("User stopped OSD\n");
31632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINTR;
31732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
31832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
31932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return ret;
32032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
32132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
322641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
323be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			      unsigned long dest_offset, int count)
32432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
32532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	DEFINE_WAIT(wait);
326aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	struct osd_info *oi = itv->osd_info;
32732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
32832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Nothing to do */
32932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (count == 0) {
330641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n");
33132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
33232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
33332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
33432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check Total FB Size */
335aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	if ((dest_offset + count) > oi->video_buffer_size) {
336641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
337aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong			dest_offset + count, oi->video_buffer_size);
33832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -E2BIG;
33932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
34032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
34132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Not fatal, but will have undesirable results */
34232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if ((unsigned long)source & 3)
343641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
344be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			(unsigned long)source);
34532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
34632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (dest_offset & 3)
347641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
34832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
34932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (count & 3)
350641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
35132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
35232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check Source */
35332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
354641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
35532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			(unsigned long)source);
35632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
357641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
35832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			dest_offset, (unsigned long)source,
35932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			count);
36032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
36132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
36232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
36332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* OSD Address to send DMA to */
36433c0fcad2160bc211272295e862c6f708118d006Hans Verkuil	dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
36532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
36632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Fill Buffers */
367641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
36832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
36932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
37032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
37132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
37232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	DEFINE_WAIT(wait);
37332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *)info->par;
374be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	int rc = 0;
37532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
37632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (cmd) {
37732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case FBIOGET_VBLANK: {
37832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			struct fb_vblank vblank;
37932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			u32 trace;
38032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
38132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
38232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil					FB_VBLANK_HAVE_VSYNC;
383be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			trace = read_reg(0x028c0) >> 16;
38432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (itv->is_50hz && trace > 312) trace -= 312;
38532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			else if (itv->is_60hz && trace > 262) trace -= 262;
38632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
387a158f3559334c6314c7876390caffe88c9fdb64dHans Verkuil			vblank.count = itv->last_vsync_field;
38832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			vblank.vcount = trace;
38932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			vblank.hcount = 0;
39032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
39132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				return -EFAULT;
39232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return 0;
39332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
39432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
395be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		case FBIO_WAITFORVSYNC:
39632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
39784149a0f70a73385ee7fbb77024544cbed4fe16dHans Verkuil			if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
398be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			finish_wait(&itv->vsync_waitq, &wait);
39932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return rc;
40032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
401d715e766ddf4786a06abe6a841e956ad8a875963Hans Verkuil		case IVTVFB_IOC_DMA_FRAME: {
402d715e766ddf4786a06abe6a841e956ad8a875963Hans Verkuil			struct ivtvfb_dma_frame args;
40332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
404641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
40532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
40632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				return -EFAULT;
40732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
408641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
40932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
41032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
41132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		default:
412641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
41332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
41432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
41532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
41632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
41732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
41832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Framebuffer device handling */
41932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
42032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
42132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
422aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	struct osd_info *oi = itv->osd_info;
42332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv_osd_coords ivtv_osd;
42432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct v4l2_rect ivtv_window;
425aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	int osd_mode = -1;
42632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
427641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
42832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
42932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Select color space */
43032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->nonstd) /* YUV */
431be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
43232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else /* RGB  */
433be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
43432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
435aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	/* Set the color mode */
43632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (var->bits_per_pixel) {
43732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case 8:
438aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong			osd_mode = IVTV_OSD_BPP_8;
43932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
44032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case 32:
441aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong			osd_mode = IVTV_OSD_BPP_32;
44232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
44332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case 16:
44432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			switch (var->green.length) {
44532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 4:
446aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong				osd_mode = IVTV_OSD_BPP_16_444;
44732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
44832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 5:
449aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong				osd_mode = IVTV_OSD_BPP_16_555;
45032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
45132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 6:
452aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong				osd_mode = IVTV_OSD_BPP_16_565;
45332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
45432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			default:
455641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil				IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
45632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			}
45732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
45832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		default:
459641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
46032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
46132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
4626659e3ed559db2e730947268f9d57869b7a9016cIan Armstrong	/* Set video mode. Although rare, the display can become scrambled even
4636659e3ed559db2e730947268f9d57869b7a9016cIan Armstrong	   if we don't change mode. Always 'bounce' to osd_mode via mode 0 */
4646659e3ed559db2e730947268f9d57869b7a9016cIan Armstrong	if (osd_mode != -1) {
465aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
466aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
467aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	}
468aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong
469aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	oi->bits_per_pixel = var->bits_per_pixel;
470aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	oi->bytes_per_pixel = var->bits_per_pixel / 8;
47132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
47232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the flicker filter */
47332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (var->vmode & FB_VMODE_MASK) {
47432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case FB_VMODE_NONINTERLACED: /* Filter on */
47532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
47632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
47732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case FB_VMODE_INTERLACED: /* Filter off */
47832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
47932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
48032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		default:
481641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
48232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
48332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
48432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Read the current osd info */
485641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	ivtvfb_get_osd_coords(itv, &ivtv_osd);
48632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
48732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Now set the OSD to the size we want */
48832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.pixel_stride = var->xres_virtual;
48932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.lines = var->yres_virtual;
49032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.x = 0;
49132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.y = 0;
492641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	ivtvfb_set_osd_coords(itv, &ivtv_osd);
49332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
49432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Can't seem to find the right API combo for this.
49532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   Use another function which does what we need through direct register access. */
49632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.width = var->xres;
49732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.height = var->yres;
49832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
49932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Minimum margin cannot be 0, as X won't allow such a mode */
500be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!var->upper_margin) var->upper_margin++;
501be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!var->left_margin) var->left_margin++;
50232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.top = var->upper_margin - 1;
50332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.left = var->left_margin - 1;
50432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
505641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	ivtvfb_set_display_window(itv, &ivtv_window);
50632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
50777aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	/* Pass screen size back to yuv handler */
50877aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
50977aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	itv->yuv_info.osd_full_h = ivtv_osd.lines;
51077aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
51132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Force update of yuv registers */
51232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.yuv_forced_update = 1;
51332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
514641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
515be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres, var->yres,
516be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres_virtual, var->yres_virtual,
517be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->bits_per_pixel);
51832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
519641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
520be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->left_margin, var->upper_margin);
52132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
522641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display filter: %s\n",
523be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
524641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
52532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
52632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
52732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
52832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
52932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
53032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
531be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
532be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
533641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
53432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
53532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	strcpy(fix->id, "cx23415 TV out");
536be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->smem_start = oi->video_pbase;
537be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->smem_len = oi->video_buffer_size;
53832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->type = FB_TYPE_PACKED_PIXELS;
539be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
54032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->xpanstep = 1;
54132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->ypanstep = 1;
54232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->ywrapstep = 0;
543be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->line_length = oi->display_byte_stride;
54432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->accel = FB_ACCEL_NONE;
54532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
54632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
54732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
54832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Check the requested display mode, returning -EINVAL if we can't
54932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   handle it. */
55032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
55132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
55232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
553be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
55468a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	int osd_height_limit;
55568a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	u32 pixclock, hlimit, vlimit;
55632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
557641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
55832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
55968a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	/* Set base references for mode calcs. */
56068a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	if (itv->is_50hz) {
56168a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		pixclock = 84316;
56268a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		hlimit = 776;
56368a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		vlimit = 591;
56468a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		osd_height_limit = 576;
56568a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	}
56668a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	else {
56768a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		pixclock = 83926;
56868a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		hlimit = 776;
56968a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		vlimit = 495;
57068a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		osd_height_limit = 480;
57168a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	}
57268a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong
57332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
57432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->transp.offset = 24;
57532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->transp.length = 8;
57632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->red.offset = 16;
57732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->red.length = 8;
57832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->green.offset = 8;
57932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->green.length = 8;
58032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->blue.offset = 0;
58132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->blue.length = 8;
58232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
58332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else if (var->bits_per_pixel == 16) {
58432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* To find out the true mode, check green length */
58532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		switch (var->green.length) {
58632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 4:
58732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.offset = 8;
58832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.length = 4;
58932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.offset = 4;
59032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.length = 4;
59132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.offset = 0;
59232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.length = 4;
593459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.offset = 12;
594459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.length = 1;
59532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
59632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 5:
59732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.offset = 10;
59832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.length = 5;
59932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.offset = 5;
60032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.length = 5;
60132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.offset = 0;
60232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.length = 5;
603459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.offset = 15;
604459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.length = 1;
60532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
60632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			default:
60732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.offset = 11;
60832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.length = 5;
60932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.offset = 5;
61032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.length = 6;
61132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.offset = 0;
61232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.length = 5;
613459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.offset = 0;
614459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.length = 0;
61532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
61632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
61732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
61832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else {
619641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
62032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
62132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
62232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
62332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check the resolution */
6246b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
6256b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
6266b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong				var->xres, var->yres);
6276b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		return -EINVAL;
62832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
62932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
6306b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	/* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
6316b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
6326b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	    var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
6336b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	    var->xres_virtual < var->xres ||
6346b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	    var->yres_virtual < var->yres) {
6356b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
6366b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong			var->xres_virtual, var->yres_virtual);
6376b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		return -EINVAL;
63832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
63932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
64032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Some extra checks if in 8 bit mode */
64132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->bits_per_pixel == 8) {
64232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Width must be a multiple of 4 */
64332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres & 3) {
644641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
64532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
64632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
64732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres_virtual & 3) {
648641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
64932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
65032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
65132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
65232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else if (var->bits_per_pixel == 16) {
65332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Width must be a multiple of 2 */
65432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres & 1) {
655641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
65632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
65732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
65832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres_virtual & 1) {
659641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
66032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
66132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
66232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
66332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
66432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Now check the offsets */
66532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
666641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
667be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
66832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
66932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
67032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
67132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check pixel format */
67232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->nonstd > 1) {
673641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
67432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
67532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
67632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
67732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check video mode */
67832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
67932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
680641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
68132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
68232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
68332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
68432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check the left & upper margins
68532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   If the margins are too large, just center the screen
68632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   (enforcing margins causes too many problems) */
68732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
68832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
68932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
69032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
69132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
69232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
69332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
69432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
69532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Maintain overall 'size' for a constant refresh rate */
69668a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	var->right_margin = hlimit - var->left_margin - var->xres;
69768a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	var->lower_margin = vlimit - var->upper_margin - var->yres;
69832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
69932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Fixed sync times */
70032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	var->hsync_len = 24;
70132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	var->vsync_len = 2;
70232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
70332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Non-interlaced / interlaced mode is used to switch the OSD filter
70432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   on or off. Adjust the clock timings to maintain a constant
70532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   vertical refresh rate. */
70632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
70768a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		var->pixclock = pixclock / 2;
70868a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	else
70968a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		var->pixclock = pixclock;
71032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
711641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
712be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres, var->yres,
713be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres_virtual, var->yres_virtual,
71432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		      var->bits_per_pixel);
71532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
716641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
717be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->left_margin, var->upper_margin);
71832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
719641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display filter: %s\n",
720be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
721641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
72232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
72332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
72432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
72532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
72632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
72732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *) info->par;
728641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
729be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	return _ivtvfb_check_var(var, itv);
73032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
73132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
73232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
73332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
73432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 osd_pan_index;
73532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *) info->par;
73632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
73732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
738be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	write_reg(osd_pan_index, 0x02A0C);
73932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
74032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Pass this info back the yuv handler */
74132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_x_pan = var->xoffset;
74232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_y_pan = var->yoffset;
74332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Force update of yuv registers */
74432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.yuv_forced_update = 1;
74532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
74632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
74732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
74832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_set_par(struct fb_info *info)
74932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
75032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int rc = 0;
75132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *) info->par;
75232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
753641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
75432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
75532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	rc = ivtvfb_set_var(itv, &info->var);
75632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtvfb_pan_display(&info->var, info);
757be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	ivtvfb_get_fix(itv, &info->fix);
75832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return rc;
75932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
76032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
76132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
76232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				unsigned blue, unsigned transp,
76332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				struct fb_info *info)
76432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
76532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 color, *palette;
766be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct ivtv *itv = (struct ivtv *)info->par;
76732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
76832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (regno >= info->cmap.len)
76932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
77032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
77132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
77232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (info->var.bits_per_pixel <= 8) {
77332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		write_reg(regno, 0x02a30);
77432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		write_reg(color, 0x02a34);
775be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		return 0;
77632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
777be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (regno >= 16)
778be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		return -EINVAL;
77932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
780be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	palette = info->pseudo_palette;
781be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (info->var.bits_per_pixel == 16) {
782be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		switch (info->var.green.length) {
783be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			case 4:
784be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				color = ((red & 0xf000) >> 4) |
785be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((green & 0xf000) >> 8) |
786be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((blue & 0xf000) >> 12);
787be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				break;
788be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			case 5:
789be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				color = ((red & 0xf800) >> 1) |
790be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((green & 0xf800) >> 6) |
791be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((blue & 0xf800) >> 11);
792be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				break;
793be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			case 6:
794be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				color = (red & 0xf800 ) |
795be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((green & 0xfc00) >> 5) |
796be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((blue & 0xf800) >> 11);
797be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				break;
79832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
79932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
800be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	palette[regno] = color;
80132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
80232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
80332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
80432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* We don't really support blanking. All this does is enable or
80532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   disable the OSD. */
80632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_blank(int blank_mode, struct fb_info *info)
80732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
80832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *)info->par;
80932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
810641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
81132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (blank_mode) {
81232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_UNBLANK:
81332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
81432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		break;
81532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_NORMAL:
81632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_HSYNC_SUSPEND:
81732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_VSYNC_SUSPEND:
81832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_POWERDOWN:
81932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
82032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		break;
82132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
82232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
82332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
82432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
82532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic struct fb_ops ivtvfb_ops = {
82632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.owner = THIS_MODULE,
82732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_check_var   = ivtvfb_check_var,
82832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_set_par     = ivtvfb_set_par,
82932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_setcolreg   = ivtvfb_setcolreg,
83032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_fillrect    = cfb_fillrect,
83132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_copyarea    = cfb_copyarea,
83232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_imageblit   = cfb_imageblit,
83332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_cursor      = NULL,
83432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_ioctl       = ivtvfb_ioctl,
83532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_pan_display = ivtvfb_pan_display,
83632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_blank       = ivtvfb_blank,
83732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil};
83832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
83932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Initialization */
84032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
84132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
84232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Setup our initial video mode */
84332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_init_vidmode(struct ivtv *itv)
84432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
845be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
84632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct v4l2_rect start_window;
847be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	int max_height;
84832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
84932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Color mode */
85032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8516b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32)
8526b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		osd_depth = 8;
853be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->bits_per_pixel = osd_depth;
854be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->bytes_per_pixel = oi->bits_per_pixel / 8;
85532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
85632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Horizontal size & position */
85732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8586b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	if (osd_xres > 720)
8596b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		osd_xres = 720;
86032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
86132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
86232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_depth == 8)
86332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_xres &= ~3;
86432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else if (osd_depth == 16)
86532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_xres &= ~1;
86632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8676b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	start_window.width = osd_xres ? osd_xres : 640;
86832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
86932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check horizontal start (osd_left). */
87032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_left && osd_left + start_window.width > 721) {
871641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Invalid osd_left - assuming default\n");
87232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_left = 0;
87332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
87432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
87532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Hardware coords start at 0, user coords start at 1. */
876be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd_left--;
87732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
878be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
87932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
880be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_byte_stride =
881be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			start_window.width * oi->bytes_per_pixel;
88232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
88332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Vertical size & position */
88432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
88532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	max_height = itv->is_50hz ? 576 : 480;
88632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
887be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (osd_yres > max_height)
888be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		osd_yres = max_height;
88932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8906b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	start_window.height = osd_yres ? osd_yres : itv->is_50hz ? 480 : 400;
89132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
89232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check vertical start (osd_upper). */
89332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_upper + start_window.height > max_height + 1) {
894641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Invalid osd_upper - assuming default\n");
89532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_upper = 0;
89632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
89732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
89832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Hardware coords start at 0, user coords start at 1. */
899be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd_upper--;
90032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
90132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
90232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
903be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_width = start_window.width;
904be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_height = start_window.height;
90532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
90632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Generate a valid fb_var_screeninfo */
90732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
908be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.xres = oi->display_width;
909be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.yres = oi->display_height;
910be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.xres_virtual = oi->display_width;
911be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.yres_virtual = oi->display_height;
912be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
913be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
914be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.left_margin = start_window.left + 1;
915be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.upper_margin = start_window.top + 1;
916be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
917be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.nonstd = 0;
91832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
91932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* We've filled in the most data, let the usual mode check
92032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   routine fill in the rest. */
921be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	_ivtvfb_check_var(&oi->ivtvfb_defined, itv);
92232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
92332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Generate valid fb_fix_screeninfo */
92432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
925be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
92632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
92732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Generate valid fb_info */
92832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
929be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.node = -1;
930be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
931be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.fbops = &ivtvfb_ops;
932be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.par = itv;
933be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.var = oi->ivtvfb_defined;
934be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.fix = oi->ivtvfb_fix;
935be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
936be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.fbops = &ivtvfb_ops;
93732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
93832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Supply some monitor specs. Bogus values will do for now */
939be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.hfmin = 8000;
940be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.hfmax = 70000;
941be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.vfmin = 10;
942be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.vfmax = 100;
94332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
94432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Allocate color map */
945be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
946641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("abort, unable to alloc cmap\n");
94732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENOMEM;
94832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
94932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
95032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Allocate the pseudo palette */
951be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
95232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
953be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!oi->ivtvfb_info.pseudo_palette) {
954641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
95532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENOMEM;
95632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
95732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
95832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
95932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
96032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
96132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
96232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
96332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_init_io(struct ivtv *itv)
96432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
965be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
966be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
96726e9d599561e9a964bd4d7c2be0029db8aaff852Hans Verkuil	mutex_lock(&itv->serialize_lock);
9686e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil	if (ivtv_init_on_first_open(itv)) {
96926e9d599561e9a964bd4d7c2be0029db8aaff852Hans Verkuil		mutex_unlock(&itv->serialize_lock);
970641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Failed to initialize ivtv\n");
9716e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil		return -ENXIO;
9726e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil	}
97326e9d599561e9a964bd4d7c2be0029db8aaff852Hans Verkuil	mutex_unlock(&itv->serialize_lock);
9746e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil
975641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
97632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
97732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* The osd buffer size depends on the number of video buffers allocated
97832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   on the PVR350 itself. For now we'll hardcode the smallest osd buffer
97932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   size to prevent any overlap. */
980be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->video_buffer_size = 1704960;
98132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
982be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
983be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->video_vbase = itv->dec_mem + oi->video_rbase;
98432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
985be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!oi->video_vbase) {
986641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
987be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		     oi->video_buffer_size, oi->video_pbase);
98832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EIO;
98932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
99032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
991641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
992be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->video_pbase, oi->video_vbase,
993be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->video_buffer_size / 1024);
99432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
99532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
99632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	{
99732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Find the largest power of two that maps the whole buffer */
99832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		int size_shift = 31;
99932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1000be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		while (!(oi->video_buffer_size & (1 << size_shift))) {
100132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			size_shift--;
100232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
100332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		size_shift++;
1004be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1005be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1006be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1007be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1008be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		if (mtrr_add(oi->fb_start_aligned_physaddr,
1009be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
101032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			     MTRR_TYPE_WRCOMB, 1) < 0) {
1011641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_INFO("disabled mttr\n");
1012be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_start_aligned_physaddr = 0;
1013be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_end_aligned_physaddr = 0;
101432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
101532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
1016be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil#endif
101732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
101832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Blank the entire osd. */
1019be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	memset_io(oi->video_vbase, 0, oi->video_buffer_size);
102032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
102132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
102232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
102332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
102432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Release any memory we've grabbed & remove mtrr entry */
102532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic void ivtvfb_release_buffers (struct ivtv *itv)
102632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
1027be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
1028be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
102932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Release cmap */
1030136280322d894e6ec07187f2427b00c3d64ad066Adrian Bunk	if (oi->ivtvfb_info.cmap.len)
1031136280322d894e6ec07187f2427b00c3d64ad066Adrian Bunk		fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
103232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
103332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Release pseudo palette */
1034be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (oi->ivtvfb_info.pseudo_palette)
1035be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		kfree(oi->ivtvfb_info.pseudo_palette);
103632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
103732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
1038be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (oi->fb_end_aligned_physaddr) {
1039be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		mtrr_del(-1, oi->fb_start_aligned_physaddr,
1040be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1041be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	}
1042be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil#endif
104332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1044be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	kfree(oi);
104532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->osd_info = NULL;
104632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
104732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
104832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Initialize the specified card */
104932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1050be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuilstatic int ivtvfb_init_card(struct ivtv *itv)
105132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
105232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int rc;
105332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
105432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (itv->osd_info) {
1055641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
105632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EBUSY;
105732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
105832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
105932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
106032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (itv->osd_info == 0) {
1061641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Failed to allocate memory for osd_info\n");
106232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENOMEM;
106332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
106432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
106532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Find & setup the OSD buffer */
1066be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if ((rc = ivtvfb_init_io(itv)))
106732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return rc;
106832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
106932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the startup video mode information */
1070be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if ((rc = ivtvfb_init_vidmode(itv))) {
107132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtvfb_release_buffers(itv);
107232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return rc;
107332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
107432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
107532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Register the framebuffer */
107632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
107732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtvfb_release_buffers(itv);
107832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
107932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
108032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
108132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->osd_video_pbase = itv->osd_info->video_pbase;
108232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
108332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the card to the requested mode */
108432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
108532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
108632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set color 0 to black */
108732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg(0, 0x02a30);
108832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg(0, 0x02a34);
108932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
109032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Enable the osd */
109132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
109232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
109332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Allocate DMA */
109432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_udma_alloc(itv);
109532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
109632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
109732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
109832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
109932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int __init ivtvfb_init(void)
110032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
110132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv;
110232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int i, registered = 0;
110332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1104641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
1105641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		printk(KERN_ERR "ivtvfb:  ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
110632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		     IVTV_MAX_CARDS - 1);
110732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
110832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
110932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
111032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Locate & initialise all cards supporting an OSD. */
111132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	for (i = 0; i < ivtv_cards_active; i++) {
1112641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		if (ivtvfb_card_id != -1 && i != ivtvfb_card_id)
111332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			continue;
111432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		itv = ivtv_cards[i];
111532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
111632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (ivtvfb_init_card(itv) == 0) {
1117641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil				IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i);
111832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				registered++;
111932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			}
112032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
112132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
112232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (!registered) {
11237b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil		printk(KERN_ERR "ivtvfb:  no cards found");
112432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENODEV;
112532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
112632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
112732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
112832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
112932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic void ivtvfb_cleanup(void)
113032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
113132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv;
113232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int i;
113332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11347b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil	printk(KERN_INFO "ivtvfb:  Unloading framebuffer module\n");
113532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
113632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	for (i = 0; i < ivtv_cards_active; i++) {
113732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		itv = ivtv_cards[i];
113832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
1139d343d7f9792ac1790757cb35a419b8b0b5210917Hans Verkuil			if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
1140d343d7f9792ac1790757cb35a419b8b0b5210917Hans Verkuil				IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", i);
1141d343d7f9792ac1790757cb35a419b8b0b5210917Hans Verkuil				return;
1142d343d7f9792ac1790757cb35a419b8b0b5210917Hans Verkuil			}
1143641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i);
114432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
114532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtvfb_release_buffers(itv);
114632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			itv->osd_video_pbase = 0;
114732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
114832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
114932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
115032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
115132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_init(ivtvfb_init);
115232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_exit(ivtvfb_cleanup);
1153