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