V4L/DVB (5905): ivtv-fb: Use proper ioctl value
[deliverable/linux.git] / drivers / media / video / ivtv / ivtv-fb.c
CommitLineData
32db7754
HV
1/*
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
be383bd3 6 support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
32db7754
HV
7 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>
43#include <linux/string.h>
44#include <linux/mm.h>
45#include <linux/tty.h>
46#include <linux/fb.h>
47#include <linux/console.h>
48#include <linux/bitops.h>
49#include <linux/pagemap.h>
50#include <linux/matroxfb.h>
51
52#include <asm/io.h>
53#include <asm/ioctl.h>
54
55#ifdef CONFIG_MTRR
56#include <asm/mtrr.h>
57#endif
58
59#include "ivtv-driver.h"
60#include "ivtv-queue.h"
61#include "ivtv-udma.h"
62#include "ivtv-irq.h"
63#include "ivtv-fileops.h"
64#include "ivtv-mailbox.h"
65#include "ivtv-cards.h"
66#include <media/ivtv-fb.h>
67
68/* card parameters */
69static int ivtv_fb_card_id = -1;
70static int ivtv_fb_debug = 0;
71static int osd_laced;
72static int osd_compat;
73static int osd_depth;
74static int osd_upper;
75static int osd_left;
76static int osd_yres;
77static int osd_xres;
78
79module_param(ivtv_fb_card_id, int, 0444);
80module_param_named(debug,ivtv_fb_debug, int, 0644);
81module_param(osd_laced, bool, 0444);
82module_param(osd_compat, bool, 0444);
83module_param(osd_depth, int, 0444);
84module_param(osd_upper, int, 0444);
85module_param(osd_left, int, 0444);
86module_param(osd_yres, int, 0444);
87module_param(osd_xres, int, 0444);
88
89MODULE_PARM_DESC(ivtv_fb_card_id,
90 "Only use framebuffer of the specified ivtv card (0-31)\n"
91 "\t\t\tdefault -1: initialize all available framebuffers");
92
93MODULE_PARM_DESC(debug,
94 "Debug level (bitmask). Default: errors only\n"
95 "\t\t\t(debug = 3 gives full debugging)");
96
97MODULE_PARM_DESC(osd_compat,
98 "Compatibility mode - Display size is locked (use for old X drivers)\n"
99 "\t\t\t0=off\n"
100 "\t\t\t1=on\n"
101 "\t\t\tdefault off");
102
103/* Why upper, left, xres, yres, depth, laced ? To match terminology used
104 by fbset.
105 Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
106
107MODULE_PARM_DESC(osd_laced,
108 "Interlaced mode\n"
109 "\t\t\t0=off\n"
110 "\t\t\t1=on\n"
111 "\t\t\tdefault off");
112
113MODULE_PARM_DESC(osd_depth,
be383bd3 114 "Bits per pixel - 8, 16, 32\n"
32db7754
HV
115 "\t\t\tdefault 8");
116
117MODULE_PARM_DESC(osd_upper,
118 "Vertical start position\n"
119 "\t\t\tdefault 0 (Centered)");
120
121MODULE_PARM_DESC(osd_left,
122 "Horizontal start position\n"
123 "\t\t\tdefault 0 (Centered)");
124
125MODULE_PARM_DESC(osd_yres,
126 "Display height\n"
127 "\t\t\tdefault 480 (PAL)\n"
128 "\t\t\t 400 (NTSC)");
129
130MODULE_PARM_DESC(osd_xres,
131 "Display width\n"
132 "\t\t\tdefault 640");
133
134MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
135MODULE_LICENSE("GPL");
136
137/* --------------------------------------------------------------------- */
138
139#define IVTV_FB_DBGFLG_WARN (1 << 0)
140#define IVTV_FB_DBGFLG_INFO (1 << 1)
141
142#define IVTV_FB_DEBUG(x, type, fmt, args...) \
143 do { \
144 if ((x) & ivtv_fb_debug) \
145 printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \
146 } while (0)
147#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args)
148#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args)
149
150/* Standard kernel messages */
151#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args)
152#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args)
153#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args)
154
155/* --------------------------------------------------------------------- */
156
157#define IVTV_OSD_MAX_WIDTH 720
158#define IVTV_OSD_MAX_HEIGHT 576
159
160#define IVTV_OSD_BPP_8 0x00
161#define IVTV_OSD_BPP_16_444 0x03
162#define IVTV_OSD_BPP_16_555 0x02
163#define IVTV_OSD_BPP_16_565 0x01
164#define IVTV_OSD_BPP_32 0x04
165
166struct osd_info {
167 /* Timing info for modes */
168 u32 pixclock;
169 u32 hlimit;
170 u32 vlimit;
171
172 /* Physical base address */
173 unsigned long video_pbase;
174 /* Relative base address (relative to start of decoder memory) */
175 u32 video_rbase;
176 /* Mapped base address */
177 volatile char __iomem *video_vbase;
178 /* Buffer size */
179 u32 video_buffer_size;
180
181#ifdef CONFIG_MTRR
182 /* video_base rounded down as required by hardware MTRRs */
183 unsigned long fb_start_aligned_physaddr;
184 /* video_base rounded up as required by hardware MTRRs */
185 unsigned long fb_end_aligned_physaddr;
186#endif
187
188 /* Store the buffer offset */
189 int set_osd_coords_x;
190 int set_osd_coords_y;
191
192 /* Current dimensions (NOT VISIBLE SIZE!) */
193 int display_width;
194 int display_height;
195 int display_byte_stride;
196
197 /* Current bits per pixel */
198 int bits_per_pixel;
199 int bytes_per_pixel;
200
201 /* Frame buffer stuff */
202 struct fb_info ivtvfb_info;
203 struct fb_var_screeninfo ivtvfb_defined;
204 struct fb_fix_screeninfo ivtvfb_fix;
205};
206
207struct ivtv_osd_coords {
208 unsigned long offset;
209 unsigned long max_offset;
210 int pixel_stride;
211 int lines;
212 int x;
213 int y;
214};
215
216/* --------------------------------------------------------------------- */
217
218/* ivtv API calls for framebuffer related support */
219
220static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
221 u32 *fblength)
222{
223 u32 data[CX2341X_MBOX_MAX_DATA];
224 int rc;
225
226 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
227 *fbbase = data[0];
228 *fblength = data[1];
229 return rc;
230}
231
232static int ivtv_fb_get_osd_coords(struct ivtv *itv,
233 struct ivtv_osd_coords *osd)
234{
be383bd3 235 struct osd_info *oi = itv->osd_info;
32db7754
HV
236 u32 data[CX2341X_MBOX_MAX_DATA];
237
238 ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
239
be383bd3
HV
240 osd->offset = data[0] - oi->video_rbase;
241 osd->max_offset = oi->display_width * oi->display_height * 4;
32db7754
HV
242 osd->pixel_stride = data[1];
243 osd->lines = data[2];
244 osd->x = data[3];
245 osd->y = data[4];
246 return 0;
247}
248
249static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
250{
be383bd3
HV
251 struct osd_info *oi = itv->osd_info;
252
253 oi->display_width = osd->pixel_stride;
254 oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
255 oi->set_osd_coords_x += osd->x;
256 oi->set_osd_coords_y = osd->y;
32db7754
HV
257
258 return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
be383bd3 259 osd->offset + oi->video_rbase,
32db7754
HV
260 osd->pixel_stride,
261 osd->lines, osd->x, osd->y);
262}
263
264static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
265{
32db7754
HV
266 int osd_height_limit = itv->is_50hz ? 576 : 480;
267
268 /* Only fail if resolution too high, otherwise fudge the start coords. */
269 if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
270 return -EINVAL;
271
272 /* Ensure we don't exceed display limits */
273 if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
be383bd3 274 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
32db7754
HV
275 ivtv_window->top, ivtv_window->height);
276 ivtv_window->top = osd_height_limit - ivtv_window->height;
277 }
278
279 if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
be383bd3 280 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
32db7754
HV
281 ivtv_window->left, ivtv_window->width);
282 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
283 }
284
285 /* Set the OSD origin */
286 write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
287
288 /* How much to display */
289 write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
290
291 /* Pass this info back the yuv handler */
292 itv->yuv_info.osd_vis_w = ivtv_window->width;
293 itv->yuv_info.osd_vis_h = ivtv_window->height;
294 itv->yuv_info.osd_x_offset = ivtv_window->left;
295 itv->yuv_info.osd_y_offset = ivtv_window->top;
296
297 return 0;
298}
299
300static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv,
301 unsigned long ivtv_dest_addr, void __user *userbuf,
302 int size_in_bytes)
303{
304 DEFINE_WAIT(wait);
305 int ret = 0;
306 int got_sig = 0;
307
308 mutex_lock(&itv->udma.lock);
309 /* Map User DMA */
310 if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
311 mutex_unlock(&itv->udma.lock);
312 IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, "
313 "Error with get_user_pages: %d bytes, %d pages returned\n",
314 size_in_bytes, itv->udma.page_count);
315
316 /* get_user_pages must have failed completely */
317 return -EIO;
318 }
319
320 IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
321 size_in_bytes, itv->udma.page_count);
322
323 ivtv_udma_prepare(itv);
324 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
325 /* if no UDMA is pending and no UDMA is in progress, then the DMA
326 is finished */
327 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
328 /* don't interrupt if the DMA is in progress but break off
329 a still pending DMA. */
330 got_sig = signal_pending(current);
331 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
332 break;
333 got_sig = 0;
334 schedule();
335 }
336 finish_wait(&itv->dma_waitq, &wait);
337
338 /* Unmap Last DMA Xfer */
339 ivtv_udma_unmap(itv);
340 mutex_unlock(&itv->udma.lock);
341 if (got_sig) {
342 IVTV_DEBUG_INFO("User stopped OSD\n");
343 return -EINTR;
344 }
345
346 return ret;
347}
348
be383bd3
HV
349static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
350 unsigned long dest_offset, int count)
32db7754
HV
351{
352 DEFINE_WAIT(wait);
353
354 /* Nothing to do */
355 if (count == 0) {
356 IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n");
357 return -EINVAL;
358 }
359
360 /* Check Total FB Size */
361 if ((dest_offset + count) > itv->osd_info->video_buffer_size) {
be383bd3
HV
362 IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
363 dest_offset + count, itv->osd_info->video_buffer_size);
32db7754
HV
364 return -E2BIG;
365 }
366
367 /* Not fatal, but will have undesirable results */
368 if ((unsigned long)source & 3)
be383bd3
HV
369 IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
370 (unsigned long)source);
32db7754
HV
371
372 if (dest_offset & 3)
be383bd3 373 IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
32db7754
HV
374
375 if (count & 3)
be383bd3 376 IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count);
32db7754
HV
377
378 /* Check Source */
379 if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
be383bd3 380 IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n",
32db7754
HV
381 (unsigned long)source);
382
be383bd3 383 IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
32db7754
HV
384 dest_offset, (unsigned long)source,
385 count);
386 return -EINVAL;
387 }
388
389 /* OSD Address to send DMA to */
390 dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase;
391
392 /* Fill Buffers */
393 return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count);
394}
395
396static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
397{
398 DEFINE_WAIT(wait);
399 struct ivtv *itv = (struct ivtv *)info->par;
be383bd3 400 int rc = 0;
32db7754
HV
401
402 switch (cmd) {
32db7754
HV
403 case FBIOGET_VBLANK: {
404 struct fb_vblank vblank;
405 u32 trace;
406
407 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
408 FB_VBLANK_HAVE_VSYNC;
be383bd3 409 trace = read_reg(0x028c0) >> 16;
32db7754
HV
410 if (itv->is_50hz && trace > 312) trace -= 312;
411 else if (itv->is_60hz && trace > 262) trace -= 262;
412 if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
413 vblank.count = itv->lastVsyncFrame;
414 vblank.vcount = trace;
415 vblank.hcount = 0;
416 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
417 return -EFAULT;
418 return 0;
419 }
420
be383bd3 421 case FBIO_WAITFORVSYNC:
32db7754
HV
422 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
423 if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT;
be383bd3 424 finish_wait(&itv->vsync_waitq, &wait);
32db7754 425 return rc;
32db7754 426
d715e766
HV
427 case IVTVFB_IOC_DMA_FRAME: {
428 struct ivtvfb_dma_frame args;
32db7754 429
d715e766 430 IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
32db7754
HV
431 if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
432 return -EFAULT;
433
434 return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
435 }
436
437 default:
be383bd3 438 IVTV_FB_ERR("Unknown IOCTL %d\n", cmd);
32db7754
HV
439 return -EINVAL;
440 }
441 return 0;
442}
443
444/* Framebuffer device handling */
445
446static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
447{
32db7754
HV
448 struct ivtv_osd_coords ivtv_osd;
449 struct v4l2_rect ivtv_window;
450
451 IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n");
452
453 /* Select color space */
454 if (var->nonstd) /* YUV */
be383bd3 455 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
32db7754 456 else /* RGB */
be383bd3 457 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
32db7754
HV
458
459 /* Set the color mode
460 Although rare, occasionally things go wrong. The extra mode
461 change seems to help... */
462
463 switch (var->bits_per_pixel) {
464 case 8:
465 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
466 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8);
467 break;
468 case 32:
469 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
470 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32);
471 break;
472 case 16:
473 switch (var->green.length) {
474 case 4:
475 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
476 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444);
477 break;
478 case 5:
479 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
480 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555);
481 break;
482 case 6:
483 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
484 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565);
485 break;
486 default:
487 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
488 }
489 break;
490 default:
491 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
492 }
493
494 itv->osd_info->bits_per_pixel = var->bits_per_pixel;
495 itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8;
496
497 /* Set the flicker filter */
498 switch (var->vmode & FB_VMODE_MASK) {
499 case FB_VMODE_NONINTERLACED: /* Filter on */
500 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
501 break;
502 case FB_VMODE_INTERLACED: /* Filter off */
503 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
504 break;
505 default:
506 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
507 }
508
509 /* Read the current osd info */
510 ivtv_fb_get_osd_coords(itv, &ivtv_osd);
511
512 /* Now set the OSD to the size we want */
513 ivtv_osd.pixel_stride = var->xres_virtual;
514 ivtv_osd.lines = var->yres_virtual;
515 ivtv_osd.x = 0;
516 ivtv_osd.y = 0;
517 ivtv_fb_set_osd_coords(itv, &ivtv_osd);
518
519 /* Can't seem to find the right API combo for this.
520 Use another function which does what we need through direct register access. */
521 ivtv_window.width = var->xres;
522 ivtv_window.height = var->yres;
523
524 /* Minimum margin cannot be 0, as X won't allow such a mode */
be383bd3
HV
525 if (!var->upper_margin) var->upper_margin++;
526 if (!var->left_margin) var->left_margin++;
32db7754
HV
527 ivtv_window.top = var->upper_margin - 1;
528 ivtv_window.left = var->left_margin - 1;
529
530 ivtv_fb_set_display_window(itv, &ivtv_window);
531
532 /* Force update of yuv registers */
533 itv->yuv_info.yuv_forced_update = 1;
534
be383bd3
HV
535 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
536 var->xres, var->yres,
537 var->xres_virtual, var->yres_virtual,
538 var->bits_per_pixel);
32db7754 539
be383bd3
HV
540 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
541 var->left_margin, var->upper_margin);
32db7754 542
be383bd3
HV
543 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
544 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
545 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
32db7754
HV
546
547 return 0;
548}
549
550static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
551{
be383bd3
HV
552 struct osd_info *oi = itv->osd_info;
553
554 IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n");
32db7754
HV
555 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
556 strcpy(fix->id, "cx23415 TV out");
be383bd3
HV
557 fix->smem_start = oi->video_pbase;
558 fix->smem_len = oi->video_buffer_size;
32db7754 559 fix->type = FB_TYPE_PACKED_PIXELS;
be383bd3 560 fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
32db7754
HV
561 fix->xpanstep = 1;
562 fix->ypanstep = 1;
563 fix->ywrapstep = 0;
be383bd3 564 fix->line_length = oi->display_byte_stride;
32db7754
HV
565 fix->accel = FB_ACCEL_NONE;
566 return 0;
567}
568
569/* Check the requested display mode, returning -EINVAL if we can't
570 handle it. */
571
572static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
573{
be383bd3 574 struct osd_info *oi = itv->osd_info;
32db7754
HV
575 int osd_height_limit = itv->is_50hz ? 576 : 480;
576
be383bd3 577 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
32db7754
HV
578
579 /* Check the bits per pixel */
580 if (osd_compat) {
581 if (var->bits_per_pixel != 32) {
be383bd3 582 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
32db7754
HV
583 return -EINVAL;
584 }
585 }
586
587 if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
588 var->transp.offset = 24;
589 var->transp.length = 8;
590 var->red.offset = 16;
591 var->red.length = 8;
592 var->green.offset = 8;
593 var->green.length = 8;
594 var->blue.offset = 0;
595 var->blue.length = 8;
596 }
597 else if (var->bits_per_pixel == 16) {
be383bd3
HV
598 var->transp.offset = 0;
599 var->transp.length = 0;
600
32db7754
HV
601 /* To find out the true mode, check green length */
602 switch (var->green.length) {
603 case 4:
32db7754
HV
604 var->red.offset = 8;
605 var->red.length = 4;
606 var->green.offset = 4;
607 var->green.length = 4;
608 var->blue.offset = 0;
609 var->blue.length = 4;
610 break;
611 case 5:
32db7754
HV
612 var->red.offset = 10;
613 var->red.length = 5;
614 var->green.offset = 5;
615 var->green.length = 5;
616 var->blue.offset = 0;
617 var->blue.length = 5;
618 break;
619 default:
32db7754
HV
620 var->red.offset = 11;
621 var->red.length = 5;
622 var->green.offset = 5;
623 var->green.length = 6;
624 var->blue.offset = 0;
625 var->blue.length = 5;
626 break;
627 }
628 }
629 else {
be383bd3 630 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
32db7754
HV
631 return -EINVAL;
632 }
633
634 /* Check the resolution */
635 if (osd_compat) {
be383bd3
HV
636 if (var->xres != oi->ivtvfb_defined.xres ||
637 var->yres != oi->ivtvfb_defined.yres ||
638 var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
639 var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
640 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
641 var->xres, var->yres, var->xres_virtual, var->yres_virtual);
32db7754
HV
642 return -EINVAL;
643 }
644 }
645 else {
be383bd3
HV
646 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
647 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n",
648 var->xres, var->yres);
32db7754
HV
649 return -EINVAL;
650 }
651
652 /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
653 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
be383bd3 654 var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
32db7754
HV
655 var->xres_virtual < var->xres ||
656 var->yres_virtual < var->yres) {
be383bd3 657 IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
32db7754
HV
658 var->xres_virtual, var->yres_virtual);
659 return -EINVAL;
660 }
661 }
662
663 /* Some extra checks if in 8 bit mode */
664 if (var->bits_per_pixel == 8) {
665 /* Width must be a multiple of 4 */
666 if (var->xres & 3) {
be383bd3 667 IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
32db7754
HV
668 return -EINVAL;
669 }
670 if (var->xres_virtual & 3) {
be383bd3 671 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
32db7754
HV
672 return -EINVAL;
673 }
674 }
675 else if (var->bits_per_pixel == 16) {
676 /* Width must be a multiple of 2 */
677 if (var->xres & 1) {
be383bd3 678 IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
32db7754
HV
679 return -EINVAL;
680 }
681 if (var->xres_virtual & 1) {
be383bd3 682 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
32db7754
HV
683 return -EINVAL;
684 }
685 }
686
687 /* Now check the offsets */
688 if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
be383bd3
HV
689 IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
690 var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
32db7754
HV
691 return -EINVAL;
692 }
693
694 /* Check pixel format */
695 if (var->nonstd > 1) {
be383bd3 696 IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
32db7754
HV
697 return -EINVAL;
698 }
699
700 /* Check video mode */
701 if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
702 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
be383bd3 703 IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
32db7754
HV
704 return -EINVAL;
705 }
706
707 /* Check the left & upper margins
708 If the margins are too large, just center the screen
709 (enforcing margins causes too many problems) */
710
711 if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
712 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
713 }
714 if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
715 var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
716 }
717
718 /* Maintain overall 'size' for a constant refresh rate */
be383bd3
HV
719 var->right_margin = oi->hlimit - var->left_margin - var->xres;
720 var->lower_margin = oi->vlimit - var->upper_margin - var->yres;
32db7754
HV
721
722 /* Fixed sync times */
723 var->hsync_len = 24;
724 var->vsync_len = 2;
725
726 /* Non-interlaced / interlaced mode is used to switch the OSD filter
727 on or off. Adjust the clock timings to maintain a constant
728 vertical refresh rate. */
be383bd3 729 var->pixclock = oi->pixclock;
32db7754
HV
730 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
731 var->pixclock /= 2;
732
be383bd3
HV
733 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
734 var->xres, var->yres,
735 var->xres_virtual, var->yres_virtual,
32db7754
HV
736 var->bits_per_pixel);
737
be383bd3
HV
738 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
739 var->left_margin, var->upper_margin);
32db7754 740
be383bd3
HV
741 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
742 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
743 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
32db7754
HV
744 return 0;
745}
746
747static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
748{
749 struct ivtv *itv = (struct ivtv *) info->par;
be383bd3
HV
750 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
751 return _ivtvfb_check_var(var, itv);
32db7754
HV
752}
753
754static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
755{
756 u32 osd_pan_index;
757 struct ivtv *itv = (struct ivtv *) info->par;
758
759 osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
be383bd3 760 write_reg(osd_pan_index, 0x02A0C);
32db7754
HV
761
762 /* Pass this info back the yuv handler */
763 itv->yuv_info.osd_x_pan = var->xoffset;
764 itv->yuv_info.osd_y_pan = var->yoffset;
765 /* Force update of yuv registers */
766 itv->yuv_info.yuv_forced_update = 1;
767 return 0;
768}
769
770static int ivtvfb_set_par(struct fb_info *info)
771{
772 int rc = 0;
773 struct ivtv *itv = (struct ivtv *) info->par;
774
be383bd3 775 IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n");
32db7754
HV
776
777 rc = ivtvfb_set_var(itv, &info->var);
778 ivtvfb_pan_display(&info->var, info);
be383bd3 779 ivtvfb_get_fix(itv, &info->fix);
32db7754
HV
780 return rc;
781}
782
783static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
784 unsigned blue, unsigned transp,
785 struct fb_info *info)
786{
787 u32 color, *palette;
be383bd3 788 struct ivtv *itv = (struct ivtv *)info->par;
32db7754
HV
789
790 if (regno >= info->cmap.len)
791 return -EINVAL;
792
793 color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
794 if (info->var.bits_per_pixel <= 8) {
795 write_reg(regno, 0x02a30);
796 write_reg(color, 0x02a34);
be383bd3 797 return 0;
32db7754 798 }
be383bd3
HV
799 if (regno >= 16)
800 return -EINVAL;
32db7754 801
be383bd3
HV
802 palette = info->pseudo_palette;
803 if (info->var.bits_per_pixel == 16) {
804 switch (info->var.green.length) {
805 case 4:
806 color = ((red & 0xf000) >> 4) |
807 ((green & 0xf000) >> 8) |
808 ((blue & 0xf000) >> 12);
809 break;
810 case 5:
811 color = ((red & 0xf800) >> 1) |
812 ((green & 0xf800) >> 6) |
813 ((blue & 0xf800) >> 11);
814 break;
815 case 6:
816 color = (red & 0xf800 ) |
817 ((green & 0xfc00) >> 5) |
818 ((blue & 0xf800) >> 11);
819 break;
32db7754 820 }
32db7754 821 }
be383bd3 822 palette[regno] = color;
32db7754
HV
823 return 0;
824}
825
826/* We don't really support blanking. All this does is enable or
827 disable the OSD. */
828static int ivtvfb_blank(int blank_mode, struct fb_info *info)
829{
830 struct ivtv *itv = (struct ivtv *)info->par;
831
be383bd3 832 IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
32db7754
HV
833 switch (blank_mode) {
834 case FB_BLANK_UNBLANK:
835 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
836 break;
837 case FB_BLANK_NORMAL:
838 case FB_BLANK_HSYNC_SUSPEND:
839 case FB_BLANK_VSYNC_SUSPEND:
840 case FB_BLANK_POWERDOWN:
841 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
842 break;
843 }
844 return 0;
845}
846
847static struct fb_ops ivtvfb_ops = {
848 .owner = THIS_MODULE,
849 .fb_check_var = ivtvfb_check_var,
850 .fb_set_par = ivtvfb_set_par,
851 .fb_setcolreg = ivtvfb_setcolreg,
852 .fb_fillrect = cfb_fillrect,
853 .fb_copyarea = cfb_copyarea,
854 .fb_imageblit = cfb_imageblit,
855 .fb_cursor = NULL,
856 .fb_ioctl = ivtvfb_ioctl,
857 .fb_pan_display = ivtvfb_pan_display,
858 .fb_blank = ivtvfb_blank,
859};
860
861/* Initialization */
862
863
864/* Setup our initial video mode */
865static int ivtvfb_init_vidmode(struct ivtv *itv)
866{
be383bd3 867 struct osd_info *oi = itv->osd_info;
32db7754 868 struct v4l2_rect start_window;
be383bd3 869 int max_height;
32db7754
HV
870
871 /* Set base references for mode calcs. */
872 if (itv->is_50hz) {
be383bd3
HV
873 oi->pixclock = 84316;
874 oi->hlimit = 776;
875 oi->vlimit = 591;
32db7754
HV
876 }
877 else {
be383bd3
HV
878 oi->pixclock = 83926;
879 oi->hlimit = 776;
880 oi->vlimit = 495;
32db7754
HV
881 }
882
883 /* Color mode */
884
885 if (osd_compat) osd_depth = 32;
886 if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
be383bd3
HV
887 oi->bits_per_pixel = osd_depth;
888 oi->bytes_per_pixel = oi->bits_per_pixel / 8;
32db7754
HV
889
890 /* Horizontal size & position */
891
892 if (osd_xres > 720) osd_xres = 720;
893
894 /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
895 if (osd_depth == 8)
896 osd_xres &= ~3;
897 else if (osd_depth == 16)
898 osd_xres &= ~1;
899
900 if (osd_xres)
901 start_window.width = osd_xres;
902 else
903 start_window.width = osd_compat ? 720: 640;
904
905 /* Check horizontal start (osd_left). */
906 if (osd_left && osd_left + start_window.width > 721) {
be383bd3 907 IVTV_FB_ERR("Invalid osd_left - assuming default\n");
32db7754
HV
908 osd_left = 0;
909 }
910
911 /* Hardware coords start at 0, user coords start at 1. */
be383bd3 912 osd_left--;
32db7754 913
be383bd3 914 start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
32db7754 915
be383bd3
HV
916 oi->display_byte_stride =
917 start_window.width * oi->bytes_per_pixel;
32db7754
HV
918
919 /* Vertical size & position */
920
921 max_height = itv->is_50hz ? 576 : 480;
922
be383bd3
HV
923 if (osd_yres > max_height)
924 osd_yres = max_height;
32db7754
HV
925
926 if (osd_yres)
927 start_window.height = osd_yres;
be383bd3
HV
928 else
929 start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
32db7754
HV
930
931 /* Check vertical start (osd_upper). */
932 if (osd_upper + start_window.height > max_height + 1) {
be383bd3 933 IVTV_FB_ERR("Invalid osd_upper - assuming default\n");
32db7754
HV
934 osd_upper = 0;
935 }
936
937 /* Hardware coords start at 0, user coords start at 1. */
be383bd3 938 osd_upper--;
32db7754
HV
939
940 start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
941
be383bd3
HV
942 oi->display_width = start_window.width;
943 oi->display_height = start_window.height;
32db7754
HV
944
945 /* Generate a valid fb_var_screeninfo */
946
be383bd3
HV
947 oi->ivtvfb_defined.xres = oi->display_width;
948 oi->ivtvfb_defined.yres = oi->display_height;
949 oi->ivtvfb_defined.xres_virtual = oi->display_width;
950 oi->ivtvfb_defined.yres_virtual = oi->display_height;
951 oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
952 oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
953 oi->ivtvfb_defined.left_margin = start_window.left + 1;
954 oi->ivtvfb_defined.upper_margin = start_window.top + 1;
955 oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
956 oi->ivtvfb_defined.nonstd = 0;
32db7754
HV
957
958 /* We've filled in the most data, let the usual mode check
959 routine fill in the rest. */
be383bd3 960 _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
32db7754
HV
961
962 /* Generate valid fb_fix_screeninfo */
963
be383bd3 964 ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
32db7754
HV
965
966 /* Generate valid fb_info */
967
be383bd3
HV
968 oi->ivtvfb_info.node = -1;
969 oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
970 oi->ivtvfb_info.fbops = &ivtvfb_ops;
971 oi->ivtvfb_info.par = itv;
972 oi->ivtvfb_info.var = oi->ivtvfb_defined;
973 oi->ivtvfb_info.fix = oi->ivtvfb_fix;
974 oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
975 oi->ivtvfb_info.fbops = &ivtvfb_ops;
32db7754
HV
976
977 /* Supply some monitor specs. Bogus values will do for now */
be383bd3
HV
978 oi->ivtvfb_info.monspecs.hfmin = 8000;
979 oi->ivtvfb_info.monspecs.hfmax = 70000;
980 oi->ivtvfb_info.monspecs.vfmin = 10;
981 oi->ivtvfb_info.monspecs.vfmax = 100;
32db7754
HV
982
983 /* Allocate color map */
be383bd3
HV
984 if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
985 IVTV_FB_ERR("abort, unable to alloc cmap\n");
32db7754
HV
986 return -ENOMEM;
987 }
988
989 /* Allocate the pseudo palette */
be383bd3 990 oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
32db7754 991
be383bd3
HV
992 if (!oi->ivtvfb_info.pseudo_palette) {
993 IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n");
32db7754
HV
994 return -ENOMEM;
995 }
996
997 return 0;
998}
999
1000/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
1001
1002static int ivtvfb_init_io(struct ivtv *itv)
1003{
be383bd3
HV
1004 struct osd_info *oi = itv->osd_info;
1005
1006 ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
32db7754
HV
1007
1008 /* The osd buffer size depends on the number of video buffers allocated
1009 on the PVR350 itself. For now we'll hardcode the smallest osd buffer
1010 size to prevent any overlap. */
be383bd3 1011 oi->video_buffer_size = 1704960;
32db7754 1012
be383bd3
HV
1013 oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1014 oi->video_vbase = itv->dec_mem + oi->video_rbase;
32db7754 1015
be383bd3 1016 if (!oi->video_vbase) {
32db7754 1017 IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
be383bd3 1018 oi->video_buffer_size, oi->video_pbase);
32db7754
HV
1019 return -EIO;
1020 }
1021
1022 IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
be383bd3
HV
1023 oi->video_pbase, oi->video_vbase,
1024 oi->video_buffer_size / 1024);
32db7754
HV
1025
1026#ifdef CONFIG_MTRR
1027 {
1028 /* Find the largest power of two that maps the whole buffer */
1029 int size_shift = 31;
1030
be383bd3 1031 while (!(oi->video_buffer_size & (1 << size_shift))) {
32db7754
HV
1032 size_shift--;
1033 }
1034 size_shift++;
be383bd3
HV
1035 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1036 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1037 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1038 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1039 if (mtrr_add(oi->fb_start_aligned_physaddr,
1040 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
32db7754 1041 MTRR_TYPE_WRCOMB, 1) < 0) {
be383bd3
HV
1042 IVTV_FB_WARN("cannot use mttr\n");
1043 oi->fb_start_aligned_physaddr = 0;
1044 oi->fb_end_aligned_physaddr = 0;
32db7754
HV
1045 }
1046 }
be383bd3 1047#endif
32db7754
HV
1048
1049 /* Blank the entire osd. */
be383bd3 1050 memset_io(oi->video_vbase, 0, oi->video_buffer_size);
32db7754
HV
1051
1052 return 0;
1053}
1054
1055/* Release any memory we've grabbed & remove mtrr entry */
1056static void ivtvfb_release_buffers (struct ivtv *itv)
1057{
be383bd3
HV
1058 struct osd_info *oi = itv->osd_info;
1059
32db7754 1060 /* Release cmap */
be383bd3
HV
1061 if (oi->ivtvfb_info.cmap.len);
1062 fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
32db7754
HV
1063
1064 /* Release pseudo palette */
be383bd3
HV
1065 if (oi->ivtvfb_info.pseudo_palette)
1066 kfree(oi->ivtvfb_info.pseudo_palette);
32db7754
HV
1067
1068#ifdef CONFIG_MTRR
be383bd3
HV
1069 if (oi->fb_end_aligned_physaddr) {
1070 mtrr_del(-1, oi->fb_start_aligned_physaddr,
1071 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1072 }
1073#endif
32db7754 1074
be383bd3 1075 kfree(oi);
32db7754
HV
1076 itv->osd_info = NULL;
1077}
1078
1079/* Initialize the specified card */
1080
be383bd3 1081static int ivtvfb_init_card(struct ivtv *itv)
32db7754
HV
1082{
1083 int rc;
1084
1085 if (itv->osd_info) {
1086 IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id);
1087 return -EBUSY;
1088 }
1089
1090 itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
1091 if (itv->osd_info == 0) {
1092 IVTV_FB_ERR("Failed to allocate memory for osd_info\n");
1093 return -ENOMEM;
1094 }
1095
1096 /* Find & setup the OSD buffer */
be383bd3 1097 if ((rc = ivtvfb_init_io(itv)))
32db7754
HV
1098 return rc;
1099
1100 /* Set the startup video mode information */
be383bd3 1101 if ((rc = ivtvfb_init_vidmode(itv))) {
32db7754
HV
1102 ivtvfb_release_buffers(itv);
1103 return rc;
1104 }
1105
1106 /* Register the framebuffer */
1107 if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1108 ivtvfb_release_buffers(itv);
1109 return -EINVAL;
1110 }
1111
1112 itv->osd_video_pbase = itv->osd_info->video_pbase;
1113
1114 /* Set the card to the requested mode */
1115 ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1116
1117 /* Set color 0 to black */
1118 write_reg(0, 0x02a30);
1119 write_reg(0, 0x02a34);
1120
1121 /* Enable the osd */
1122 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1123
1124 /* Note if we're running in compatibility mode */
1125 if (osd_compat)
1126 IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
1127
1128 /* Allocate DMA */
1129 ivtv_udma_alloc(itv);
1130 return 0;
1131
1132}
1133
1134static int __init ivtvfb_init(void)
1135{
1136 struct ivtv *itv;
1137 int i, registered = 0;
1138
1139 if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) {
1140 printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n",
1141 IVTV_MAX_CARDS - 1);
1142 return -EINVAL;
1143 }
1144
1145 /* Locate & initialise all cards supporting an OSD. */
1146 for (i = 0; i < ivtv_cards_active; i++) {
1147 if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id)
1148 continue;
1149 itv = ivtv_cards[i];
1150 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1151 if (ivtvfb_init_card(itv) == 0) {
1152 IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i);
1153 registered++;
1154 }
1155 }
1156 }
1157 if (!registered) {
1158 printk(KERN_ERR "ivtv-fb: no cards found");
1159 return -ENODEV;
1160 }
1161 return 0;
1162}
1163
1164static void ivtvfb_cleanup(void)
1165{
1166 struct ivtv *itv;
1167 int i;
1168
1169 printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n");
1170
1171 for (i = 0; i < ivtv_cards_active; i++) {
1172 itv = ivtv_cards[i];
1173 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
1174 IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i);
1175 ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
1176 unregister_framebuffer(&itv->osd_info->ivtvfb_info);
1177 ivtvfb_release_buffers(itv);
1178 itv->osd_video_pbase = 0;
1179 }
1180 }
1181}
1182
1183module_init(ivtvfb_init);
1184module_exit(ivtvfb_cleanup);
This page took 0.075882 seconds and 5 git commands to generate.