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>
455a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
4632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
4732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
4832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include <asm/mtrr.h>
4932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#endif
5032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
5132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include "ivtv-driver.h"
5267ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil#include "ivtv-cards.h"
534e7ca40dbff522691b13dd9b5ed41891e6c68e1aIan Armstrong#include "ivtv-i2c.h"
5432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include "ivtv-udma.h"
5532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#include "ivtv-mailbox.h"
56215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong#include "ivtv-firmware.h"
5732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
5832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* card parameters */
59641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_card_id = -1;
60641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_debug = 0;
6190ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool osd_laced;
6232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_depth;
6332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_upper;
6432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_left;
6532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_yres;
6632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int osd_xres;
6732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
68641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilmodule_param(ivtvfb_card_id, int, 0444);
69641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilmodule_param_named(debug,ivtvfb_debug, int, 0644);
7032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_laced, bool, 0444);
7132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_depth, int, 0444);
7232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_upper, int, 0444);
7332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_left, int, 0444);
7432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_yres, int, 0444);
7532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_param(osd_xres, int, 0444);
7632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
77641ed49db6ecf6c539a5eab50a7540542377add1Hans VerkuilMODULE_PARM_DESC(ivtvfb_card_id,
7832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Only use framebuffer of the specified ivtv card (0-31)\n"
7932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault -1: initialize all available framebuffers");
8032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8132db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(debug,
8232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Debug level (bitmask). Default: errors only\n"
8332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t(debug = 3 gives full debugging)");
8432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Why upper, left, xres, yres, depth, laced ? To match terminology used
8632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   by fbset.
8732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
8832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8932db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_laced,
9032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Interlaced mode\n"
9132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t0=off\n"
9232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t1=on\n"
9332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault off");
9432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
9532db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_depth,
96be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		 "Bits per pixel - 8, 16, 32\n"
9732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 8");
9832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
9932db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_upper,
10032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Vertical start position\n"
10132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 0 (Centered)");
10232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
10332db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_left,
10432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Horizontal start position\n"
10532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 0 (Centered)");
10632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
10732db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_yres,
10832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Display height\n"
10932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 480 (PAL)\n"
11032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\t        400 (NTSC)");
11132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11232db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_PARM_DESC(osd_xres,
11332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "Display width\n"
11432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		 "\t\t\tdefault 640");
11532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11632db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
11732db775452818656d5fd8fd8b0f54425f5cfc177Hans VerkuilMODULE_LICENSE("GPL");
11832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* --------------------------------------------------------------------- */
12032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
121641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DBGFLG_WARN  (1 << 0)
122641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DBGFLG_INFO  (1 << 1)
12332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
124641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DEBUG(x, type, fmt, args...) \
12532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	do { \
126641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		if ((x) & ivtvfb_debug) \
12767ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil			printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \
12832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	} while (0)
129641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DEBUG_WARN(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
130641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil#define IVTVFB_DEBUG_INFO(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
13132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
13232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Standard kernel messages */
13367ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil#define IVTVFB_ERR(fmt, args...)   printk(KERN_ERR  "ivtvfb%d: " fmt, itv->instance , ## args)
13467ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil#define IVTVFB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtvfb%d: " fmt, itv->instance , ## args)
13567ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil#define IVTVFB_INFO(fmt, args...)  printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args)
13632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
13732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* --------------------------------------------------------------------- */
13832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
13932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_MAX_WIDTH  720
14032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_MAX_HEIGHT 576
14132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
14232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_8      0x00
14332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_16_444 0x03
14432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_16_555 0x02
14532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_16_565 0x01
14632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#define IVTV_OSD_BPP_32     0x04
14732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
14832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstruct osd_info {
14932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Physical base address */
15032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long video_pbase;
15132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Relative base address (relative to start of decoder memory) */
15232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 video_rbase;
15332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Mapped base address */
15432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	volatile char __iomem *video_vbase;
15532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Buffer size */
15632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 video_buffer_size;
15732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
15832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
15932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* video_base rounded down as required by hardware MTRRs */
16032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long fb_start_aligned_physaddr;
16132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* video_base rounded up as required by hardware MTRRs */
16232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long fb_end_aligned_physaddr;
16332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#endif
16432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
16532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Store the buffer offset */
16632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int set_osd_coords_x;
16732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int set_osd_coords_y;
16832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
16932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Current dimensions (NOT VISIBLE SIZE!) */
17032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int display_width;
17132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int display_height;
17232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int display_byte_stride;
17332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
17432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Current bits per pixel */
17532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int bits_per_pixel;
17632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int bytes_per_pixel;
17732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
17832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Frame buffer stuff */
17932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct fb_info ivtvfb_info;
18032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct fb_var_screeninfo ivtvfb_defined;
18132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct fb_fix_screeninfo ivtvfb_fix;
182215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong
183215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	/* Used for a warm start */
184215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	struct fb_var_screeninfo fbvar_cur;
185215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	int blank_cur;
186215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	u32 palette_cur[256];
187215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	u32 pan_cur;
18832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil};
18932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
19032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstruct ivtv_osd_coords {
19132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long offset;
19232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	unsigned long max_offset;
19332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int pixel_stride;
19432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int lines;
19532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int x;
19632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int y;
19732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil};
19832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
19932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* --------------------------------------------------------------------- */
20032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
20132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* ivtv API calls for framebuffer related support */
20232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
203641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
20432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				       u32 *fblength)
20532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
20632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 data[CX2341X_MBOX_MAX_DATA];
20732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int rc;
20832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
209215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	ivtv_firmware_check(itv, "ivtvfb_get_framebuffer");
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
216641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_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
233641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_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
248641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
24932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
250c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong	int osd_height_limit = itv->is_out_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) {
258641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_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) {
264641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_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
284641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_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 got_sig = 0;
29032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
29132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	mutex_lock(&itv->udma.lock);
29232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Map User DMA */
29332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
29432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		mutex_unlock(&itv->udma.lock);
295641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, "
29632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			       "Error with get_user_pages: %d bytes, %d pages returned\n",
29732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			       size_in_bytes, itv->udma.page_count);
29832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
29932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* get_user_pages must have failed completely */
30032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EIO;
30132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
30232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
303641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
30432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		       size_in_bytes, itv->udma.page_count);
30532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
30632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_udma_prepare(itv);
30732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
30832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* if no UDMA is pending and no UDMA is in progress, then the DMA
30932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   is finished */
310ec105a42ac397366e05888ea96503ab3b57f79adHans Verkuil	while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
311ec105a42ac397366e05888ea96503ab3b57f79adHans Verkuil	       test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
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
330c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong	return 0;
33132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
33232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
333641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuilstatic int ivtvfb_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) {
341641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("ivtvfb_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) {
347641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_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)
354641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
355be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			(unsigned long)source);
35632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
35732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (dest_offset & 3)
358641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
35932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
36032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (count & 3)
361641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("ivtvfb_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)) {
365641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
36632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			(unsigned long)source);
36732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
368641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_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 */
378641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
37932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
38032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
3814cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrongstatic ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
3824ee0e42b31b282d0d0bb11effbbeb0610ee76d09Ian Armstrong						size_t count, loff_t *ppos)
3834cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong{
3844cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	unsigned long p = *ppos;
3854cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	void *dst;
3864cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	int err = 0;
387c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong	int dma_err;
3884cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	unsigned long total_size;
3894cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	struct ivtv *itv = (struct ivtv *) info->par;
3904cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	unsigned long dma_offset =
3914cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong			IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
3924cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	unsigned long dma_size;
3934cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	u16 lead = 0, tail = 0;
3944cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
3954cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	if (info->state != FBINFO_STATE_RUNNING)
3964cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		return -EPERM;
3974cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
3984cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	total_size = info->screen_size;
3994cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
4004cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	if (total_size == 0)
4014cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		total_size = info->fix.smem_len;
4024cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
4034cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	if (p > total_size)
4044cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		return -EFBIG;
4054cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
4064cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	if (count > total_size) {
4074cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		err = -EFBIG;
4084cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		count = total_size;
4094cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	}
4104cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
4114cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	if (count + p > total_size) {
4124cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		if (!err)
4134cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong			err = -ENOSPC;
4144cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		count = total_size - p;
4154cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	}
4164cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
4174cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	dst = (void __force *) (info->screen_base + p);
4184cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
4194cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	if (info->fbops->fb_sync)
4204cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		info->fbops->fb_sync(info);
4214cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
422c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong	/* If transfer size > threshold and both src/dst
423c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong	addresses are aligned, use DMA */
424c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong	if (count >= 4096 &&
425c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong	    ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
426c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		/* Odd address = can't DMA. Align */
427c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		if ((unsigned long)dst & 3) {
428c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong			lead = 4 - ((unsigned long)dst & 3);
429c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong			if (copy_from_user(dst, buf, lead))
430c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong				return -EFAULT;
431c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong			buf += lead;
432c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong			dst += lead;
4334cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		}
434c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		/* DMA resolution is 32 bits */
435c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		if ((count - lead) & 3)
436c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong			tail = (count - lead) & 3;
437c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		/* DMA the data */
438c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		dma_size = count - lead - tail;
439c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		dma_err = ivtvfb_prep_dec_dma_to_device(itv,
440c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		       p + lead + dma_offset, (void __user *)buf, dma_size);
441c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		if (dma_err)
442c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong			return dma_err;
443c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		dst += dma_size;
444c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		buf += dma_size;
445c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		/* Copy any leftover data */
446c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		if (tail && copy_from_user(dst, buf, tail))
447c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong			return -EFAULT;
448c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong	} else if (copy_from_user(dst, buf, count)) {
449c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong		return -EFAULT;
4504cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	}
4514cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
4524cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	if  (!err)
4534cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong		*ppos += count;
4544cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
4554cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	return (err) ? err : count;
4564cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong}
4574cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong
45832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
45932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
46032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	DEFINE_WAIT(wait);
46132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *)info->par;
462be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	int rc = 0;
46332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
46432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (cmd) {
46532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case FBIOGET_VBLANK: {
46632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			struct fb_vblank vblank;
46732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			u32 trace;
46832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
469405707985594169cfd0b1d97d29fcb4b4c6f2ac9Dan Rosenberg			memset(&vblank, 0, sizeof(struct fb_vblank));
470405707985594169cfd0b1d97d29fcb4b4c6f2ac9Dan Rosenberg
47132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
47232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil					FB_VBLANK_HAVE_VSYNC;
4734e1af31aaaa8cc4a5cc1d894bdf04dfc7450d47fAndy Walls			trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16;
474c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong			if (itv->is_out_50hz && trace > 312)
475c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong				trace -= 312;
476c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong			else if (itv->is_out_60hz && trace > 262)
477c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong				trace -= 262;
478c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong			if (trace == 1)
479c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong				vblank.flags |= FB_VBLANK_VSYNCING;
480a158f3559334c6314c7876390caffe88c9fdb64dHans Verkuil			vblank.count = itv->last_vsync_field;
48132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			vblank.vcount = trace;
48232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			vblank.hcount = 0;
48332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
48432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				return -EFAULT;
48532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return 0;
48632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
48732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
488be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		case FBIO_WAITFORVSYNC:
48932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
490c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong			if (!schedule_timeout(msecs_to_jiffies(50)))
491c777549fc9c5c704707394b0235a9a6794247b83Ian Armstrong				rc = -ETIMEDOUT;
492be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			finish_wait(&itv->vsync_waitq, &wait);
49332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return rc;
49432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
495d715e766ddf4786a06abe6a841e956ad8a875963Hans Verkuil		case IVTVFB_IOC_DMA_FRAME: {
496d715e766ddf4786a06abe6a841e956ad8a875963Hans Verkuil			struct ivtvfb_dma_frame args;
49732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
498641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
49932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
50032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				return -EFAULT;
50132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
502641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
50332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
50432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
50532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		default:
506641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
50732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
50832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
50932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
51032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
51132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
51232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Framebuffer device handling */
51332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
51432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
51532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
516aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	struct osd_info *oi = itv->osd_info;
51732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv_osd_coords ivtv_osd;
51832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct v4l2_rect ivtv_window;
519aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	int osd_mode = -1;
52032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
521641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
52232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
52332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Select color space */
52432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->nonstd) /* YUV */
525be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
52632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else /* RGB  */
527be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
52832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
529aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	/* Set the color mode */
53032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (var->bits_per_pixel) {
53132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case 8:
532aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong			osd_mode = IVTV_OSD_BPP_8;
53332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
53432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case 32:
535aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong			osd_mode = IVTV_OSD_BPP_32;
53632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
53732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case 16:
53832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			switch (var->green.length) {
53932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 4:
540aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong				osd_mode = IVTV_OSD_BPP_16_444;
54132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
54232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 5:
543aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong				osd_mode = IVTV_OSD_BPP_16_555;
54432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
54532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 6:
546aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong				osd_mode = IVTV_OSD_BPP_16_565;
54732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
54832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			default:
549641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil				IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
55032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			}
55132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
55232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		default:
553641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
55432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
55532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
5566659e3ed559db2e730947268f9d57869b7a9016cIan Armstrong	/* Set video mode. Although rare, the display can become scrambled even
5576659e3ed559db2e730947268f9d57869b7a9016cIan Armstrong	   if we don't change mode. Always 'bounce' to osd_mode via mode 0 */
5586659e3ed559db2e730947268f9d57869b7a9016cIan Armstrong	if (osd_mode != -1) {
559aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
560aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
561aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	}
562aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong
563aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	oi->bits_per_pixel = var->bits_per_pixel;
564aaf9fa21b684509973dd593e30423fc0a6a5e7a3Ian Armstrong	oi->bytes_per_pixel = var->bits_per_pixel / 8;
56532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
56632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the flicker filter */
56732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (var->vmode & FB_VMODE_MASK) {
56832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case FB_VMODE_NONINTERLACED: /* Filter on */
56932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
57032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
57132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		case FB_VMODE_INTERLACED: /* Filter off */
57232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
57332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			break;
57432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		default:
575641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
57632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
57732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
57832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Read the current osd info */
579641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	ivtvfb_get_osd_coords(itv, &ivtv_osd);
58032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
58132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Now set the OSD to the size we want */
58232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.pixel_stride = var->xres_virtual;
58332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.lines = var->yres_virtual;
58432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.x = 0;
58532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_osd.y = 0;
586641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	ivtvfb_set_osd_coords(itv, &ivtv_osd);
58732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
58832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Can't seem to find the right API combo for this.
58932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   Use another function which does what we need through direct register access. */
59032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.width = var->xres;
59132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.height = var->yres;
59232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
59332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Minimum margin cannot be 0, as X won't allow such a mode */
594215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	if (!var->upper_margin)
595215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong		var->upper_margin++;
596215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	if (!var->left_margin)
597215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong		var->left_margin++;
59832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.top = var->upper_margin - 1;
59932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_window.left = var->left_margin - 1;
60032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
601641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	ivtvfb_set_display_window(itv, &ivtv_window);
60232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
60377aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	/* Pass screen size back to yuv handler */
60477aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
60577aded6ba51f01335840ce8e18b413067810b68eIan Armstrong	itv->yuv_info.osd_full_h = ivtv_osd.lines;
60677aded6ba51f01335840ce8e18b413067810b68eIan Armstrong
60732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Force update of yuv registers */
60832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.yuv_forced_update = 1;
60932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
610215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	/* Keep a copy of these settings */
611215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
612215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong
613641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
614be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres, var->yres,
615be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres_virtual, var->yres_virtual,
616be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->bits_per_pixel);
61732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
618641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
619be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->left_margin, var->upper_margin);
62032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
621641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display filter: %s\n",
622be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
623641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
62432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
62532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
62632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
62732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
62832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
62932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
630be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
631be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
632641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
63332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
634cebfadff4a5c877c524ae6014613edab9f50a2a9Hans Verkuil	strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));
635be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->smem_start = oi->video_pbase;
636be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->smem_len = oi->video_buffer_size;
63732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->type = FB_TYPE_PACKED_PIXELS;
638be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
63932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->xpanstep = 1;
64032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->ypanstep = 1;
64132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->ywrapstep = 0;
642be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	fix->line_length = oi->display_byte_stride;
64332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	fix->accel = FB_ACCEL_NONE;
64432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
64532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
64632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
64732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Check the requested display mode, returning -EINVAL if we can't
64832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   handle it. */
64932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
65032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
65132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
652be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
65368a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	int osd_height_limit;
65468a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	u32 pixclock, hlimit, vlimit;
65532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
656641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
65732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
65868a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	/* Set base references for mode calcs. */
659c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong	if (itv->is_out_50hz) {
66068a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		pixclock = 84316;
66168a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		hlimit = 776;
66268a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		vlimit = 591;
66368a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		osd_height_limit = 576;
66468a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	}
66568a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	else {
66668a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		pixclock = 83926;
66768a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		hlimit = 776;
66868a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		vlimit = 495;
66968a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		osd_height_limit = 480;
67068a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	}
67168a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong
67232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
67332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->transp.offset = 24;
67432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->transp.length = 8;
67532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->red.offset = 16;
67632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->red.length = 8;
67732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->green.offset = 8;
67832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->green.length = 8;
67932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->blue.offset = 0;
68032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->blue.length = 8;
68132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
68232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else if (var->bits_per_pixel == 16) {
68332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* To find out the true mode, check green length */
68432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		switch (var->green.length) {
68532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 4:
68632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.offset = 8;
68732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.length = 4;
68832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.offset = 4;
68932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.length = 4;
69032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.offset = 0;
69132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.length = 4;
692459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.offset = 12;
693459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.length = 1;
69432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
69532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			case 5:
69632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.offset = 10;
69732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.length = 5;
69832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.offset = 5;
69932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.length = 5;
70032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.offset = 0;
70132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.length = 5;
702459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.offset = 15;
703459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.length = 1;
70432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
70532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			default:
70632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.offset = 11;
70732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->red.length = 5;
70832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.offset = 5;
70932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->green.length = 6;
71032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.offset = 0;
71132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				var->blue.length = 5;
712459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.offset = 0;
713459a52fab2c42cd5fadfd51fdcfc6dea8107fabfHans Verkuil				var->transp.length = 0;
71432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				break;
71532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
71632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
71732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else {
718641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
71932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
72032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
72132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
72232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check the resolution */
7236b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
7246b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
7256b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong				var->xres, var->yres);
7266b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		return -EINVAL;
72732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
72832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
7296b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	/* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
7306b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
7316b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	    var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
7326b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	    var->xres_virtual < var->xres ||
7336b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	    var->yres_virtual < var->yres) {
7346b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
7356b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong			var->xres_virtual, var->yres_virtual);
7366b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		return -EINVAL;
73732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
73832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
73932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Some extra checks if in 8 bit mode */
74032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->bits_per_pixel == 8) {
74132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Width must be a multiple of 4 */
74232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres & 3) {
743641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
74432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
74532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
74632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres_virtual & 3) {
747641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
74832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
74932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
75032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
75132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else if (var->bits_per_pixel == 16) {
75232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Width must be a multiple of 2 */
75332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres & 1) {
754641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
75532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
75632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
75732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		if (var->xres_virtual & 1) {
758641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
75932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			return -EINVAL;
76032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
76132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
76232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
76332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Now check the offsets */
76432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
765641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
766be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
76732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
76832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
76932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
77032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check pixel format */
77132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (var->nonstd > 1) {
772641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
77332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
77432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
77532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
77632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check video mode */
77732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
77832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
779641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
78032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
78132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
78232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
78332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check the left & upper margins
78432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   If the margins are too large, just center the screen
78532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   (enforcing margins causes too many problems) */
78632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
787c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong	if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1)
78832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
789c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong
790c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong	if (var->upper_margin + var->yres > (itv->is_out_50hz ? 577 : 481))
791c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong		var->upper_margin = 1 + (((itv->is_out_50hz ? 576 : 480) -
792c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong			var->yres) / 2);
79332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
79432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Maintain overall 'size' for a constant refresh rate */
79568a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	var->right_margin = hlimit - var->left_margin - var->xres;
79668a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	var->lower_margin = vlimit - var->upper_margin - var->yres;
79732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
79832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Fixed sync times */
79932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	var->hsync_len = 24;
80032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	var->vsync_len = 2;
80132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
80232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Non-interlaced / interlaced mode is used to switch the OSD filter
80332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   on or off. Adjust the clock timings to maintain a constant
80432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   vertical refresh rate. */
80532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
80668a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		var->pixclock = pixclock / 2;
80768a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong	else
80868a341a53ab5a3c5b7dad4b226124414c62c124dIan Armstrong		var->pixclock = pixclock;
80932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
81037f89f9542c3945bddf46efc15a1b1e349af3f88Hans Verkuil	itv->osd_rect.width = var->xres;
81137f89f9542c3945bddf46efc15a1b1e349af3f88Hans Verkuil	itv->osd_rect.height = var->yres;
81237f89f9542c3945bddf46efc15a1b1e349af3f88Hans Verkuil
813641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
814be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres, var->yres,
815be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->xres_virtual, var->yres_virtual,
81632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		      var->bits_per_pixel);
81732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
818641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
819be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		      var->left_margin, var->upper_margin);
82032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
821641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Display filter: %s\n",
822be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
823641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
82432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
82532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
82632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
82732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
82832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
82932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *) info->par;
830641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
831be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	return _ivtvfb_check_var(var, itv);
83232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
83332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
83432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
83532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
83632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 osd_pan_index;
83732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *) info->par;
83832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
8396600cc301d0762e3db8bd2b44d2d5fef36a4fd68Ian Armstrong	if (var->yoffset + info->var.yres > info->var.yres_virtual ||
8406600cc301d0762e3db8bd2b44d2d5fef36a4fd68Ian Armstrong	    var->xoffset + info->var.xres > info->var.xres_virtual)
8416600cc301d0762e3db8bd2b44d2d5fef36a4fd68Ian Armstrong		return -EINVAL;
8426600cc301d0762e3db8bd2b44d2d5fef36a4fd68Ian Armstrong
8435d9c08dea0c13c09408f97fe61d34c198c4f3277Laurent Pinchart	osd_pan_index = var->yoffset * info->fix.line_length
8445d9c08dea0c13c09408f97fe61d34c198c4f3277Laurent Pinchart		      + var->xoffset * info->var.bits_per_pixel / 8;
845be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	write_reg(osd_pan_index, 0x02A0C);
84632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
84732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Pass this info back the yuv handler */
84832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_x_pan = var->xoffset;
84932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.osd_y_pan = var->yoffset;
85032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Force update of yuv registers */
85132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->yuv_info.yuv_forced_update = 1;
852215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	/* Remember this value */
853215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	itv->osd_info->pan_cur = osd_pan_index;
85432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
85532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
85632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
85732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_set_par(struct fb_info *info)
85832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
85932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int rc = 0;
86032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *) info->par;
86132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
862641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
86332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
86432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	rc = ivtvfb_set_var(itv, &info->var);
86532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtvfb_pan_display(&info->var, info);
866be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	ivtvfb_get_fix(itv, &info->fix);
867215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	ivtv_firmware_check(itv, "ivtvfb_set_par");
86832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return rc;
86932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
87032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
87132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
87232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				unsigned blue, unsigned transp,
87332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil				struct fb_info *info)
87432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
87532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	u32 color, *palette;
876be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct ivtv *itv = (struct ivtv *)info->par;
87732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
87832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (regno >= info->cmap.len)
87932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
88032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
88132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
88232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (info->var.bits_per_pixel <= 8) {
88332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		write_reg(regno, 0x02a30);
88432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		write_reg(color, 0x02a34);
885215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong		itv->osd_info->palette_cur[regno] = color;
886be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		return 0;
88732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
888be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (regno >= 16)
889be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		return -EINVAL;
89032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
891be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	palette = info->pseudo_palette;
892be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (info->var.bits_per_pixel == 16) {
893be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		switch (info->var.green.length) {
894be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			case 4:
895be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				color = ((red & 0xf000) >> 4) |
896be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((green & 0xf000) >> 8) |
897be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((blue & 0xf000) >> 12);
898be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				break;
899be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			case 5:
900be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				color = ((red & 0xf800) >> 1) |
901be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((green & 0xf800) >> 6) |
902be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((blue & 0xf800) >> 11);
903be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				break;
904be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			case 6:
905be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				color = (red & 0xf800 ) |
906be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((green & 0xfc00) >> 5) |
907be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil					((blue & 0xf800) >> 11);
908be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil				break;
90932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
91032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
911be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	palette[regno] = color;
91232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
91332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
91432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
91532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* We don't really support blanking. All this does is enable or
91632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil   disable the OSD. */
91732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_blank(int blank_mode, struct fb_info *info)
91832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
91932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct ivtv *itv = (struct ivtv *)info->par;
92032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
921641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
92232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	switch (blank_mode) {
92332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_UNBLANK:
92432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
92567ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
92632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		break;
92732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_NORMAL:
92832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_HSYNC_SUSPEND:
92932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_VSYNC_SUSPEND:
9304e7ca40dbff522691b13dd9b5ed41891e6c68e1aIan Armstrong		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
93167ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
9324e7ca40dbff522691b13dd9b5ed41891e6c68e1aIan Armstrong		break;
93332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	case FB_BLANK_POWERDOWN:
93467ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
93532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
93632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		break;
93732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
938215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	itv->osd_info->blank_cur = blank_mode;
93932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
94032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
94132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
94232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic struct fb_ops ivtvfb_ops = {
94332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.owner = THIS_MODULE,
9444cbeb3711481a7e563fe4c61888986c4aa1cb22eIan Armstrong	.fb_write       = ivtvfb_write,
94532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_check_var   = ivtvfb_check_var,
94632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_set_par     = ivtvfb_set_par,
94732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_setcolreg   = ivtvfb_setcolreg,
94832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_fillrect    = cfb_fillrect,
94932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_copyarea    = cfb_copyarea,
95032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_imageblit   = cfb_imageblit,
95132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_cursor      = NULL,
95232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_ioctl       = ivtvfb_ioctl,
95332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_pan_display = ivtvfb_pan_display,
95432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	.fb_blank       = ivtvfb_blank,
95532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil};
95632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
957215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong/* Restore hardware after firmware restart */
958215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrongstatic void ivtvfb_restore(struct ivtv *itv)
959215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong{
960215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	struct osd_info *oi = itv->osd_info;
961215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	int i;
962215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong
963215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	ivtvfb_set_var(itv, &oi->fbvar_cur);
964215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info);
965215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	for (i = 0; i < 256; i++) {
966215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong		write_reg(i, 0x02a30);
967215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong		write_reg(oi->palette_cur[i], 0x02a34);
968215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	}
969215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	write_reg(oi->pan_cur, 0x02a0c);
970215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong}
971215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong
97232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Initialization */
97332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
97432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
97532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Setup our initial video mode */
97632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_init_vidmode(struct ivtv *itv)
97732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
978be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
97932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	struct v4l2_rect start_window;
980be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	int max_height;
98132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
98232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Color mode */
98332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
9846b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32)
9856b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		osd_depth = 8;
986be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->bits_per_pixel = osd_depth;
987be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->bytes_per_pixel = oi->bits_per_pixel / 8;
98832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
98932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Horizontal size & position */
99032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
9916b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	if (osd_xres > 720)
9926b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong		osd_xres = 720;
99332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
99432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
99532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_depth == 8)
99632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_xres &= ~3;
99732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	else if (osd_depth == 16)
99832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_xres &= ~1;
99932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
10006b1ec9da152c03106aa92fa045f5cf9b7912597cIan Armstrong	start_window.width = osd_xres ? osd_xres : 640;
100132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
100232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check horizontal start (osd_left). */
100332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_left && osd_left + start_window.width > 721) {
1004641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Invalid osd_left - assuming default\n");
100532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_left = 0;
100632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
100732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
100832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Hardware coords start at 0, user coords start at 1. */
1009be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd_left--;
101032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1011c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong	start_window.left = osd_left >= 0 ?
1012c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong		 osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
101332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1014be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_byte_stride =
1015be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			start_window.width * oi->bytes_per_pixel;
101632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
101732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Vertical size & position */
101832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1019c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong	max_height = itv->is_out_50hz ? 576 : 480;
102032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1021be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (osd_yres > max_height)
1022be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		osd_yres = max_height;
102332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1024c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong	start_window.height = osd_yres ?
1025c5874c9245d298c65f81c2f91f89e1da8ea66409Ian Armstrong		osd_yres : itv->is_out_50hz ? 480 : 400;
102632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
102732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Check vertical start (osd_upper). */
102832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (osd_upper + start_window.height > max_height + 1) {
1029641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Invalid osd_upper - assuming default\n");
103032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		osd_upper = 0;
103132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
103232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
103332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Hardware coords start at 0, user coords start at 1. */
1034be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	osd_upper--;
103532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
103632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
103732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1038be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_width = start_window.width;
1039be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->display_height = start_window.height;
104032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
104132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Generate a valid fb_var_screeninfo */
104232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1043be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.xres = oi->display_width;
1044be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.yres = oi->display_height;
1045be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.xres_virtual = oi->display_width;
1046be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.yres_virtual = oi->display_height;
1047be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
1048be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
1049be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.left_margin = start_window.left + 1;
1050be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.upper_margin = start_window.top + 1;
1051be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
1052be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_defined.nonstd = 0;
105332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
105432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* We've filled in the most data, let the usual mode check
105532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   routine fill in the rest. */
1056be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	_ivtvfb_check_var(&oi->ivtvfb_defined, itv);
105732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
105832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Generate valid fb_fix_screeninfo */
105932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1060be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
106132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
106232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Generate valid fb_info */
106332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1064be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.node = -1;
1065be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
1066be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.fbops = &ivtvfb_ops;
1067be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.par = itv;
1068be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.var = oi->ivtvfb_defined;
1069be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.fix = oi->ivtvfb_fix;
1070be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
1071be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.fbops = &ivtvfb_ops;
107232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
107332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Supply some monitor specs. Bogus values will do for now */
1074be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.hfmin = 8000;
1075be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.hfmax = 70000;
1076be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.vfmin = 10;
1077be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->ivtvfb_info.monspecs.vfmax = 100;
107832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
107932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Allocate color map */
1080be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
1081641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("abort, unable to alloc cmap\n");
108232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENOMEM;
108332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
108432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
108532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Allocate the pseudo palette */
10863f98387efa9333c5765d36e144c47c107d6ba64aHans Verkuil	oi->ivtvfb_info.pseudo_palette =
10873f98387efa9333c5765d36e144c47c107d6ba64aHans Verkuil		kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN);
108832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1089be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!oi->ivtvfb_info.pseudo_palette) {
109025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi		IVTVFB_ERR("abort, unable to alloc pseudo palette\n");
109132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENOMEM;
109232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
109332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
109432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
109532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
109632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
109732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
109832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
109932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int ivtvfb_init_io(struct ivtv *itv)
110032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
1101be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
1102be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
110326e9d599561e9a964bd4d7c2be0029db8aaff852Hans Verkuil	mutex_lock(&itv->serialize_lock);
11046e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil	if (ivtv_init_on_first_open(itv)) {
110526e9d599561e9a964bd4d7c2be0029db8aaff852Hans Verkuil		mutex_unlock(&itv->serialize_lock);
1106641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Failed to initialize ivtv\n");
11076e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil		return -ENXIO;
11086e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil	}
110926e9d599561e9a964bd4d7c2be0029db8aaff852Hans Verkuil	mutex_unlock(&itv->serialize_lock);
11106e5eb59102aa6007d3ea2b382a1d3ca4112c272aHans Verkuil
11115f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong	if (ivtvfb_get_framebuffer(itv, &oi->video_rbase,
11125f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong					&oi->video_buffer_size) < 0) {
11135f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong		IVTVFB_ERR("Firmware failed to respond\n");
11145f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong		return -EIO;
11155f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong	}
111632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
111732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* The osd buffer size depends on the number of video buffers allocated
111832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   on the PVR350 itself. For now we'll hardcode the smallest osd buffer
111932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	   size to prevent any overlap. */
1120be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->video_buffer_size = 1704960;
112132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1122be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1123be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	oi->video_vbase = itv->dec_mem + oi->video_rbase;
112432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1125be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (!oi->video_vbase) {
1126641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1127be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		     oi->video_buffer_size, oi->video_pbase);
112832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EIO;
112932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
113032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1131641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1132be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->video_pbase, oi->video_vbase,
1133be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->video_buffer_size / 1024);
113432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
113532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
113632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	{
113732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		/* Find the largest power of two that maps the whole buffer */
113832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		int size_shift = 31;
113932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1140be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		while (!(oi->video_buffer_size & (1 << size_shift))) {
114132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			size_shift--;
114232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
114332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		size_shift++;
1144be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1145be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1146be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1147be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1148be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		if (mtrr_add(oi->fb_start_aligned_physaddr,
1149be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
115032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil			     MTRR_TYPE_WRCOMB, 1) < 0) {
1151641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil			IVTVFB_INFO("disabled mttr\n");
1152be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_start_aligned_physaddr = 0;
1153be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_end_aligned_physaddr = 0;
115432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		}
115532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
1156be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil#endif
115732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
115832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Blank the entire osd. */
1159be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	memset_io(oi->video_vbase, 0, oi->video_buffer_size);
116032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
116132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
116232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
116332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
116432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Release any memory we've grabbed & remove mtrr entry */
116532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic void ivtvfb_release_buffers (struct ivtv *itv)
116632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
1167be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	struct osd_info *oi = itv->osd_info;
1168be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil
116932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Release cmap */
1170136280322d894e6ec07187f2427b00c3d64ad066Adrian Bunk	if (oi->ivtvfb_info.cmap.len)
1171136280322d894e6ec07187f2427b00c3d64ad066Adrian Bunk		fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
117232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
117332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Release pseudo palette */
117418552ea1322e218b43f7692d9358c930a6d81df1Syam Sidhardhan	kfree(oi->ivtvfb_info.pseudo_palette);
117532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
117632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil#ifdef CONFIG_MTRR
1177be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if (oi->fb_end_aligned_physaddr) {
1178be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil		mtrr_del(-1, oi->fb_start_aligned_physaddr,
1179be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1180be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	}
1181be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil#endif
118232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1183be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	kfree(oi);
118432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->osd_info = NULL;
118532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
118632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
118732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil/* Initialize the specified card */
118832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1189be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuilstatic int ivtvfb_init_card(struct ivtv *itv)
119032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
119132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	int rc;
119232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
119332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (itv->osd_info) {
1194641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
119532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EBUSY;
119632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
119732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
11983f98387efa9333c5765d36e144c47c107d6ba64aHans Verkuil	itv->osd_info = kzalloc(sizeof(struct osd_info),
11993f98387efa9333c5765d36e144c47c107d6ba64aHans Verkuil					GFP_ATOMIC|__GFP_NOWARN);
120014d5deba2737c59444e805c10764d58a3d73e9b2Richard Knutsson	if (itv->osd_info == NULL) {
1201641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		IVTVFB_ERR("Failed to allocate memory for osd_info\n");
120232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENOMEM;
120332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
120432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
120532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Find & setup the OSD buffer */
12065f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong	rc = ivtvfb_init_io(itv);
12075f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong	if (rc) {
12085f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong		ivtvfb_release_buffers(itv);
120932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return rc;
12105f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong	}
121132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
121232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the startup video mode information */
1213be383bd312c4defab8bd4bde8c06fea5bfe0996bHans Verkuil	if ((rc = ivtvfb_init_vidmode(itv))) {
121432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtvfb_release_buffers(itv);
121532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return rc;
121632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
121732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
121832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Register the framebuffer */
121932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
122032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		ivtvfb_release_buffers(itv);
122132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
122232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
122332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
122432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	itv->osd_video_pbase = itv->osd_info->video_pbase;
122532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
122632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set the card to the requested mode */
122732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
122832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
122932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Set color 0 to black */
123032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg(0, 0x02a30);
123132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	write_reg(0, 0x02a34);
123232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
123332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Enable the osd */
123432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
123532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1236215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	/* Enable restart */
1237215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong	itv->ivtvfb_restore = ivtvfb_restore;
1238215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong
123932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	/* Allocate DMA */
124032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	ivtv_udma_alloc(itv);
124132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
124232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
124332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
124432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
124567ec09fdf5e05d4670b617256c696348b5df080bHans Verkuilstatic int __init ivtvfb_callback_init(struct device *dev, void *p)
124667ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil{
124767ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
12488ac05ae3192ce8a71fc84e4a88772cce0c09173cHans Verkuil	struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
124967ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil
125037b58bfe4bb3df303aa9d7f1ccdbfc477b42c5e2Jiri Slaby	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
125167ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		if (ivtvfb_init_card(itv) == 0) {
125267ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil			IVTVFB_INFO("Framebuffer registered on %s\n",
12538ac05ae3192ce8a71fc84e4a88772cce0c09173cHans Verkuil					itv->v4l2_dev.name);
125467ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil			(*(int *)p)++;
125567ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		}
125667ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	}
125767ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	return 0;
125867ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil}
125967ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil
126067ec09fdf5e05d4670b617256c696348b5df080bHans Verkuilstatic int ivtvfb_callback_cleanup(struct device *dev, void *p)
126167ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil{
126267ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
12638ac05ae3192ce8a71fc84e4a88772cce0c09173cHans Verkuil	struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
12645f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong	struct osd_info *oi = itv->osd_info;
126567ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil
126637b58bfe4bb3df303aa9d7f1ccdbfc477b42c5e2Jiri Slaby	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
126767ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
126867ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil			IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
126967ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil				       itv->instance);
127067ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil			return 0;
127167ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		}
127267ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
1273215659d14f9dbc849ccda1655c94d710f8cc6384Ian Armstrong		itv->ivtvfb_restore = NULL;
12745f39b9f660778c3b095fc380da178d58a040add5Ian Armstrong		ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
127567ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		ivtvfb_release_buffers(itv);
127667ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		itv->osd_video_pbase = 0;
127767ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	}
127867ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	return 0;
127967ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil}
128067ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil
128132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic int __init ivtvfb_init(void)
128232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
128367ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	struct device_driver *drv;
128467ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	int registered = 0;
128567ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	int err;
128632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
1287641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil	if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
1288641ed49db6ecf6c539a5eab50a7540542377add1Hans Verkuil		printk(KERN_ERR "ivtvfb:  ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
128932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		     IVTV_MAX_CARDS - 1);
129032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -EINVAL;
129132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
129232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
129367ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	drv = driver_find("ivtv", &pci_bus_type);
129467ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
1295932205a7ea64bab9edda04b9d555a277b57943fdHans Verkuil	(void)err;	/* suppress compiler warning */
129632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	if (!registered) {
129767ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil		printk(KERN_ERR "ivtvfb:  no cards found\n");
129832db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil		return -ENODEV;
129932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	}
130032db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil	return 0;
130132db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
130232db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
130332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilstatic void ivtvfb_cleanup(void)
130432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil{
130567ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	struct device_driver *drv;
130667ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	int err;
130732db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
13087b3a0d49e3e929b810ade38926342faca53e867dHans Verkuil	printk(KERN_INFO "ivtvfb:  Unloading framebuffer module\n");
130932db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
131067ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	drv = driver_find("ivtv", &pci_bus_type);
131167ec09fdf5e05d4670b617256c696348b5df080bHans Verkuil	err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
1312932205a7ea64bab9edda04b9d555a277b57943fdHans Verkuil	(void)err;	/* suppress compiler warning */
131332db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil}
131432db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuil
131532db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_init(ivtvfb_init);
131632db775452818656d5fd8fd8b0f54425f5cfc177Hans Verkuilmodule_exit(ivtvfb_cleanup);
1317