ivtvfb.c revision 7b3a0d49e3e929b810ade38926342faca53e867d
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 */
5532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtv_fb_card_id = -1;
5632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtv_fb_debug = 0;
5732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_laced;
5832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_compat;
5932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_depth;
6032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_upper;
6132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_left;
6232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_yres;
6332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_xres;
6432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
6532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(ivtv_fb_card_id, int, 0444);
6632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param_named(debug,ivtv_fb_debug, int, 0644);
6732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_laced, bool, 0444);
6832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_compat, bool, 0444);
6932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_depth, int, 0444);
7032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_upper, int, 0444);
7132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_left, int, 0444);
7232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_yres, int, 0444);
7332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_xres, int, 0444);
7432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
7532db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(ivtv_fb_card_id,
7632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Only use framebuffer of the specified ivtv card (0-31)\n"
7732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault -1: initialize all available framebuffers");
7832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
7932db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(debug,
8032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Debug level (bitmask). Default: errors only\n"
8132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t(debug = 3 gives full debugging)");
8232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8332db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_compat,
8432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Compatibility mode - Display size is locked (use for old X drivers)\n"
8532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t0=off\n"
8632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t1=on\n"
8732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault off");
8832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Why upper, left, xres, yres, depth, laced ? To match terminology used
9032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   by fbset.
9132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
9232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
9332db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_laced,
9432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Interlaced mode\n"
9532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t0=off\n"
9632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t1=on\n"
9732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault off");
9832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
9932db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_depth,
100be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		 "Bits per pixel - 8, 16, 32\n"
10132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 8");
10232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
10332db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_upper,
10432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Vertical start position\n"
10532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 0 (Centered)");
10632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
10732db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_left,
10832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Horizontal start position\n"
10932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 0 (Centered)");
11032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11132db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_yres,
11232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Display height\n"
11332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 480 (PAL)\n"
11432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t        400 (NTSC)");
11532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11632db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_xres,
11732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Display width\n"
11832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 640");
11932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
12032db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
12132db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_LICENSE("GPL");
12232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
12332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* --------------------------------------------------------------------- */
12432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
12532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_FB_DBGFLG_WARN  (1 << 0)
12632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_FB_DBGFLG_INFO  (1 << 1)
12732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
12832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_FB_DEBUG(x, type, fmt, args...) \
12932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	do { \
13032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if ((x) & ivtv_fb_debug) \
1317b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil			printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \
13232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	} while (0)
13332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_FB_DEBUG_WARN(fmt, args...)  IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args)
13432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_FB_DEBUG_INFO(fmt, args...)  IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args)
13532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
13632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Standard kernel messages */
1377b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil#define IVTV_FB_ERR(fmt, args...)   printk(KERN_ERR  "ivtvfb%d: " fmt, itv->num , ## args)
1387b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil#define IVTV_FB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtvfb%d: " fmt, itv->num , ## args)
1397b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil#define IVTV_FB_INFO(fmt, args...)  printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args)
14032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
14132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* --------------------------------------------------------------------- */
14232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
14332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_MAX_WIDTH  720
14432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_MAX_HEIGHT 576
14532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
14632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_8      0x00
14732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_16_444 0x03
14832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_16_555 0x02
14932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_16_565 0x01
15032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_32     0x04
15132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
15232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstruct osd_info {
15332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Physical base address */
15432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long video_pbase;
15532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Relative base address (relative to start of decoder memory) */
15632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 video_rbase;
15732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Mapped base address */
15832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	volatile char __iomem *video_vbase;
15932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Buffer size */
16032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 video_buffer_size;
16132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
16232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
16332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* video_base rounded down as required by hardware MTRRs */
16432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long fb_start_aligned_physaddr;
16532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* video_base rounded up as required by hardware MTRRs */
16632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long fb_end_aligned_physaddr;
16732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#endif
16832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
169aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	/* Current osd mode */
170aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	int osd_mode;
171aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong
17232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Store the buffer offset */
17332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int set_osd_coords_x;
17432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int set_osd_coords_y;
17532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
17632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Current dimensions (NOT VISIBLE SIZE!) */
17732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int display_width;
17832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int display_height;
17932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int display_byte_stride;
18032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
18132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Current bits per pixel */
18232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int bits_per_pixel;
18332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int bytes_per_pixel;
18432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
18532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Frame buffer stuff */
18632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct fb_info ivtvfb_info;
18732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct fb_var_screeninfo ivtvfb_defined;
18832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct fb_fix_screeninfo ivtvfb_fix;
18932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil};
19032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
19132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstruct ivtv_osd_coords {
19232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long offset;
19332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long max_offset;
19432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int pixel_stride;
19532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int lines;
19632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int x;
19732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int y;
19832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil};
19932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
20032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* --------------------------------------------------------------------- */
20132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
20232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* ivtv API calls for framebuffer related support */
20332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
20432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
20532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				       u32 *fblength)
20632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
20732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 data[CX2341X_MBOX_MAX_DATA];
20832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int rc;
20932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
21032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
21132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	*fbbase = data[0];
21232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	*fblength = data[1];
21332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return rc;
21432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
21532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
21632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtv_fb_get_osd_coords(struct ivtv *itv,
21732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				      struct ivtv_osd_coords *osd)
21832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
219be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
22032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 data[CX2341X_MBOX_MAX_DATA];
22132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
22232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
22332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
224be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd->offset = data[0] - oi->video_rbase;
225be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd->max_offset = oi->display_width * oi->display_height * 4;
22632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd->pixel_stride = data[1];
22732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd->lines = data[2];
22832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd->x = data[3];
22932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd->y = data[4];
23032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
23132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
23232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
23332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
23432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
235be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
236be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
237be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_width = osd->pixel_stride;
238be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
239be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->set_osd_coords_x += osd->x;
240be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->set_osd_coords_y = osd->y;
24132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
24232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
243be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			osd->offset + oi->video_rbase,
24432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			osd->pixel_stride,
24532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			osd->lines, osd->x, osd->y);
24632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
24732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
24832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
24932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
25032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int osd_height_limit = itv->is_50hz ? 576 : 480;
25132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
25232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Only fail if resolution too high, otherwise fudge the start coords. */
25332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
25432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
25532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
25632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Ensure we don't exceed display limits */
25732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
258be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
25932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_window->top, ivtv_window->height);
26032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_window->top = osd_height_limit - ivtv_window->height;
26132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
26232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
26332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
264be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
26532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_window->left, ivtv_window->width);
26632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
26732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
26832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
26932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the OSD origin */
27032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
27132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
27232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* How much to display */
27332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
27432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
27532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Pass this info back the yuv handler */
27632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_vis_w = ivtv_window->width;
27732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_vis_h = ivtv_window->height;
27832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_x_offset = ivtv_window->left;
27932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_y_offset = ivtv_window->top;
28032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
28132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
28232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
28332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
28432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv,
28532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				  unsigned long ivtv_dest_addr, void __user *userbuf,
28632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				  int size_in_bytes)
28732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
28832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	DEFINE_WAIT(wait);
28932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int ret = 0;
29032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int got_sig = 0;
29132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
29232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	mutex_lock(&itv->udma.lock);
29332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Map User DMA */
29432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
29532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		mutex_unlock(&itv->udma.lock);
29632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, "
29732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			       "Error with get_user_pages: %d bytes, %d pages returned\n",
29832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			       size_in_bytes, itv->udma.page_count);
29932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
30032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* get_user_pages must have failed completely */
30132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EIO;
30232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
30332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
30432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
30532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		       size_in_bytes, itv->udma.page_count);
30632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
30732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_udma_prepare(itv);
30832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
30932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* if no UDMA is pending and no UDMA is in progress, then the DMA
31032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   is finished */
31132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
31232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* don't interrupt if the DMA is in progress but break off
31332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		   a still pending DMA. */
31432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		got_sig = signal_pending(current);
31532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
31632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
31732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		got_sig = 0;
31832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		schedule();
31932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
32032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	finish_wait(&itv->dma_waitq, &wait);
32132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
32232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Unmap Last DMA Xfer */
32332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_udma_unmap(itv);
32432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	mutex_unlock(&itv->udma.lock);
32532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (got_sig) {
32632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		IVTV_DEBUG_INFO("User stopped OSD\n");
32732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINTR;
32832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
32932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
33032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return ret;
33132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
33232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
333be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuilstatic int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
334be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			      unsigned long dest_offset, int count)
33532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
33632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	DEFINE_WAIT(wait);
337aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	struct osd_info *oi = itv->osd_info;
33832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
33932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Nothing to do */
34032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (count == 0) {
34132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n");
34232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
34332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
34432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
34532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check Total FB Size */
346aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	if ((dest_offset + count) > oi->video_buffer_size) {
347be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
348aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong			dest_offset + count, oi->video_buffer_size);
34932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -E2BIG;
35032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
35132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
35232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Not fatal, but will have undesirable results */
35332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if ((unsigned long)source & 3)
354be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
355be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			(unsigned long)source);
35632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
35732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (dest_offset & 3)
358be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
35932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
36032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (count & 3)
361be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count);
36232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
36332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check Source */
36432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
365be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n",
36632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			(unsigned long)source);
36732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
368be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
36932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			dest_offset, (unsigned long)source,
37032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			count);
37132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
37232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
37332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
37432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* OSD Address to send DMA to */
37533c0fcad2160bc211272295e862c6f708118d006Hans Verkuil	dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
37632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
37732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Fill Buffers */
37832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count);
37932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
38032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
38132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
38232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
38332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	DEFINE_WAIT(wait);
38432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *)info->par;
385be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	int rc = 0;
38632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
38732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (cmd) {
38832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case FBIOGET_VBLANK: {
38932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			struct fb_vblank vblank;
39032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			u32 trace;
39132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
39232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
39332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil					FB_VBLANK_HAVE_VSYNC;
394be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			trace = read_reg(0x028c0) >> 16;
39532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (itv->is_50hz && trace > 312) trace -= 312;
39632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			else if (itv->is_60hz && trace > 262) trace -= 262;
39732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
398a158f3559334c6314c7876390caffe88c9fdb64dHans Verkuil			vblank.count = itv->last_vsync_field;
39932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			vblank.vcount = trace;
40032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			vblank.hcount = 0;
40132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
40232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				return -EFAULT;
40332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return 0;
40432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
40532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
406be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		case FBIO_WAITFORVSYNC:
40732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
40884149a0f70a73385ee7fbb77024544cbed4fe16dHans Verkuil			if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
409be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			finish_wait(&itv->vsync_waitq, &wait);
41032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return rc;
41132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
412d715e766ddf4786a06abe6a841e956ad8a875963Hans Verkuil		case IVTVFB_IOC_DMA_FRAME: {
413d715e766ddf4786a06abe6a841e956ad8a875963Hans Verkuil			struct ivtvfb_dma_frame args;
41432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
415d715e766ddf4786a06abe6a841e956ad8a875963Hans Verkuil			IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
41632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
41732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				return -EFAULT;
41832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
41932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
42032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
42132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
42232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		default:
423c6f95d16e0da4d909afc787a3a3dfc504be12177Hans Verkuil			IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
42432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
42532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
42632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
42732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
42832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
42932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Framebuffer device handling */
43032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
43132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
43232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
433aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	struct osd_info *oi = itv->osd_info;
43432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv_osd_coords ivtv_osd;
43532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct v4l2_rect ivtv_window;
436aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	int osd_mode = -1;
43732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
43832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n");
43932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
44032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Select color space */
44132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->nonstd) /* YUV */
442be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
44332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else /* RGB  */
444be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
44532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
446aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	/* Set the color mode */
44732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (var->bits_per_pixel) {
44832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case 8:
449aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong			osd_mode = IVTV_OSD_BPP_8;
45032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
45132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case 32:
452aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong			osd_mode = IVTV_OSD_BPP_32;
45332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
45432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case 16:
45532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			switch (var->green.length) {
45632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 4:
457aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong				osd_mode = IVTV_OSD_BPP_16_444;
45832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
45932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 5:
460aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong				osd_mode = IVTV_OSD_BPP_16_555;
46132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
46232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 6:
463aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong				osd_mode = IVTV_OSD_BPP_16_565;
46432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
46532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			default:
46632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
46732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			}
46832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
46932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		default:
47032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
47132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
47232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
473aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	/* Change osd mode if needed.
474aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	   Although rare, things can go wrong. The extra mode
475aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	   change seems to help... */
476aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	if (osd_mode != -1 && osd_mode != oi->osd_mode) {
477aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
478aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
479aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong		oi->osd_mode = osd_mode;
480aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	}
481aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong
482aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	oi->bits_per_pixel = var->bits_per_pixel;
483aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	oi->bytes_per_pixel = var->bits_per_pixel / 8;
48432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
48532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the flicker filter */
48632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (var->vmode & FB_VMODE_MASK) {
48732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case FB_VMODE_NONINTERLACED: /* Filter on */
48832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
48932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
49032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case FB_VMODE_INTERLACED: /* Filter off */
49132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
49232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
49332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		default:
49432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
49532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
49632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
49732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Read the current osd info */
49832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_fb_get_osd_coords(itv, &ivtv_osd);
49932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
50032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Now set the OSD to the size we want */
50132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.pixel_stride = var->xres_virtual;
50232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.lines = var->yres_virtual;
50332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.x = 0;
50432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.y = 0;
50532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_fb_set_osd_coords(itv, &ivtv_osd);
50632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
50732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Can't seem to find the right API combo for this.
50832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   Use another function which does what we need through direct register access. */
50932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.width = var->xres;
51032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.height = var->yres;
51132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
51232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Minimum margin cannot be 0, as X won't allow such a mode */
513be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!var->upper_margin) var->upper_margin++;
514be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!var->left_margin) var->left_margin++;
51532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.top = var->upper_margin - 1;
51632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.left = var->left_margin - 1;
51732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
51832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_fb_set_display_window(itv, &ivtv_window);
51932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
52032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Force update of yuv registers */
52132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.yuv_forced_update = 1;
52232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
523be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
524be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres, var->yres,
525be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres_virtual, var->yres_virtual,
526be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->bits_per_pixel);
52732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
528be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
529be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->left_margin, var->upper_margin);
53032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
531be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("Display filter: %s\n",
532be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
533be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
53432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
53532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
53632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
53732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
53832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
53932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
540be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
541be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
542be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n");
54332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
54432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	strcpy(fix->id, "cx23415 TV out");
545be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->smem_start = oi->video_pbase;
546be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->smem_len = oi->video_buffer_size;
54732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->type = FB_TYPE_PACKED_PIXELS;
548be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
54932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->xpanstep = 1;
55032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->ypanstep = 1;
55132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->ywrapstep = 0;
552be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->line_length = oi->display_byte_stride;
55332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->accel = FB_ACCEL_NONE;
55432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
55532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
55632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
55732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Check the requested display mode, returning -EINVAL if we can't
55832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   handle it. */
55932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
56032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
56132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
562be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
56368a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	int osd_height_limit;
56468a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	u32 pixclock, hlimit, vlimit;
56532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
566be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
56732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
56868a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	/* Set base references for mode calcs. */
56968a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	if (itv->is_50hz) {
57068a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		pixclock = 84316;
57168a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		hlimit = 776;
57268a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		vlimit = 591;
57368a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		osd_height_limit = 576;
57468a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	}
57568a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	else {
57668a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		pixclock = 83926;
57768a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		hlimit = 776;
57868a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		vlimit = 495;
57968a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		osd_height_limit = 480;
58068a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	}
58168a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong
58232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check the bits per pixel */
58332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_compat) {
58432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->bits_per_pixel != 32) {
585be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
58632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
58732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
58832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
58932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
59032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
59132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->transp.offset = 24;
59232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->transp.length = 8;
59332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->red.offset = 16;
59432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->red.length = 8;
59532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->green.offset = 8;
59632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->green.length = 8;
59732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->blue.offset = 0;
59832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->blue.length = 8;
59932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
60032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else if (var->bits_per_pixel == 16) {
60132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* To find out the true mode, check green length */
60232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		switch (var->green.length) {
60332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 4:
60432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.offset = 8;
60532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.length = 4;
60632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.offset = 4;
60732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.length = 4;
60832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.offset = 0;
60932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.length = 4;
610459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.offset = 12;
611459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.length = 1;
61232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
61332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 5:
61432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.offset = 10;
61532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.length = 5;
61632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.offset = 5;
61732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.length = 5;
61832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.offset = 0;
61932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.length = 5;
620459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.offset = 15;
621459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.length = 1;
62232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
62332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			default:
62432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.offset = 11;
62532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.length = 5;
62632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.offset = 5;
62732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.length = 6;
62832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.offset = 0;
62932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.length = 5;
630459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.offset = 0;
631459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.length = 0;
63232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
63332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
63432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
63532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else {
636be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
63732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
63832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
63932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
64032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check the resolution */
64132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_compat) {
642be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		if (var->xres != oi->ivtvfb_defined.xres ||
643be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		    var->yres != oi->ivtvfb_defined.yres ||
644be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		    var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
645be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		    var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
646be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
647be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				var->xres, var->yres, var->xres_virtual, var->yres_virtual);
64832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
64932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
65032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
65132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else {
652be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
653be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n",
654be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					var->xres, var->yres);
65532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
65632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
65732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
65832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
65932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
660be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		    var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
66132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		    var->xres_virtual < var->xres ||
66232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		    var->yres_virtual < var->yres) {
663be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
66432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->xres_virtual, var->yres_virtual);
66532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
66632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
66732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
66832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
66932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Some extra checks if in 8 bit mode */
67032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->bits_per_pixel == 8) {
67132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Width must be a multiple of 4 */
67232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres & 3) {
673be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
67432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
67532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
67632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres_virtual & 3) {
677be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
67832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
67932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
68032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
68132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else if (var->bits_per_pixel == 16) {
68232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Width must be a multiple of 2 */
68332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres & 1) {
684be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
68532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
68632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
68732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres_virtual & 1) {
688be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
68932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
69032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
69132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
69232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
69332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Now check the offsets */
69432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
695be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
696be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
69732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
69832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
69932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
70032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check pixel format */
70132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->nonstd > 1) {
702be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
70332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
70432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
70532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
70632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check video mode */
70732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
70832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
709be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
71032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
71132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
71232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
71332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check the left & upper margins
71432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   If the margins are too large, just center the screen
71532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   (enforcing margins causes too many problems) */
71632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
71732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
71832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
71932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
72032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
72132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
72232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
72332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
72432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Maintain overall 'size' for a constant refresh rate */
72568a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	var->right_margin = hlimit - var->left_margin - var->xres;
72668a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	var->lower_margin = vlimit - var->upper_margin - var->yres;
72732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
72832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Fixed sync times */
72932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	var->hsync_len = 24;
73032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	var->vsync_len = 2;
73132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
73232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Non-interlaced / interlaced mode is used to switch the OSD filter
73332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   on or off. Adjust the clock timings to maintain a constant
73432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   vertical refresh rate. */
73532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
73668a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		var->pixclock = pixclock / 2;
73768a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	else
73868a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		var->pixclock = pixclock;
73932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
740be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
741be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres, var->yres,
742be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres_virtual, var->yres_virtual,
74332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		      var->bits_per_pixel);
74432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
745be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
746be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->left_margin, var->upper_margin);
74732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
748be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("Display filter: %s\n",
749be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
750be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
75132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
75232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
75332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
75432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
75532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
75632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *) info->par;
757be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
758be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	return _ivtvfb_check_var(var, itv);
75932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
76032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
76132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
76232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
76332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 osd_pan_index;
76432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *) info->par;
76532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
76632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
767be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	write_reg(osd_pan_index, 0x02A0C);
76832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
76932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Pass this info back the yuv handler */
77032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_x_pan = var->xoffset;
77132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_y_pan = var->yoffset;
77232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Force update of yuv registers */
77332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.yuv_forced_update = 1;
77432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
77532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
77632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
77732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_set_par(struct fb_info *info)
77832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
77932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int rc = 0;
78032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *) info->par;
78132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
782be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n");
78332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
78432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	rc = ivtvfb_set_var(itv, &info->var);
78532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtvfb_pan_display(&info->var, info);
786be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	ivtvfb_get_fix(itv, &info->fix);
78732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return rc;
78832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
78932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
79032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
79132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				unsigned blue, unsigned transp,
79232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				struct fb_info *info)
79332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
79432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 color, *palette;
795be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct ivtv *itv = (struct ivtv *)info->par;
79632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
79732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (regno >= info->cmap.len)
79832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
79932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
80032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
80132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (info->var.bits_per_pixel <= 8) {
80232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		write_reg(regno, 0x02a30);
80332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		write_reg(color, 0x02a34);
804be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		return 0;
80532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
806be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (regno >= 16)
807be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		return -EINVAL;
80832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
809be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	palette = info->pseudo_palette;
810be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (info->var.bits_per_pixel == 16) {
811be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		switch (info->var.green.length) {
812be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			case 4:
813be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				color = ((red & 0xf000) >> 4) |
814be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((green & 0xf000) >> 8) |
815be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((blue & 0xf000) >> 12);
816be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				break;
817be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			case 5:
818be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				color = ((red & 0xf800) >> 1) |
819be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((green & 0xf800) >> 6) |
820be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((blue & 0xf800) >> 11);
821be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				break;
822be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			case 6:
823be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				color = (red & 0xf800 ) |
824be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((green & 0xfc00) >> 5) |
825be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((blue & 0xf800) >> 11);
826be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				break;
82732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
82832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
829be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	palette[regno] = color;
83032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
83132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
83232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
83332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* We don't really support blanking. All this does is enable or
83432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   disable the OSD. */
83532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_blank(int blank_mode, struct fb_info *info)
83632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
83732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *)info->par;
83832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
839be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
84032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (blank_mode) {
84132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_UNBLANK:
84232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
84332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		break;
84432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_NORMAL:
84532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_HSYNC_SUSPEND:
84632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_VSYNC_SUSPEND:
84732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_POWERDOWN:
84832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
84932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		break;
85032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
85132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
85232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
85332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
85432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic struct fb_ops ivtvfb_ops = {
85532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.owner = THIS_MODULE,
85632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_check_var   = ivtvfb_check_var,
85732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_set_par     = ivtvfb_set_par,
85832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_setcolreg   = ivtvfb_setcolreg,
85932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_fillrect    = cfb_fillrect,
86032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_copyarea    = cfb_copyarea,
86132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_imageblit   = cfb_imageblit,
86232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_cursor      = NULL,
86332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_ioctl       = ivtvfb_ioctl,
86432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_pan_display = ivtvfb_pan_display,
86532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_blank       = ivtvfb_blank,
86632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil};
86732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
86832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Initialization */
86932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
87032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
87132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Setup our initial video mode */
87232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_init_vidmode(struct ivtv *itv)
87332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
874be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
87532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct v4l2_rect start_window;
876be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	int max_height;
87732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
87832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Color mode */
87932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
88032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_compat) osd_depth = 32;
88132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
882be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->bits_per_pixel = osd_depth;
883be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->bytes_per_pixel = oi->bits_per_pixel / 8;
88432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
885aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	/* Invalidate current osd mode to force a mode switch later */
886aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	oi->osd_mode = -1;
887aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong
88832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Horizontal size & position */
88932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
89032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_xres > 720) osd_xres = 720;
89132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
89232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
89332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_depth == 8)
89432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_xres &= ~3;
89532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else if (osd_depth == 16)
89632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_xres &= ~1;
89732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
89832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_xres)
89932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		start_window.width = osd_xres;
90032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else
90132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		start_window.width = osd_compat ? 720: 640;
90232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
90332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check horizontal start (osd_left). */
90432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_left && osd_left + start_window.width > 721) {
905be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_ERR("Invalid osd_left - assuming default\n");
90632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_left = 0;
90732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
90832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
90932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Hardware coords start at 0, user coords start at 1. */
910be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd_left--;
91132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
912be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
91332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
914be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_byte_stride =
915be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			start_window.width * oi->bytes_per_pixel;
91632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
91732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Vertical size & position */
91832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
91932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	max_height = itv->is_50hz ? 576 : 480;
92032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
921be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (osd_yres > max_height)
922be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		osd_yres = max_height;
92332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
92432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_yres)
92532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		start_window.height = osd_yres;
926be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	else
927be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
92832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
92932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check vertical start (osd_upper). */
93032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_upper + start_window.height > max_height + 1) {
931be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_ERR("Invalid osd_upper - assuming default\n");
93232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_upper = 0;
93332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
93432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
93532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Hardware coords start at 0, user coords start at 1. */
936be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd_upper--;
93732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
93832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
93932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
940be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_width = start_window.width;
941be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_height = start_window.height;
94232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
94332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Generate a valid fb_var_screeninfo */
94432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
945be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.xres = oi->display_width;
946be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.yres = oi->display_height;
947be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.xres_virtual = oi->display_width;
948be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.yres_virtual = oi->display_height;
949be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
950be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
951be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.left_margin = start_window.left + 1;
952be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.upper_margin = start_window.top + 1;
953be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
954be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.nonstd = 0;
95532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
95632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* We've filled in the most data, let the usual mode check
95732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   routine fill in the rest. */
958be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	_ivtvfb_check_var(&oi->ivtvfb_defined, itv);
95932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
96032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Generate valid fb_fix_screeninfo */
96132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
962be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
96332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
96432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Generate valid fb_info */
96532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
966be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.node = -1;
967be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
968be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.fbops = &ivtvfb_ops;
969be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.par = itv;
970be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.var = oi->ivtvfb_defined;
971be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.fix = oi->ivtvfb_fix;
972be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
973be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.fbops = &ivtvfb_ops;
97432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
97532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Supply some monitor specs. Bogus values will do for now */
976be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.hfmin = 8000;
977be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.hfmax = 70000;
978be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.vfmin = 10;
979be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.vfmax = 100;
98032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
98132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Allocate color map */
982be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
983be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_ERR("abort, unable to alloc cmap\n");
98432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENOMEM;
98532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
98632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
98732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Allocate the pseudo palette */
988be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
98932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
990be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!oi->ivtvfb_info.pseudo_palette) {
991be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n");
99232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENOMEM;
99332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
99432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
99532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
99632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
99732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
99832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
99932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
100032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_init_io(struct ivtv *itv)
100132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
1002be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
1003be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
100426e9d599561e9a964bd4d7c2be0029db8aaff852Hans Verkuil	mutex_lock(&itv->serialize_lock);
10056e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil	if (ivtv_init_on_first_open(itv)) {
100626e9d599561e9a964bd4d7c2be0029db8aaff852Hans Verkuil		mutex_unlock(&itv->serialize_lock);
10076e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil		IVTV_FB_ERR("Failed to initialize ivtv\n");
10086e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil		return -ENXIO;
10096e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil	}
101026e9d599561e9a964bd4d7c2be0029db8aaff852Hans Verkuil	mutex_unlock(&itv->serialize_lock);
10116e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil
1012be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
101332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
101432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* The osd buffer size depends on the number of video buffers allocated
101532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   on the PVR350 itself. For now we'll hardcode the smallest osd buffer
101632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   size to prevent any overlap. */
1017be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->video_buffer_size = 1704960;
101832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1019be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1020be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->video_vbase = itv->dec_mem + oi->video_rbase;
102132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1022be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!oi->video_vbase) {
102332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1024be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		     oi->video_buffer_size, oi->video_pbase);
102532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EIO;
102632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
102732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
102832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1029be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->video_pbase, oi->video_vbase,
1030be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->video_buffer_size / 1024);
103132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
103232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
103332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	{
103432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Find the largest power of two that maps the whole buffer */
103532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		int size_shift = 31;
103632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1037be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		while (!(oi->video_buffer_size & (1 << size_shift))) {
103832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			size_shift--;
103932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
104032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		size_shift++;
1041be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1042be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1043be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1044be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1045be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		if (mtrr_add(oi->fb_start_aligned_physaddr,
1046be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
104732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			     MTRR_TYPE_WRCOMB, 1) < 0) {
1048be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			IVTV_FB_WARN("cannot use mttr\n");
1049be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_start_aligned_physaddr = 0;
1050be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_end_aligned_physaddr = 0;
105132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
105232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
1053be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil#endif
105432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
105532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Blank the entire osd. */
1056be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	memset_io(oi->video_vbase, 0, oi->video_buffer_size);
105732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
105832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
105932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
106032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
106132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Release any memory we've grabbed & remove mtrr entry */
106232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic void ivtvfb_release_buffers (struct ivtv *itv)
106332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
1064be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
1065be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
106632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Release cmap */
1067be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (oi->ivtvfb_info.cmap.len);
1068be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
106932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
107032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Release pseudo palette */
1071be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (oi->ivtvfb_info.pseudo_palette)
1072be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		kfree(oi->ivtvfb_info.pseudo_palette);
107332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
107432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
1075be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (oi->fb_end_aligned_physaddr) {
1076be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		mtrr_del(-1, oi->fb_start_aligned_physaddr,
1077be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1078be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	}
1079be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil#endif
108032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1081be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	kfree(oi);
108232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->osd_info = NULL;
108332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
108432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
108532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Initialize the specified card */
108632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1087be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuilstatic int ivtvfb_init_card(struct ivtv *itv)
108832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
108932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int rc;
109032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
109132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (itv->osd_info) {
109232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id);
109332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EBUSY;
109432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
109532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
109632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
109732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (itv->osd_info == 0) {
109832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		IVTV_FB_ERR("Failed to allocate memory for osd_info\n");
109932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENOMEM;
110032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
110132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
110232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Find & setup the OSD buffer */
1103be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if ((rc = ivtvfb_init_io(itv)))
110432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return rc;
110532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
110632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the startup video mode information */
1107be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if ((rc = ivtvfb_init_vidmode(itv))) {
110832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtvfb_release_buffers(itv);
110932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return rc;
111032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
111132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
111232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Register the framebuffer */
111332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
111432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtvfb_release_buffers(itv);
111532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
111632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
111732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
111832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->osd_video_pbase = itv->osd_info->video_pbase;
111932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
112032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the card to the requested mode */
112132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
112232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
112332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set color 0 to black */
112432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg(0, 0x02a30);
112532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg(0, 0x02a34);
112632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
112732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Enable the osd */
112832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
112932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
113032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Note if we're running in compatibility mode */
113132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_compat)
113232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
113332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
113432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Allocate DMA */
113532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_udma_alloc(itv);
113632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
113732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
113832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
113932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
114032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int __init ivtvfb_init(void)
114132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
114232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv;
114332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int i, registered = 0;
114432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
114532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) {
11467b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil		printk(KERN_ERR "ivtvfb:  ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n",
114732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		     IVTV_MAX_CARDS - 1);
114832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
114932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
115032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
115132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Locate & initialise all cards supporting an OSD. */
115232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	for (i = 0; i < ivtv_cards_active; i++) {
115332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id)
115432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			continue;
115532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		itv = ivtv_cards[i];
115632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
115732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (ivtvfb_init_card(itv) == 0) {
115832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i);
115932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				registered++;
116032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			}
116132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
116232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
116332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (!registered) {
11647b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil		printk(KERN_ERR "ivtvfb:  no cards found");
116532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENODEV;
116632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
116732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
116832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
116932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
117032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic void ivtvfb_cleanup(void)
117132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
117232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv;
117332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int i;
117432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11757b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil	printk(KERN_INFO "ivtvfb:  Unloading framebuffer module\n");
117632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
117732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	for (i = 0; i < ivtv_cards_active; i++) {
117832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		itv = ivtv_cards[i];
117932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
118032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i);
118132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
118232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			unregister_framebuffer(&itv->osd_info->ivtvfb_info);
118332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtvfb_release_buffers(itv);
118432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			itv->osd_video_pbase = 0;
118532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
118632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
118732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
118832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
118932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_init(ivtvfb_init);
119032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_exit(ivtvfb_cleanup);
1191