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