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, ®istered, 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