blob: de2ff1c6ac3476453ef1c3c59732b81510b959fe [file] [log] [blame]
Hans Verkuil32db7752007-07-20 09:29:43 -03001/*
2 On Screen Display cx23415 Framebuffer driver
3
4 This module presents the cx23415 OSD (onscreen display) framebuffer memory
5 as a standard Linux /dev/fb style framebuffer device. The framebuffer has
Hans Verkuilbe383bd2007-07-20 10:16:03 -03006 support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
Hans Verkuil32db7752007-07-20 09:29:43 -03007 mode, there is a choice of a three color depths (12, 15 or 16 bits), but no
8 local alpha. The colorspace is selectable between rgb & yuv.
9 Depending on the TV standard configured in the ivtv module at load time,
10 the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp.
11 Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL)
12 or 59.94 (NTSC)
13
14 Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
15
16 Derived from drivers/video/vesafb.c
17 Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
18
19 2.6 kernel port:
20 Copyright (C) 2004 Matthias Badaire
21
22 Copyright (C) 2004 Chris Kennedy <c@groovy.org>
23
24 Copyright (C) 2006 Ian Armstrong <ian@iarmst.demon.co.uk>
25
26 This program is free software; you can redistribute it and/or modify
27 it under the terms of the GNU General Public License as published by
28 the Free Software Foundation; either version 2 of the License, or
29 (at your option) any later version.
30
31 This program is distributed in the hope that it will be useful,
32 but WITHOUT ANY WARRANTY; without even the implied warranty of
33 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 GNU General Public License for more details.
35
36 You should have received a copy of the GNU General Public License
37 along with this program; if not, write to the Free Software
38 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
39 */
40
41#include <linux/module.h>
42#include <linux/kernel.h>
Hans Verkuil32db7752007-07-20 09:29:43 -030043#include <linux/fb.h>
Hans Verkuil0f45b8c2007-08-26 06:04:10 -030044#include <linux/ivtvfb.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090045#include <linux/slab.h>
Hans Verkuil32db7752007-07-20 09:29:43 -030046
47#ifdef CONFIG_MTRR
48#include <asm/mtrr.h>
49#endif
50
51#include "ivtv-driver.h"
Hans Verkuil67ec09f2008-11-29 19:38:23 -030052#include "ivtv-cards.h"
Ian Armstrong4e7ca402008-10-19 18:58:26 -030053#include "ivtv-i2c.h"
Hans Verkuil32db7752007-07-20 09:29:43 -030054#include "ivtv-udma.h"
Hans Verkuil32db7752007-07-20 09:29:43 -030055#include "ivtv-mailbox.h"
Hans Verkuil32db7752007-07-20 09:29:43 -030056
57/* card parameters */
Hans Verkuil641ed492007-08-28 03:24:31 -030058static int ivtvfb_card_id = -1;
59static int ivtvfb_debug = 0;
Hans Verkuil32db7752007-07-20 09:29:43 -030060static int osd_laced;
Hans Verkuil32db7752007-07-20 09:29:43 -030061static int osd_depth;
62static int osd_upper;
63static int osd_left;
64static int osd_yres;
65static int osd_xres;
66
Hans Verkuil641ed492007-08-28 03:24:31 -030067module_param(ivtvfb_card_id, int, 0444);
68module_param_named(debug,ivtvfb_debug, int, 0644);
Hans Verkuil32db7752007-07-20 09:29:43 -030069module_param(osd_laced, bool, 0444);
Hans Verkuil32db7752007-07-20 09:29:43 -030070module_param(osd_depth, int, 0444);
71module_param(osd_upper, int, 0444);
72module_param(osd_left, int, 0444);
73module_param(osd_yres, int, 0444);
74module_param(osd_xres, int, 0444);
75
Hans Verkuil641ed492007-08-28 03:24:31 -030076MODULE_PARM_DESC(ivtvfb_card_id,
Hans Verkuil32db7752007-07-20 09:29:43 -030077 "Only use framebuffer of the specified ivtv card (0-31)\n"
78 "\t\t\tdefault -1: initialize all available framebuffers");
79
80MODULE_PARM_DESC(debug,
81 "Debug level (bitmask). Default: errors only\n"
82 "\t\t\t(debug = 3 gives full debugging)");
83
Hans Verkuil32db7752007-07-20 09:29:43 -030084/* Why upper, left, xres, yres, depth, laced ? To match terminology used
85 by fbset.
86 Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
87
88MODULE_PARM_DESC(osd_laced,
89 "Interlaced mode\n"
90 "\t\t\t0=off\n"
91 "\t\t\t1=on\n"
92 "\t\t\tdefault off");
93
94MODULE_PARM_DESC(osd_depth,
Hans Verkuilbe383bd2007-07-20 10:16:03 -030095 "Bits per pixel - 8, 16, 32\n"
Hans Verkuil32db7752007-07-20 09:29:43 -030096 "\t\t\tdefault 8");
97
98MODULE_PARM_DESC(osd_upper,
99 "Vertical start position\n"
100 "\t\t\tdefault 0 (Centered)");
101
102MODULE_PARM_DESC(osd_left,
103 "Horizontal start position\n"
104 "\t\t\tdefault 0 (Centered)");
105
106MODULE_PARM_DESC(osd_yres,
107 "Display height\n"
108 "\t\t\tdefault 480 (PAL)\n"
109 "\t\t\t 400 (NTSC)");
110
111MODULE_PARM_DESC(osd_xres,
112 "Display width\n"
113 "\t\t\tdefault 640");
114
115MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
116MODULE_LICENSE("GPL");
117
118/* --------------------------------------------------------------------- */
119
Hans Verkuil641ed492007-08-28 03:24:31 -0300120#define IVTVFB_DBGFLG_WARN (1 << 0)
121#define IVTVFB_DBGFLG_INFO (1 << 1)
Hans Verkuil32db7752007-07-20 09:29:43 -0300122
Hans Verkuil641ed492007-08-28 03:24:31 -0300123#define IVTVFB_DEBUG(x, type, fmt, args...) \
Hans Verkuil32db7752007-07-20 09:29:43 -0300124 do { \
Hans Verkuil641ed492007-08-28 03:24:31 -0300125 if ((x) & ivtvfb_debug) \
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300126 printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \
Hans Verkuil32db7752007-07-20 09:29:43 -0300127 } while (0)
Hans Verkuil641ed492007-08-28 03:24:31 -0300128#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
129#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
Hans Verkuil32db7752007-07-20 09:29:43 -0300130
131/* Standard kernel messages */
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300132#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->instance , ## args)
133#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->instance , ## args)
134#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args)
Hans Verkuil32db7752007-07-20 09:29:43 -0300135
136/* --------------------------------------------------------------------- */
137
138#define IVTV_OSD_MAX_WIDTH 720
139#define IVTV_OSD_MAX_HEIGHT 576
140
141#define IVTV_OSD_BPP_8 0x00
142#define IVTV_OSD_BPP_16_444 0x03
143#define IVTV_OSD_BPP_16_555 0x02
144#define IVTV_OSD_BPP_16_565 0x01
145#define IVTV_OSD_BPP_32 0x04
146
147struct osd_info {
Hans Verkuil32db7752007-07-20 09:29:43 -0300148 /* Physical base address */
149 unsigned long video_pbase;
150 /* Relative base address (relative to start of decoder memory) */
151 u32 video_rbase;
152 /* Mapped base address */
153 volatile char __iomem *video_vbase;
154 /* Buffer size */
155 u32 video_buffer_size;
156
157#ifdef CONFIG_MTRR
158 /* video_base rounded down as required by hardware MTRRs */
159 unsigned long fb_start_aligned_physaddr;
160 /* video_base rounded up as required by hardware MTRRs */
161 unsigned long fb_end_aligned_physaddr;
162#endif
163
164 /* Store the buffer offset */
165 int set_osd_coords_x;
166 int set_osd_coords_y;
167
168 /* Current dimensions (NOT VISIBLE SIZE!) */
169 int display_width;
170 int display_height;
171 int display_byte_stride;
172
173 /* Current bits per pixel */
174 int bits_per_pixel;
175 int bytes_per_pixel;
176
177 /* Frame buffer stuff */
178 struct fb_info ivtvfb_info;
179 struct fb_var_screeninfo ivtvfb_defined;
180 struct fb_fix_screeninfo ivtvfb_fix;
181};
182
183struct ivtv_osd_coords {
184 unsigned long offset;
185 unsigned long max_offset;
186 int pixel_stride;
187 int lines;
188 int x;
189 int y;
190};
191
192/* --------------------------------------------------------------------- */
193
194/* ivtv API calls for framebuffer related support */
195
Hans Verkuil641ed492007-08-28 03:24:31 -0300196static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
Hans Verkuil32db7752007-07-20 09:29:43 -0300197 u32 *fblength)
198{
199 u32 data[CX2341X_MBOX_MAX_DATA];
200 int rc;
201
202 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
203 *fbbase = data[0];
204 *fblength = data[1];
205 return rc;
206}
207
Hans Verkuil641ed492007-08-28 03:24:31 -0300208static int ivtvfb_get_osd_coords(struct ivtv *itv,
Hans Verkuil32db7752007-07-20 09:29:43 -0300209 struct ivtv_osd_coords *osd)
210{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300211 struct osd_info *oi = itv->osd_info;
Hans Verkuil32db7752007-07-20 09:29:43 -0300212 u32 data[CX2341X_MBOX_MAX_DATA];
213
214 ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
215
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300216 osd->offset = data[0] - oi->video_rbase;
217 osd->max_offset = oi->display_width * oi->display_height * 4;
Hans Verkuil32db7752007-07-20 09:29:43 -0300218 osd->pixel_stride = data[1];
219 osd->lines = data[2];
220 osd->x = data[3];
221 osd->y = data[4];
222 return 0;
223}
224
Hans Verkuil641ed492007-08-28 03:24:31 -0300225static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
Hans Verkuil32db7752007-07-20 09:29:43 -0300226{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300227 struct osd_info *oi = itv->osd_info;
228
229 oi->display_width = osd->pixel_stride;
230 oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
231 oi->set_osd_coords_x += osd->x;
232 oi->set_osd_coords_y = osd->y;
Hans Verkuil32db7752007-07-20 09:29:43 -0300233
234 return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300235 osd->offset + oi->video_rbase,
Hans Verkuil32db7752007-07-20 09:29:43 -0300236 osd->pixel_stride,
237 osd->lines, osd->x, osd->y);
238}
239
Hans Verkuil641ed492007-08-28 03:24:31 -0300240static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
Hans Verkuil32db7752007-07-20 09:29:43 -0300241{
Hans Verkuil32db7752007-07-20 09:29:43 -0300242 int osd_height_limit = itv->is_50hz ? 576 : 480;
243
244 /* Only fail if resolution too high, otherwise fudge the start coords. */
245 if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
246 return -EINVAL;
247
248 /* Ensure we don't exceed display limits */
249 if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300250 IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300251 ivtv_window->top, ivtv_window->height);
252 ivtv_window->top = osd_height_limit - ivtv_window->height;
253 }
254
255 if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300256 IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300257 ivtv_window->left, ivtv_window->width);
258 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
259 }
260
261 /* Set the OSD origin */
262 write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
263
264 /* How much to display */
265 write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
266
267 /* Pass this info back the yuv handler */
268 itv->yuv_info.osd_vis_w = ivtv_window->width;
269 itv->yuv_info.osd_vis_h = ivtv_window->height;
270 itv->yuv_info.osd_x_offset = ivtv_window->left;
271 itv->yuv_info.osd_y_offset = ivtv_window->top;
272
273 return 0;
274}
275
Hans Verkuil641ed492007-08-28 03:24:31 -0300276static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
Hans Verkuil32db7752007-07-20 09:29:43 -0300277 unsigned long ivtv_dest_addr, void __user *userbuf,
278 int size_in_bytes)
279{
280 DEFINE_WAIT(wait);
Hans Verkuil32db7752007-07-20 09:29:43 -0300281 int got_sig = 0;
282
283 mutex_lock(&itv->udma.lock);
284 /* Map User DMA */
285 if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
286 mutex_unlock(&itv->udma.lock);
Hans Verkuil641ed492007-08-28 03:24:31 -0300287 IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, "
Hans Verkuil32db7752007-07-20 09:29:43 -0300288 "Error with get_user_pages: %d bytes, %d pages returned\n",
289 size_in_bytes, itv->udma.page_count);
290
291 /* get_user_pages must have failed completely */
292 return -EIO;
293 }
294
Hans Verkuil641ed492007-08-28 03:24:31 -0300295 IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300296 size_in_bytes, itv->udma.page_count);
297
298 ivtv_udma_prepare(itv);
299 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
300 /* if no UDMA is pending and no UDMA is in progress, then the DMA
301 is finished */
Hans Verkuilec105a42009-05-02 11:10:23 -0300302 while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
303 test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
Hans Verkuil32db7752007-07-20 09:29:43 -0300304 /* don't interrupt if the DMA is in progress but break off
305 a still pending DMA. */
306 got_sig = signal_pending(current);
307 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
308 break;
309 got_sig = 0;
310 schedule();
311 }
312 finish_wait(&itv->dma_waitq, &wait);
313
314 /* Unmap Last DMA Xfer */
315 ivtv_udma_unmap(itv);
316 mutex_unlock(&itv->udma.lock);
317 if (got_sig) {
318 IVTV_DEBUG_INFO("User stopped OSD\n");
319 return -EINTR;
320 }
321
Ian Armstrongc7775492008-10-04 10:28:24 -0300322 return 0;
Hans Verkuil32db7752007-07-20 09:29:43 -0300323}
324
Hans Verkuil641ed492007-08-28 03:24:31 -0300325static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300326 unsigned long dest_offset, int count)
Hans Verkuil32db7752007-07-20 09:29:43 -0300327{
328 DEFINE_WAIT(wait);
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300329 struct osd_info *oi = itv->osd_info;
Hans Verkuil32db7752007-07-20 09:29:43 -0300330
331 /* Nothing to do */
332 if (count == 0) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300333 IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300334 return -EINVAL;
335 }
336
337 /* Check Total FB Size */
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300338 if ((dest_offset + count) > oi->video_buffer_size) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300339 IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300340 dest_offset + count, oi->video_buffer_size);
Hans Verkuil32db7752007-07-20 09:29:43 -0300341 return -E2BIG;
342 }
343
344 /* Not fatal, but will have undesirable results */
345 if ((unsigned long)source & 3)
Hans Verkuil641ed492007-08-28 03:24:31 -0300346 IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300347 (unsigned long)source);
Hans Verkuil32db7752007-07-20 09:29:43 -0300348
349 if (dest_offset & 3)
Hans Verkuil641ed492007-08-28 03:24:31 -0300350 IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
Hans Verkuil32db7752007-07-20 09:29:43 -0300351
352 if (count & 3)
Hans Verkuil641ed492007-08-28 03:24:31 -0300353 IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
Hans Verkuil32db7752007-07-20 09:29:43 -0300354
355 /* Check Source */
356 if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300357 IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300358 (unsigned long)source);
359
Hans Verkuil641ed492007-08-28 03:24:31 -0300360 IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
Hans Verkuil32db7752007-07-20 09:29:43 -0300361 dest_offset, (unsigned long)source,
362 count);
363 return -EINVAL;
364 }
365
366 /* OSD Address to send DMA to */
Hans Verkuil33c0fca2007-08-23 06:32:46 -0300367 dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
Hans Verkuil32db7752007-07-20 09:29:43 -0300368
369 /* Fill Buffers */
Hans Verkuil641ed492007-08-28 03:24:31 -0300370 return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
Hans Verkuil32db7752007-07-20 09:29:43 -0300371}
372
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300373static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
Ian Armstrong4ee0e422008-10-06 03:03:18 -0300374 size_t count, loff_t *ppos)
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300375{
376 unsigned long p = *ppos;
377 void *dst;
378 int err = 0;
Ian Armstrongc7775492008-10-04 10:28:24 -0300379 int dma_err;
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300380 unsigned long total_size;
381 struct ivtv *itv = (struct ivtv *) info->par;
382 unsigned long dma_offset =
383 IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
384 unsigned long dma_size;
385 u16 lead = 0, tail = 0;
386
387 if (info->state != FBINFO_STATE_RUNNING)
388 return -EPERM;
389
390 total_size = info->screen_size;
391
392 if (total_size == 0)
393 total_size = info->fix.smem_len;
394
395 if (p > total_size)
396 return -EFBIG;
397
398 if (count > total_size) {
399 err = -EFBIG;
400 count = total_size;
401 }
402
403 if (count + p > total_size) {
404 if (!err)
405 err = -ENOSPC;
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300406 count = total_size - p;
407 }
408
409 dst = (void __force *) (info->screen_base + p);
410
411 if (info->fbops->fb_sync)
412 info->fbops->fb_sync(info);
413
Ian Armstrongc7775492008-10-04 10:28:24 -0300414 /* If transfer size > threshold and both src/dst
415 addresses are aligned, use DMA */
416 if (count >= 4096 &&
417 ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
418 /* Odd address = can't DMA. Align */
419 if ((unsigned long)dst & 3) {
420 lead = 4 - ((unsigned long)dst & 3);
421 if (copy_from_user(dst, buf, lead))
422 return -EFAULT;
423 buf += lead;
424 dst += lead;
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300425 }
Ian Armstrongc7775492008-10-04 10:28:24 -0300426 /* DMA resolution is 32 bits */
427 if ((count - lead) & 3)
428 tail = (count - lead) & 3;
429 /* DMA the data */
430 dma_size = count - lead - tail;
431 dma_err = ivtvfb_prep_dec_dma_to_device(itv,
432 p + lead + dma_offset, (void __user *)buf, dma_size);
433 if (dma_err)
434 return dma_err;
435 dst += dma_size;
436 buf += dma_size;
437 /* Copy any leftover data */
438 if (tail && copy_from_user(dst, buf, tail))
439 return -EFAULT;
440 } else if (copy_from_user(dst, buf, count)) {
441 return -EFAULT;
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300442 }
443
444 if (!err)
445 *ppos += count;
446
447 return (err) ? err : count;
448}
449
Hans Verkuil32db7752007-07-20 09:29:43 -0300450static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
451{
452 DEFINE_WAIT(wait);
453 struct ivtv *itv = (struct ivtv *)info->par;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300454 int rc = 0;
Hans Verkuil32db7752007-07-20 09:29:43 -0300455
456 switch (cmd) {
Hans Verkuil32db7752007-07-20 09:29:43 -0300457 case FBIOGET_VBLANK: {
458 struct fb_vblank vblank;
459 u32 trace;
460
461 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
462 FB_VBLANK_HAVE_VSYNC;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300463 trace = read_reg(0x028c0) >> 16;
Ian Armstrongc7775492008-10-04 10:28:24 -0300464 if (itv->is_50hz && trace > 312)
465 trace -= 312;
466 else if (itv->is_60hz && trace > 262)
467 trace -= 262;
468 if (trace == 1)
469 vblank.flags |= FB_VBLANK_VSYNCING;
Hans Verkuila158f352007-08-23 11:31:57 -0300470 vblank.count = itv->last_vsync_field;
Hans Verkuil32db7752007-07-20 09:29:43 -0300471 vblank.vcount = trace;
472 vblank.hcount = 0;
473 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
474 return -EFAULT;
475 return 0;
476 }
477
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300478 case FBIO_WAITFORVSYNC:
Hans Verkuil32db7752007-07-20 09:29:43 -0300479 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
Ian Armstrongc7775492008-10-04 10:28:24 -0300480 if (!schedule_timeout(msecs_to_jiffies(50)))
481 rc = -ETIMEDOUT;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300482 finish_wait(&itv->vsync_waitq, &wait);
Hans Verkuil32db7752007-07-20 09:29:43 -0300483 return rc;
Hans Verkuil32db7752007-07-20 09:29:43 -0300484
Hans Verkuild715e762007-07-20 10:30:32 -0300485 case IVTVFB_IOC_DMA_FRAME: {
486 struct ivtvfb_dma_frame args;
Hans Verkuil32db7752007-07-20 09:29:43 -0300487
Hans Verkuil641ed492007-08-28 03:24:31 -0300488 IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300489 if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
490 return -EFAULT;
491
Hans Verkuil641ed492007-08-28 03:24:31 -0300492 return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
Hans Verkuil32db7752007-07-20 09:29:43 -0300493 }
494
495 default:
Hans Verkuil641ed492007-08-28 03:24:31 -0300496 IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
Hans Verkuil32db7752007-07-20 09:29:43 -0300497 return -EINVAL;
498 }
499 return 0;
500}
501
502/* Framebuffer device handling */
503
504static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
505{
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300506 struct osd_info *oi = itv->osd_info;
Hans Verkuil32db7752007-07-20 09:29:43 -0300507 struct ivtv_osd_coords ivtv_osd;
508 struct v4l2_rect ivtv_window;
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300509 int osd_mode = -1;
Hans Verkuil32db7752007-07-20 09:29:43 -0300510
Hans Verkuil641ed492007-08-28 03:24:31 -0300511 IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300512
513 /* Select color space */
514 if (var->nonstd) /* YUV */
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300515 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
Hans Verkuil32db7752007-07-20 09:29:43 -0300516 else /* RGB */
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300517 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
Hans Verkuil32db7752007-07-20 09:29:43 -0300518
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300519 /* Set the color mode */
Hans Verkuil32db7752007-07-20 09:29:43 -0300520 switch (var->bits_per_pixel) {
521 case 8:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300522 osd_mode = IVTV_OSD_BPP_8;
Hans Verkuil32db7752007-07-20 09:29:43 -0300523 break;
524 case 32:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300525 osd_mode = IVTV_OSD_BPP_32;
Hans Verkuil32db7752007-07-20 09:29:43 -0300526 break;
527 case 16:
528 switch (var->green.length) {
529 case 4:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300530 osd_mode = IVTV_OSD_BPP_16_444;
Hans Verkuil32db7752007-07-20 09:29:43 -0300531 break;
532 case 5:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300533 osd_mode = IVTV_OSD_BPP_16_555;
Hans Verkuil32db7752007-07-20 09:29:43 -0300534 break;
535 case 6:
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300536 osd_mode = IVTV_OSD_BPP_16_565;
Hans Verkuil32db7752007-07-20 09:29:43 -0300537 break;
538 default:
Hans Verkuil641ed492007-08-28 03:24:31 -0300539 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300540 }
541 break;
542 default:
Hans Verkuil641ed492007-08-28 03:24:31 -0300543 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300544 }
545
Ian Armstrong6659e3e2007-10-12 08:15:41 -0300546 /* Set video mode. Although rare, the display can become scrambled even
547 if we don't change mode. Always 'bounce' to osd_mode via mode 0 */
548 if (osd_mode != -1) {
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300549 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
550 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
Ian Armstrongaaf9fa22007-07-21 16:43:36 -0300551 }
552
553 oi->bits_per_pixel = var->bits_per_pixel;
554 oi->bytes_per_pixel = var->bits_per_pixel / 8;
Hans Verkuil32db7752007-07-20 09:29:43 -0300555
556 /* Set the flicker filter */
557 switch (var->vmode & FB_VMODE_MASK) {
558 case FB_VMODE_NONINTERLACED: /* Filter on */
559 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
560 break;
561 case FB_VMODE_INTERLACED: /* Filter off */
562 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
563 break;
564 default:
Hans Verkuil641ed492007-08-28 03:24:31 -0300565 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300566 }
567
568 /* Read the current osd info */
Hans Verkuil641ed492007-08-28 03:24:31 -0300569 ivtvfb_get_osd_coords(itv, &ivtv_osd);
Hans Verkuil32db7752007-07-20 09:29:43 -0300570
571 /* Now set the OSD to the size we want */
572 ivtv_osd.pixel_stride = var->xres_virtual;
573 ivtv_osd.lines = var->yres_virtual;
574 ivtv_osd.x = 0;
575 ivtv_osd.y = 0;
Hans Verkuil641ed492007-08-28 03:24:31 -0300576 ivtvfb_set_osd_coords(itv, &ivtv_osd);
Hans Verkuil32db7752007-07-20 09:29:43 -0300577
578 /* Can't seem to find the right API combo for this.
579 Use another function which does what we need through direct register access. */
580 ivtv_window.width = var->xres;
581 ivtv_window.height = var->yres;
582
583 /* Minimum margin cannot be 0, as X won't allow such a mode */
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300584 if (!var->upper_margin) var->upper_margin++;
585 if (!var->left_margin) var->left_margin++;
Hans Verkuil32db7752007-07-20 09:29:43 -0300586 ivtv_window.top = var->upper_margin - 1;
587 ivtv_window.left = var->left_margin - 1;
588
Hans Verkuil641ed492007-08-28 03:24:31 -0300589 ivtvfb_set_display_window(itv, &ivtv_window);
Hans Verkuil32db7752007-07-20 09:29:43 -0300590
Ian Armstrong77aded62007-11-05 14:27:09 -0300591 /* Pass screen size back to yuv handler */
592 itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
593 itv->yuv_info.osd_full_h = ivtv_osd.lines;
594
Hans Verkuil32db7752007-07-20 09:29:43 -0300595 /* Force update of yuv registers */
596 itv->yuv_info.yuv_forced_update = 1;
597
Hans Verkuil641ed492007-08-28 03:24:31 -0300598 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300599 var->xres, var->yres,
600 var->xres_virtual, var->yres_virtual,
601 var->bits_per_pixel);
Hans Verkuil32db7752007-07-20 09:29:43 -0300602
Hans Verkuil641ed492007-08-28 03:24:31 -0300603 IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300604 var->left_margin, var->upper_margin);
Hans Verkuil32db7752007-07-20 09:29:43 -0300605
Hans Verkuil641ed492007-08-28 03:24:31 -0300606 IVTVFB_DEBUG_INFO("Display filter: %s\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300607 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
Hans Verkuil641ed492007-08-28 03:24:31 -0300608 IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
Hans Verkuil32db7752007-07-20 09:29:43 -0300609
610 return 0;
611}
612
613static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
614{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300615 struct osd_info *oi = itv->osd_info;
616
Hans Verkuil641ed492007-08-28 03:24:31 -0300617 IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300618 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
Hans Verkuilcebfadf2008-04-26 08:51:51 -0300619 strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300620 fix->smem_start = oi->video_pbase;
621 fix->smem_len = oi->video_buffer_size;
Hans Verkuil32db7752007-07-20 09:29:43 -0300622 fix->type = FB_TYPE_PACKED_PIXELS;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300623 fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
Hans Verkuil32db7752007-07-20 09:29:43 -0300624 fix->xpanstep = 1;
625 fix->ypanstep = 1;
626 fix->ywrapstep = 0;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300627 fix->line_length = oi->display_byte_stride;
Hans Verkuil32db7752007-07-20 09:29:43 -0300628 fix->accel = FB_ACCEL_NONE;
629 return 0;
630}
631
632/* Check the requested display mode, returning -EINVAL if we can't
633 handle it. */
634
635static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
636{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300637 struct osd_info *oi = itv->osd_info;
Ian Armstrong68a341a2007-08-03 09:51:58 -0300638 int osd_height_limit;
639 u32 pixclock, hlimit, vlimit;
Hans Verkuil32db7752007-07-20 09:29:43 -0300640
Hans Verkuil641ed492007-08-28 03:24:31 -0300641 IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300642
Ian Armstrong68a341a2007-08-03 09:51:58 -0300643 /* Set base references for mode calcs. */
644 if (itv->is_50hz) {
645 pixclock = 84316;
646 hlimit = 776;
647 vlimit = 591;
648 osd_height_limit = 576;
649 }
650 else {
651 pixclock = 83926;
652 hlimit = 776;
653 vlimit = 495;
654 osd_height_limit = 480;
655 }
656
Hans Verkuil32db7752007-07-20 09:29:43 -0300657 if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
658 var->transp.offset = 24;
659 var->transp.length = 8;
660 var->red.offset = 16;
661 var->red.length = 8;
662 var->green.offset = 8;
663 var->green.length = 8;
664 var->blue.offset = 0;
665 var->blue.length = 8;
666 }
667 else if (var->bits_per_pixel == 16) {
668 /* To find out the true mode, check green length */
669 switch (var->green.length) {
670 case 4:
Hans Verkuil32db7752007-07-20 09:29:43 -0300671 var->red.offset = 8;
672 var->red.length = 4;
673 var->green.offset = 4;
674 var->green.length = 4;
675 var->blue.offset = 0;
676 var->blue.length = 4;
Hans Verkuil459a52f2007-08-22 08:58:47 -0300677 var->transp.offset = 12;
678 var->transp.length = 1;
Hans Verkuil32db7752007-07-20 09:29:43 -0300679 break;
680 case 5:
Hans Verkuil32db7752007-07-20 09:29:43 -0300681 var->red.offset = 10;
682 var->red.length = 5;
683 var->green.offset = 5;
684 var->green.length = 5;
685 var->blue.offset = 0;
686 var->blue.length = 5;
Hans Verkuil459a52f2007-08-22 08:58:47 -0300687 var->transp.offset = 15;
688 var->transp.length = 1;
Hans Verkuil32db7752007-07-20 09:29:43 -0300689 break;
690 default:
Hans Verkuil32db7752007-07-20 09:29:43 -0300691 var->red.offset = 11;
692 var->red.length = 5;
693 var->green.offset = 5;
694 var->green.length = 6;
695 var->blue.offset = 0;
696 var->blue.length = 5;
Hans Verkuil459a52f2007-08-22 08:58:47 -0300697 var->transp.offset = 0;
698 var->transp.length = 0;
Hans Verkuil32db7752007-07-20 09:29:43 -0300699 break;
700 }
701 }
702 else {
Hans Verkuil641ed492007-08-28 03:24:31 -0300703 IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
Hans Verkuil32db7752007-07-20 09:29:43 -0300704 return -EINVAL;
705 }
706
707 /* Check the resolution */
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300708 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
709 IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
710 var->xres, var->yres);
711 return -EINVAL;
Hans Verkuil32db7752007-07-20 09:29:43 -0300712 }
Hans Verkuil32db7752007-07-20 09:29:43 -0300713
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300714 /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
715 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
716 var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
717 var->xres_virtual < var->xres ||
718 var->yres_virtual < var->yres) {
719 IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
720 var->xres_virtual, var->yres_virtual);
721 return -EINVAL;
Hans Verkuil32db7752007-07-20 09:29:43 -0300722 }
723
724 /* Some extra checks if in 8 bit mode */
725 if (var->bits_per_pixel == 8) {
726 /* Width must be a multiple of 4 */
727 if (var->xres & 3) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300728 IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
Hans Verkuil32db7752007-07-20 09:29:43 -0300729 return -EINVAL;
730 }
731 if (var->xres_virtual & 3) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300732 IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
Hans Verkuil32db7752007-07-20 09:29:43 -0300733 return -EINVAL;
734 }
735 }
736 else if (var->bits_per_pixel == 16) {
737 /* Width must be a multiple of 2 */
738 if (var->xres & 1) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300739 IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
Hans Verkuil32db7752007-07-20 09:29:43 -0300740 return -EINVAL;
741 }
742 if (var->xres_virtual & 1) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300743 IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
Hans Verkuil32db7752007-07-20 09:29:43 -0300744 return -EINVAL;
745 }
746 }
747
748 /* Now check the offsets */
749 if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300750 IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300751 var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
Hans Verkuil32db7752007-07-20 09:29:43 -0300752 return -EINVAL;
753 }
754
755 /* Check pixel format */
756 if (var->nonstd > 1) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300757 IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
Hans Verkuil32db7752007-07-20 09:29:43 -0300758 return -EINVAL;
759 }
760
761 /* Check video mode */
762 if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
763 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300764 IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
Hans Verkuil32db7752007-07-20 09:29:43 -0300765 return -EINVAL;
766 }
767
768 /* Check the left & upper margins
769 If the margins are too large, just center the screen
770 (enforcing margins causes too many problems) */
771
772 if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
773 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
774 }
775 if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
776 var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
777 }
778
779 /* Maintain overall 'size' for a constant refresh rate */
Ian Armstrong68a341a2007-08-03 09:51:58 -0300780 var->right_margin = hlimit - var->left_margin - var->xres;
781 var->lower_margin = vlimit - var->upper_margin - var->yres;
Hans Verkuil32db7752007-07-20 09:29:43 -0300782
783 /* Fixed sync times */
784 var->hsync_len = 24;
785 var->vsync_len = 2;
786
787 /* Non-interlaced / interlaced mode is used to switch the OSD filter
788 on or off. Adjust the clock timings to maintain a constant
789 vertical refresh rate. */
Hans Verkuil32db7752007-07-20 09:29:43 -0300790 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
Ian Armstrong68a341a2007-08-03 09:51:58 -0300791 var->pixclock = pixclock / 2;
792 else
793 var->pixclock = pixclock;
Hans Verkuil32db7752007-07-20 09:29:43 -0300794
Hans Verkuil37f89f92008-06-22 11:57:31 -0300795 itv->osd_rect.width = var->xres;
796 itv->osd_rect.height = var->yres;
797
Hans Verkuil641ed492007-08-28 03:24:31 -0300798 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300799 var->xres, var->yres,
800 var->xres_virtual, var->yres_virtual,
Hans Verkuil32db7752007-07-20 09:29:43 -0300801 var->bits_per_pixel);
802
Hans Verkuil641ed492007-08-28 03:24:31 -0300803 IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300804 var->left_margin, var->upper_margin);
Hans Verkuil32db7752007-07-20 09:29:43 -0300805
Hans Verkuil641ed492007-08-28 03:24:31 -0300806 IVTVFB_DEBUG_INFO("Display filter: %s\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300807 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
Hans Verkuil641ed492007-08-28 03:24:31 -0300808 IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
Hans Verkuil32db7752007-07-20 09:29:43 -0300809 return 0;
810}
811
812static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
813{
814 struct ivtv *itv = (struct ivtv *) info->par;
Hans Verkuil641ed492007-08-28 03:24:31 -0300815 IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300816 return _ivtvfb_check_var(var, itv);
Hans Verkuil32db7752007-07-20 09:29:43 -0300817}
818
819static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
820{
821 u32 osd_pan_index;
822 struct ivtv *itv = (struct ivtv *) info->par;
823
824 osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300825 write_reg(osd_pan_index, 0x02A0C);
Hans Verkuil32db7752007-07-20 09:29:43 -0300826
827 /* Pass this info back the yuv handler */
828 itv->yuv_info.osd_x_pan = var->xoffset;
829 itv->yuv_info.osd_y_pan = var->yoffset;
830 /* Force update of yuv registers */
831 itv->yuv_info.yuv_forced_update = 1;
832 return 0;
833}
834
835static int ivtvfb_set_par(struct fb_info *info)
836{
837 int rc = 0;
838 struct ivtv *itv = (struct ivtv *) info->par;
839
Hans Verkuil641ed492007-08-28 03:24:31 -0300840 IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300841
842 rc = ivtvfb_set_var(itv, &info->var);
843 ivtvfb_pan_display(&info->var, info);
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300844 ivtvfb_get_fix(itv, &info->fix);
Hans Verkuil32db7752007-07-20 09:29:43 -0300845 return rc;
846}
847
848static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
849 unsigned blue, unsigned transp,
850 struct fb_info *info)
851{
852 u32 color, *palette;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300853 struct ivtv *itv = (struct ivtv *)info->par;
Hans Verkuil32db7752007-07-20 09:29:43 -0300854
855 if (regno >= info->cmap.len)
856 return -EINVAL;
857
858 color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
859 if (info->var.bits_per_pixel <= 8) {
860 write_reg(regno, 0x02a30);
861 write_reg(color, 0x02a34);
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300862 return 0;
Hans Verkuil32db7752007-07-20 09:29:43 -0300863 }
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300864 if (regno >= 16)
865 return -EINVAL;
Hans Verkuil32db7752007-07-20 09:29:43 -0300866
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300867 palette = info->pseudo_palette;
868 if (info->var.bits_per_pixel == 16) {
869 switch (info->var.green.length) {
870 case 4:
871 color = ((red & 0xf000) >> 4) |
872 ((green & 0xf000) >> 8) |
873 ((blue & 0xf000) >> 12);
874 break;
875 case 5:
876 color = ((red & 0xf800) >> 1) |
877 ((green & 0xf800) >> 6) |
878 ((blue & 0xf800) >> 11);
879 break;
880 case 6:
881 color = (red & 0xf800 ) |
882 ((green & 0xfc00) >> 5) |
883 ((blue & 0xf800) >> 11);
884 break;
Hans Verkuil32db7752007-07-20 09:29:43 -0300885 }
Hans Verkuil32db7752007-07-20 09:29:43 -0300886 }
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300887 palette[regno] = color;
Hans Verkuil32db7752007-07-20 09:29:43 -0300888 return 0;
889}
890
891/* We don't really support blanking. All this does is enable or
892 disable the OSD. */
893static int ivtvfb_blank(int blank_mode, struct fb_info *info)
894{
895 struct ivtv *itv = (struct ivtv *)info->par;
896
Hans Verkuil641ed492007-08-28 03:24:31 -0300897 IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
Hans Verkuil32db7752007-07-20 09:29:43 -0300898 switch (blank_mode) {
899 case FB_BLANK_UNBLANK:
900 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300901 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
Hans Verkuil32db7752007-07-20 09:29:43 -0300902 break;
903 case FB_BLANK_NORMAL:
904 case FB_BLANK_HSYNC_SUSPEND:
905 case FB_BLANK_VSYNC_SUSPEND:
Ian Armstrong4e7ca402008-10-19 18:58:26 -0300906 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300907 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
Ian Armstrong4e7ca402008-10-19 18:58:26 -0300908 break;
Hans Verkuil32db7752007-07-20 09:29:43 -0300909 case FB_BLANK_POWERDOWN:
Hans Verkuil67ec09f2008-11-29 19:38:23 -0300910 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
Hans Verkuil32db7752007-07-20 09:29:43 -0300911 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
912 break;
913 }
914 return 0;
915}
916
917static struct fb_ops ivtvfb_ops = {
918 .owner = THIS_MODULE,
Ian Armstrong4cbeb3712008-05-12 11:53:10 -0300919 .fb_write = ivtvfb_write,
Hans Verkuil32db7752007-07-20 09:29:43 -0300920 .fb_check_var = ivtvfb_check_var,
921 .fb_set_par = ivtvfb_set_par,
922 .fb_setcolreg = ivtvfb_setcolreg,
923 .fb_fillrect = cfb_fillrect,
924 .fb_copyarea = cfb_copyarea,
925 .fb_imageblit = cfb_imageblit,
926 .fb_cursor = NULL,
927 .fb_ioctl = ivtvfb_ioctl,
928 .fb_pan_display = ivtvfb_pan_display,
929 .fb_blank = ivtvfb_blank,
930};
931
932/* Initialization */
933
934
935/* Setup our initial video mode */
936static int ivtvfb_init_vidmode(struct ivtv *itv)
937{
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300938 struct osd_info *oi = itv->osd_info;
Hans Verkuil32db7752007-07-20 09:29:43 -0300939 struct v4l2_rect start_window;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300940 int max_height;
Hans Verkuil32db7752007-07-20 09:29:43 -0300941
Hans Verkuil32db7752007-07-20 09:29:43 -0300942 /* Color mode */
943
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300944 if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32)
945 osd_depth = 8;
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300946 oi->bits_per_pixel = osd_depth;
947 oi->bytes_per_pixel = oi->bits_per_pixel / 8;
Hans Verkuil32db7752007-07-20 09:29:43 -0300948
949 /* Horizontal size & position */
950
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300951 if (osd_xres > 720)
952 osd_xres = 720;
Hans Verkuil32db7752007-07-20 09:29:43 -0300953
954 /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
955 if (osd_depth == 8)
956 osd_xres &= ~3;
957 else if (osd_depth == 16)
958 osd_xres &= ~1;
959
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300960 start_window.width = osd_xres ? osd_xres : 640;
Hans Verkuil32db7752007-07-20 09:29:43 -0300961
962 /* Check horizontal start (osd_left). */
963 if (osd_left && osd_left + start_window.width > 721) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300964 IVTVFB_ERR("Invalid osd_left - assuming default\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300965 osd_left = 0;
966 }
967
968 /* Hardware coords start at 0, user coords start at 1. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300969 osd_left--;
Hans Verkuil32db7752007-07-20 09:29:43 -0300970
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300971 start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
Hans Verkuil32db7752007-07-20 09:29:43 -0300972
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300973 oi->display_byte_stride =
974 start_window.width * oi->bytes_per_pixel;
Hans Verkuil32db7752007-07-20 09:29:43 -0300975
976 /* Vertical size & position */
977
978 max_height = itv->is_50hz ? 576 : 480;
979
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300980 if (osd_yres > max_height)
981 osd_yres = max_height;
Hans Verkuil32db7752007-07-20 09:29:43 -0300982
Ian Armstrong6b1ec9d2007-10-17 15:09:56 -0300983 start_window.height = osd_yres ? osd_yres : itv->is_50hz ? 480 : 400;
Hans Verkuil32db7752007-07-20 09:29:43 -0300984
985 /* Check vertical start (osd_upper). */
986 if (osd_upper + start_window.height > max_height + 1) {
Hans Verkuil641ed492007-08-28 03:24:31 -0300987 IVTVFB_ERR("Invalid osd_upper - assuming default\n");
Hans Verkuil32db7752007-07-20 09:29:43 -0300988 osd_upper = 0;
989 }
990
991 /* Hardware coords start at 0, user coords start at 1. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300992 osd_upper--;
Hans Verkuil32db7752007-07-20 09:29:43 -0300993
994 start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
995
Hans Verkuilbe383bd2007-07-20 10:16:03 -0300996 oi->display_width = start_window.width;
997 oi->display_height = start_window.height;
Hans Verkuil32db7752007-07-20 09:29:43 -0300998
999 /* Generate a valid fb_var_screeninfo */
1000
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001001 oi->ivtvfb_defined.xres = oi->display_width;
1002 oi->ivtvfb_defined.yres = oi->display_height;
1003 oi->ivtvfb_defined.xres_virtual = oi->display_width;
1004 oi->ivtvfb_defined.yres_virtual = oi->display_height;
1005 oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
1006 oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
1007 oi->ivtvfb_defined.left_margin = start_window.left + 1;
1008 oi->ivtvfb_defined.upper_margin = start_window.top + 1;
1009 oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
1010 oi->ivtvfb_defined.nonstd = 0;
Hans Verkuil32db7752007-07-20 09:29:43 -03001011
1012 /* We've filled in the most data, let the usual mode check
1013 routine fill in the rest. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001014 _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
Hans Verkuil32db7752007-07-20 09:29:43 -03001015
1016 /* Generate valid fb_fix_screeninfo */
1017
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001018 ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
Hans Verkuil32db7752007-07-20 09:29:43 -03001019
1020 /* Generate valid fb_info */
1021
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001022 oi->ivtvfb_info.node = -1;
1023 oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
1024 oi->ivtvfb_info.fbops = &ivtvfb_ops;
1025 oi->ivtvfb_info.par = itv;
1026 oi->ivtvfb_info.var = oi->ivtvfb_defined;
1027 oi->ivtvfb_info.fix = oi->ivtvfb_fix;
1028 oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
1029 oi->ivtvfb_info.fbops = &ivtvfb_ops;
Hans Verkuil32db7752007-07-20 09:29:43 -03001030
1031 /* Supply some monitor specs. Bogus values will do for now */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001032 oi->ivtvfb_info.monspecs.hfmin = 8000;
1033 oi->ivtvfb_info.monspecs.hfmax = 70000;
1034 oi->ivtvfb_info.monspecs.vfmin = 10;
1035 oi->ivtvfb_info.monspecs.vfmax = 100;
Hans Verkuil32db7752007-07-20 09:29:43 -03001036
1037 /* Allocate color map */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001038 if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001039 IVTVFB_ERR("abort, unable to alloc cmap\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001040 return -ENOMEM;
1041 }
1042
1043 /* Allocate the pseudo palette */
Hans Verkuil3f983872008-05-01 10:31:12 -03001044 oi->ivtvfb_info.pseudo_palette =
1045 kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN);
Hans Verkuil32db7752007-07-20 09:29:43 -03001046
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001047 if (!oi->ivtvfb_info.pseudo_palette) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001048 IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001049 return -ENOMEM;
1050 }
1051
1052 return 0;
1053}
1054
1055/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
1056
1057static int ivtvfb_init_io(struct ivtv *itv)
1058{
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001059 struct osd_info *oi = itv->osd_info;
1060
Hans Verkuil26e9d592007-08-25 05:41:52 -03001061 mutex_lock(&itv->serialize_lock);
Hans Verkuil6e5eb592007-07-25 12:55:52 -03001062 if (ivtv_init_on_first_open(itv)) {
Hans Verkuil26e9d592007-08-25 05:41:52 -03001063 mutex_unlock(&itv->serialize_lock);
Hans Verkuil641ed492007-08-28 03:24:31 -03001064 IVTVFB_ERR("Failed to initialize ivtv\n");
Hans Verkuil6e5eb592007-07-25 12:55:52 -03001065 return -ENXIO;
1066 }
Hans Verkuil26e9d592007-08-25 05:41:52 -03001067 mutex_unlock(&itv->serialize_lock);
Hans Verkuil6e5eb592007-07-25 12:55:52 -03001068
Hans Verkuil641ed492007-08-28 03:24:31 -03001069 ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
Hans Verkuil32db7752007-07-20 09:29:43 -03001070
1071 /* The osd buffer size depends on the number of video buffers allocated
1072 on the PVR350 itself. For now we'll hardcode the smallest osd buffer
1073 size to prevent any overlap. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001074 oi->video_buffer_size = 1704960;
Hans Verkuil32db7752007-07-20 09:29:43 -03001075
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001076 oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1077 oi->video_vbase = itv->dec_mem + oi->video_rbase;
Hans Verkuil32db7752007-07-20 09:29:43 -03001078
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001079 if (!oi->video_vbase) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001080 IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001081 oi->video_buffer_size, oi->video_pbase);
Hans Verkuil32db7752007-07-20 09:29:43 -03001082 return -EIO;
1083 }
1084
Hans Verkuil641ed492007-08-28 03:24:31 -03001085 IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001086 oi->video_pbase, oi->video_vbase,
1087 oi->video_buffer_size / 1024);
Hans Verkuil32db7752007-07-20 09:29:43 -03001088
1089#ifdef CONFIG_MTRR
1090 {
1091 /* Find the largest power of two that maps the whole buffer */
1092 int size_shift = 31;
1093
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001094 while (!(oi->video_buffer_size & (1 << size_shift))) {
Hans Verkuil32db7752007-07-20 09:29:43 -03001095 size_shift--;
1096 }
1097 size_shift++;
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001098 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1099 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1100 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1101 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1102 if (mtrr_add(oi->fb_start_aligned_physaddr,
1103 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
Hans Verkuil32db7752007-07-20 09:29:43 -03001104 MTRR_TYPE_WRCOMB, 1) < 0) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001105 IVTVFB_INFO("disabled mttr\n");
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001106 oi->fb_start_aligned_physaddr = 0;
1107 oi->fb_end_aligned_physaddr = 0;
Hans Verkuil32db7752007-07-20 09:29:43 -03001108 }
1109 }
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001110#endif
Hans Verkuil32db7752007-07-20 09:29:43 -03001111
1112 /* Blank the entire osd. */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001113 memset_io(oi->video_vbase, 0, oi->video_buffer_size);
Hans Verkuil32db7752007-07-20 09:29:43 -03001114
1115 return 0;
1116}
1117
1118/* Release any memory we've grabbed & remove mtrr entry */
1119static void ivtvfb_release_buffers (struct ivtv *itv)
1120{
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001121 struct osd_info *oi = itv->osd_info;
1122
Hans Verkuil32db7752007-07-20 09:29:43 -03001123 /* Release cmap */
Adrian Bunk13628032007-08-28 03:28:04 -03001124 if (oi->ivtvfb_info.cmap.len)
1125 fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
Hans Verkuil32db7752007-07-20 09:29:43 -03001126
1127 /* Release pseudo palette */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001128 if (oi->ivtvfb_info.pseudo_palette)
1129 kfree(oi->ivtvfb_info.pseudo_palette);
Hans Verkuil32db7752007-07-20 09:29:43 -03001130
1131#ifdef CONFIG_MTRR
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001132 if (oi->fb_end_aligned_physaddr) {
1133 mtrr_del(-1, oi->fb_start_aligned_physaddr,
1134 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1135 }
1136#endif
Hans Verkuil32db7752007-07-20 09:29:43 -03001137
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001138 kfree(oi);
Hans Verkuil32db7752007-07-20 09:29:43 -03001139 itv->osd_info = NULL;
1140}
1141
1142/* Initialize the specified card */
1143
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001144static int ivtvfb_init_card(struct ivtv *itv)
Hans Verkuil32db7752007-07-20 09:29:43 -03001145{
1146 int rc;
1147
1148 if (itv->osd_info) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001149 IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
Hans Verkuil32db7752007-07-20 09:29:43 -03001150 return -EBUSY;
1151 }
1152
Hans Verkuil3f983872008-05-01 10:31:12 -03001153 itv->osd_info = kzalloc(sizeof(struct osd_info),
1154 GFP_ATOMIC|__GFP_NOWARN);
Richard Knutsson14d5deb2007-12-08 10:35:06 -03001155 if (itv->osd_info == NULL) {
Hans Verkuil641ed492007-08-28 03:24:31 -03001156 IVTVFB_ERR("Failed to allocate memory for osd_info\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001157 return -ENOMEM;
1158 }
1159
1160 /* Find & setup the OSD buffer */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001161 if ((rc = ivtvfb_init_io(itv)))
Hans Verkuil32db7752007-07-20 09:29:43 -03001162 return rc;
1163
1164 /* Set the startup video mode information */
Hans Verkuilbe383bd2007-07-20 10:16:03 -03001165 if ((rc = ivtvfb_init_vidmode(itv))) {
Hans Verkuil32db7752007-07-20 09:29:43 -03001166 ivtvfb_release_buffers(itv);
1167 return rc;
1168 }
1169
1170 /* Register the framebuffer */
1171 if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1172 ivtvfb_release_buffers(itv);
1173 return -EINVAL;
1174 }
1175
1176 itv->osd_video_pbase = itv->osd_info->video_pbase;
1177
1178 /* Set the card to the requested mode */
1179 ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1180
1181 /* Set color 0 to black */
1182 write_reg(0, 0x02a30);
1183 write_reg(0, 0x02a34);
1184
1185 /* Enable the osd */
1186 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1187
Hans Verkuil32db7752007-07-20 09:29:43 -03001188 /* Allocate DMA */
1189 ivtv_udma_alloc(itv);
1190 return 0;
1191
1192}
1193
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001194static int __init ivtvfb_callback_init(struct device *dev, void *p)
1195{
1196 struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
Hans Verkuil8ac05ae2009-02-07 07:02:27 -03001197 struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001198
1199 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1200 if (ivtvfb_init_card(itv) == 0) {
1201 IVTVFB_INFO("Framebuffer registered on %s\n",
Hans Verkuil8ac05ae2009-02-07 07:02:27 -03001202 itv->v4l2_dev.name);
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001203 (*(int *)p)++;
1204 }
1205 }
1206 return 0;
1207}
1208
1209static int ivtvfb_callback_cleanup(struct device *dev, void *p)
1210{
1211 struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
Hans Verkuil8ac05ae2009-02-07 07:02:27 -03001212 struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001213
1214 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1215 if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
1216 IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
1217 itv->instance);
1218 return 0;
1219 }
1220 IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
1221 ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
1222 ivtvfb_release_buffers(itv);
1223 itv->osd_video_pbase = 0;
1224 }
1225 return 0;
1226}
1227
Hans Verkuil32db7752007-07-20 09:29:43 -03001228static int __init ivtvfb_init(void)
1229{
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001230 struct device_driver *drv;
1231 int registered = 0;
1232 int err;
Hans Verkuil32db7752007-07-20 09:29:43 -03001233
Hans Verkuil641ed492007-08-28 03:24:31 -03001234 if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
1235 printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
Hans Verkuil32db7752007-07-20 09:29:43 -03001236 IVTV_MAX_CARDS - 1);
1237 return -EINVAL;
1238 }
1239
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001240 drv = driver_find("ivtv", &pci_bus_type);
1241 err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
1242 put_driver(drv);
Hans Verkuil32db7752007-07-20 09:29:43 -03001243 if (!registered) {
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001244 printk(KERN_ERR "ivtvfb: no cards found\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001245 return -ENODEV;
1246 }
1247 return 0;
1248}
1249
1250static void ivtvfb_cleanup(void)
1251{
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001252 struct device_driver *drv;
1253 int err;
Hans Verkuil32db7752007-07-20 09:29:43 -03001254
Hans Verkuil7b3a0d42007-08-26 06:11:07 -03001255 printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n");
Hans Verkuil32db7752007-07-20 09:29:43 -03001256
Hans Verkuil67ec09f2008-11-29 19:38:23 -03001257 drv = driver_find("ivtv", &pci_bus_type);
1258 err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
1259 put_driver(drv);
Hans Verkuil32db7752007-07-20 09:29:43 -03001260}
1261
1262module_init(ivtvfb_init);
1263module_exit(ivtvfb_cleanup);