]> err.no Git - linux-2.6/blob - drivers/media/video/ivtv/ivtv-fb.c
V4L/DVB (5910): ivtv-fb: improve debug message
[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         /* Current osd mode */
189         int osd_mode;
190
191         /* Store the buffer offset */
192         int set_osd_coords_x;
193         int set_osd_coords_y;
194
195         /* Current dimensions (NOT VISIBLE SIZE!) */
196         int display_width;
197         int display_height;
198         int display_byte_stride;
199
200         /* Current bits per pixel */
201         int bits_per_pixel;
202         int bytes_per_pixel;
203
204         /* Frame buffer stuff */
205         struct fb_info ivtvfb_info;
206         struct fb_var_screeninfo ivtvfb_defined;
207         struct fb_fix_screeninfo ivtvfb_fix;
208 };
209
210 struct ivtv_osd_coords {
211         unsigned long offset;
212         unsigned long max_offset;
213         int pixel_stride;
214         int lines;
215         int x;
216         int y;
217 };
218
219 /* --------------------------------------------------------------------- */
220
221 /* ivtv API calls for framebuffer related support */
222
223 static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
224                                        u32 *fblength)
225 {
226         u32 data[CX2341X_MBOX_MAX_DATA];
227         int rc;
228
229         rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
230         *fbbase = data[0];
231         *fblength = data[1];
232         return rc;
233 }
234
235 static int ivtv_fb_get_osd_coords(struct ivtv *itv,
236                                       struct ivtv_osd_coords *osd)
237 {
238         struct osd_info *oi = itv->osd_info;
239         u32 data[CX2341X_MBOX_MAX_DATA];
240
241         ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
242
243         osd->offset = data[0] - oi->video_rbase;
244         osd->max_offset = oi->display_width * oi->display_height * 4;
245         osd->pixel_stride = data[1];
246         osd->lines = data[2];
247         osd->x = data[3];
248         osd->y = data[4];
249         return 0;
250 }
251
252 static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
253 {
254         struct osd_info *oi = itv->osd_info;
255
256         oi->display_width = osd->pixel_stride;
257         oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
258         oi->set_osd_coords_x += osd->x;
259         oi->set_osd_coords_y = osd->y;
260
261         return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
262                         osd->offset + oi->video_rbase,
263                         osd->pixel_stride,
264                         osd->lines, osd->x, osd->y);
265 }
266
267 static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
268 {
269         int osd_height_limit = itv->is_50hz ? 576 : 480;
270
271         /* Only fail if resolution too high, otherwise fudge the start coords. */
272         if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
273                 return -EINVAL;
274
275         /* Ensure we don't exceed display limits */
276         if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
277                 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
278                         ivtv_window->top, ivtv_window->height);
279                 ivtv_window->top = osd_height_limit - ivtv_window->height;
280         }
281
282         if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
283                 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
284                         ivtv_window->left, ivtv_window->width);
285                 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
286         }
287
288         /* Set the OSD origin */
289         write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
290
291         /* How much to display */
292         write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
293
294         /* Pass this info back the yuv handler */
295         itv->yuv_info.osd_vis_w = ivtv_window->width;
296         itv->yuv_info.osd_vis_h = ivtv_window->height;
297         itv->yuv_info.osd_x_offset = ivtv_window->left;
298         itv->yuv_info.osd_y_offset = ivtv_window->top;
299
300         return 0;
301 }
302
303 static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv,
304                                   unsigned long ivtv_dest_addr, void __user *userbuf,
305                                   int size_in_bytes)
306 {
307         DEFINE_WAIT(wait);
308         int ret = 0;
309         int got_sig = 0;
310
311         mutex_lock(&itv->udma.lock);
312         /* Map User DMA */
313         if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
314                 mutex_unlock(&itv->udma.lock);
315                 IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, "
316                                "Error with get_user_pages: %d bytes, %d pages returned\n",
317                                size_in_bytes, itv->udma.page_count);
318
319                 /* get_user_pages must have failed completely */
320                 return -EIO;
321         }
322
323         IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
324                        size_in_bytes, itv->udma.page_count);
325
326         ivtv_udma_prepare(itv);
327         prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
328         /* if no UDMA is pending and no UDMA is in progress, then the DMA
329            is finished */
330         while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
331                 /* don't interrupt if the DMA is in progress but break off
332                    a still pending DMA. */
333                 got_sig = signal_pending(current);
334                 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
335                         break;
336                 got_sig = 0;
337                 schedule();
338         }
339         finish_wait(&itv->dma_waitq, &wait);
340
341         /* Unmap Last DMA Xfer */
342         ivtv_udma_unmap(itv);
343         mutex_unlock(&itv->udma.lock);
344         if (got_sig) {
345                 IVTV_DEBUG_INFO("User stopped OSD\n");
346                 return -EINTR;
347         }
348
349         return ret;
350 }
351
352 static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
353                               unsigned long dest_offset, int count)
354 {
355         DEFINE_WAIT(wait);
356         struct osd_info *oi = itv->osd_info;
357
358         /* Nothing to do */
359         if (count == 0) {
360                 IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n");
361                 return -EINVAL;
362         }
363
364         /* Check Total FB Size */
365         if ((dest_offset + count) > oi->video_buffer_size) {
366                 IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
367                         dest_offset + count, oi->video_buffer_size);
368                 return -E2BIG;
369         }
370
371         /* Not fatal, but will have undesirable results */
372         if ((unsigned long)source & 3)
373                 IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
374                         (unsigned long)source);
375
376         if (dest_offset & 3)
377                 IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
378
379         if (count & 3)
380                 IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count);
381
382         /* Check Source */
383         if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
384                 IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n",
385                         (unsigned long)source);
386
387                 IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
388                         dest_offset, (unsigned long)source,
389                         count);
390                 return -EINVAL;
391         }
392
393         /* OSD Address to send DMA to */
394         dest_offset += IVTV_DEC_MEM_START + oi->video_rbase;
395
396         /* Fill Buffers */
397         return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count);
398 }
399
400 static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
401 {
402         DEFINE_WAIT(wait);
403         struct ivtv *itv = (struct ivtv *)info->par;
404         int rc = 0;
405
406         switch (cmd) {
407                 case FBIOGET_VBLANK: {
408                         struct fb_vblank vblank;
409                         u32 trace;
410
411                         vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
412                                         FB_VBLANK_HAVE_VSYNC;
413                         trace = read_reg(0x028c0) >> 16;
414                         if (itv->is_50hz && trace > 312) trace -= 312;
415                         else if (itv->is_60hz && trace > 262) trace -= 262;
416                         if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
417                         vblank.count = itv->lastVsyncFrame;
418                         vblank.vcount = trace;
419                         vblank.hcount = 0;
420                         if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
421                                 return -EFAULT;
422                         return 0;
423                 }
424
425                 case FBIO_WAITFORVSYNC:
426                         prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
427                         if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
428                         finish_wait(&itv->vsync_waitq, &wait);
429                         return rc;
430
431                 case IVTVFB_IOC_DMA_FRAME: {
432                         struct ivtvfb_dma_frame args;
433
434                         IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
435                         if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
436                                 return -EFAULT;
437
438                         return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
439                 }
440
441                 default:
442                         IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
443                         return -EINVAL;
444         }
445         return 0;
446 }
447
448 /* Framebuffer device handling */
449
450 static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
451 {
452         struct osd_info *oi = itv->osd_info;
453         struct ivtv_osd_coords ivtv_osd;
454         struct v4l2_rect ivtv_window;
455         int osd_mode = -1;
456
457         IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n");
458
459         /* Select color space */
460         if (var->nonstd) /* YUV */
461                 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
462         else /* RGB  */
463                 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
464
465         /* Set the color mode */
466         switch (var->bits_per_pixel) {
467                 case 8:
468                         osd_mode = IVTV_OSD_BPP_8;
469                         break;
470                 case 32:
471                         osd_mode = IVTV_OSD_BPP_32;
472                         break;
473                 case 16:
474                         switch (var->green.length) {
475                         case 4:
476                                 osd_mode = IVTV_OSD_BPP_16_444;
477                                 break;
478                         case 5:
479                                 osd_mode = IVTV_OSD_BPP_16_555;
480                                 break;
481                         case 6:
482                                 osd_mode = IVTV_OSD_BPP_16_565;
483                                 break;
484                         default:
485                                 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
486                         }
487                         break;
488                 default:
489                         IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
490         }
491
492         /* Change osd mode if needed.
493            Although rare, things can go wrong. The extra mode
494            change seems to help... */
495         if (osd_mode != -1 && osd_mode != oi->osd_mode) {
496                 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
497                 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
498                 oi->osd_mode = osd_mode;
499         }
500
501         oi->bits_per_pixel = var->bits_per_pixel;
502         oi->bytes_per_pixel = var->bits_per_pixel / 8;
503
504         /* Set the flicker filter */
505         switch (var->vmode & FB_VMODE_MASK) {
506                 case FB_VMODE_NONINTERLACED: /* Filter on */
507                         ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
508                         break;
509                 case FB_VMODE_INTERLACED: /* Filter off */
510                         ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
511                         break;
512                 default:
513                         IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
514         }
515
516         /* Read the current osd info */
517         ivtv_fb_get_osd_coords(itv, &ivtv_osd);
518
519         /* Now set the OSD to the size we want */
520         ivtv_osd.pixel_stride = var->xres_virtual;
521         ivtv_osd.lines = var->yres_virtual;
522         ivtv_osd.x = 0;
523         ivtv_osd.y = 0;
524         ivtv_fb_set_osd_coords(itv, &ivtv_osd);
525
526         /* Can't seem to find the right API combo for this.
527            Use another function which does what we need through direct register access. */
528         ivtv_window.width = var->xres;
529         ivtv_window.height = var->yres;
530
531         /* Minimum margin cannot be 0, as X won't allow such a mode */
532         if (!var->upper_margin) var->upper_margin++;
533         if (!var->left_margin) var->left_margin++;
534         ivtv_window.top = var->upper_margin - 1;
535         ivtv_window.left = var->left_margin - 1;
536
537         ivtv_fb_set_display_window(itv, &ivtv_window);
538
539         /* Force update of yuv registers */
540         itv->yuv_info.yuv_forced_update = 1;
541
542         IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
543                       var->xres, var->yres,
544                       var->xres_virtual, var->yres_virtual,
545                       var->bits_per_pixel);
546
547         IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
548                       var->left_margin, var->upper_margin);
549
550         IVTV_FB_DEBUG_INFO("Display filter: %s\n",
551                         (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
552         IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
553
554         return 0;
555 }
556
557 static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
558 {
559         struct osd_info *oi = itv->osd_info;
560
561         IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n");
562         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
563         strcpy(fix->id, "cx23415 TV out");
564         fix->smem_start = oi->video_pbase;
565         fix->smem_len = oi->video_buffer_size;
566         fix->type = FB_TYPE_PACKED_PIXELS;
567         fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
568         fix->xpanstep = 1;
569         fix->ypanstep = 1;
570         fix->ywrapstep = 0;
571         fix->line_length = oi->display_byte_stride;
572         fix->accel = FB_ACCEL_NONE;
573         return 0;
574 }
575
576 /* Check the requested display mode, returning -EINVAL if we can't
577    handle it. */
578
579 static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
580 {
581         struct osd_info *oi = itv->osd_info;
582         int osd_height_limit = itv->is_50hz ? 576 : 480;
583
584         IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
585
586         /* Check the bits per pixel */
587         if (osd_compat) {
588                 if (var->bits_per_pixel != 32) {
589                         IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
590                         return -EINVAL;
591                 }
592         }
593
594         if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
595                 var->transp.offset = 24;
596                 var->transp.length = 8;
597                 var->red.offset = 16;
598                 var->red.length = 8;
599                 var->green.offset = 8;
600                 var->green.length = 8;
601                 var->blue.offset = 0;
602                 var->blue.length = 8;
603         }
604         else if (var->bits_per_pixel == 16) {
605                 var->transp.offset = 0;
606                 var->transp.length = 0;
607
608                 /* To find out the true mode, check green length */
609                 switch (var->green.length) {
610                         case 4:
611                                 var->red.offset = 8;
612                                 var->red.length = 4;
613                                 var->green.offset = 4;
614                                 var->green.length = 4;
615                                 var->blue.offset = 0;
616                                 var->blue.length = 4;
617                                 break;
618                         case 5:
619                                 var->red.offset = 10;
620                                 var->red.length = 5;
621                                 var->green.offset = 5;
622                                 var->green.length = 5;
623                                 var->blue.offset = 0;
624                                 var->blue.length = 5;
625                                 break;
626                         default:
627                                 var->red.offset = 11;
628                                 var->red.length = 5;
629                                 var->green.offset = 5;
630                                 var->green.length = 6;
631                                 var->blue.offset = 0;
632                                 var->blue.length = 5;
633                                 break;
634                 }
635         }
636         else {
637                 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
638                 return -EINVAL;
639         }
640
641         /* Check the resolution */
642         if (osd_compat) {
643                 if (var->xres != oi->ivtvfb_defined.xres ||
644                     var->yres != oi->ivtvfb_defined.yres ||
645                     var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
646                     var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
647                         IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
648                                 var->xres, var->yres, var->xres_virtual, var->yres_virtual);
649                         return -EINVAL;
650                 }
651         }
652         else {
653                 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
654                         IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n",
655                                         var->xres, var->yres);
656                         return -EINVAL;
657                 }
658
659                 /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
660                 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
661                     var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
662                     var->xres_virtual < var->xres ||
663                     var->yres_virtual < var->yres) {
664                         IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
665                                 var->xres_virtual, var->yres_virtual);
666                         return -EINVAL;
667                 }
668         }
669
670         /* Some extra checks if in 8 bit mode */
671         if (var->bits_per_pixel == 8) {
672                 /* Width must be a multiple of 4 */
673                 if (var->xres & 3) {
674                         IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
675                         return -EINVAL;
676                 }
677                 if (var->xres_virtual & 3) {
678                         IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
679                         return -EINVAL;
680                 }
681         }
682         else if (var->bits_per_pixel == 16) {
683                 /* Width must be a multiple of 2 */
684                 if (var->xres & 1) {
685                         IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
686                         return -EINVAL;
687                 }
688                 if (var->xres_virtual & 1) {
689                         IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
690                         return -EINVAL;
691                 }
692         }
693
694         /* Now check the offsets */
695         if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
696                 IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
697                         var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
698                 return -EINVAL;
699         }
700
701         /* Check pixel format */
702         if (var->nonstd > 1) {
703                 IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
704                 return -EINVAL;
705         }
706
707         /* Check video mode */
708         if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
709                 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
710                 IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
711                 return -EINVAL;
712         }
713
714         /* Check the left & upper margins
715            If the margins are too large, just center the screen
716            (enforcing margins causes too many problems) */
717
718         if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
719                 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
720         }
721         if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
722                 var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
723         }
724
725         /* Maintain overall 'size' for a constant refresh rate */
726         var->right_margin = oi->hlimit - var->left_margin - var->xres;
727         var->lower_margin = oi->vlimit - var->upper_margin - var->yres;
728
729         /* Fixed sync times */
730         var->hsync_len = 24;
731         var->vsync_len = 2;
732
733         /* Non-interlaced / interlaced mode is used to switch the OSD filter
734            on or off. Adjust the clock timings to maintain a constant
735            vertical refresh rate. */
736         var->pixclock = oi->pixclock;
737         if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
738                 var->pixclock /= 2;
739
740         IVTV_FB_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         IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
746                       var->left_margin, var->upper_margin);
747
748         IVTV_FB_DEBUG_INFO("Display filter: %s\n",
749                         (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
750         IVTV_FB_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         IVTV_FB_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         IVTV_FB_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         IVTV_FB_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         /* Set base references for mode calcs. */
879         if (itv->is_50hz) {
880                 oi->pixclock = 84316;
881                 oi->hlimit = 776;
882                 oi->vlimit = 591;
883         }
884         else {
885                 oi->pixclock = 83926;
886                 oi->hlimit = 776;
887                 oi->vlimit = 495;
888         }
889
890         /* Color mode */
891
892         if (osd_compat) osd_depth = 32;
893         if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
894         oi->bits_per_pixel = osd_depth;
895         oi->bytes_per_pixel = oi->bits_per_pixel / 8;
896
897         /* Invalidate current osd mode to force a mode switch later */
898         oi->osd_mode = -1;
899
900         /* Horizontal size & position */
901
902         if (osd_xres > 720) osd_xres = 720;
903
904         /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
905         if (osd_depth == 8)
906                 osd_xres &= ~3;
907         else if (osd_depth == 16)
908                 osd_xres &= ~1;
909
910         if (osd_xres)
911                 start_window.width = osd_xres;
912         else
913                 start_window.width = osd_compat ? 720: 640;
914
915         /* Check horizontal start (osd_left). */
916         if (osd_left && osd_left + start_window.width > 721) {
917                 IVTV_FB_ERR("Invalid osd_left - assuming default\n");
918                 osd_left = 0;
919         }
920
921         /* Hardware coords start at 0, user coords start at 1. */
922         osd_left--;
923
924         start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
925
926         oi->display_byte_stride =
927                         start_window.width * oi->bytes_per_pixel;
928
929         /* Vertical size & position */
930
931         max_height = itv->is_50hz ? 576 : 480;
932
933         if (osd_yres > max_height)
934                 osd_yres = max_height;
935
936         if (osd_yres)
937                 start_window.height = osd_yres;
938         else
939                 start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
940
941         /* Check vertical start (osd_upper). */
942         if (osd_upper + start_window.height > max_height + 1) {
943                 IVTV_FB_ERR("Invalid osd_upper - assuming default\n");
944                 osd_upper = 0;
945         }
946
947         /* Hardware coords start at 0, user coords start at 1. */
948         osd_upper--;
949
950         start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
951
952         oi->display_width = start_window.width;
953         oi->display_height = start_window.height;
954
955         /* Generate a valid fb_var_screeninfo */
956
957         oi->ivtvfb_defined.xres = oi->display_width;
958         oi->ivtvfb_defined.yres = oi->display_height;
959         oi->ivtvfb_defined.xres_virtual = oi->display_width;
960         oi->ivtvfb_defined.yres_virtual = oi->display_height;
961         oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
962         oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
963         oi->ivtvfb_defined.left_margin = start_window.left + 1;
964         oi->ivtvfb_defined.upper_margin = start_window.top + 1;
965         oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
966         oi->ivtvfb_defined.nonstd = 0;
967
968         /* We've filled in the most data, let the usual mode check
969            routine fill in the rest. */
970         _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
971
972         /* Generate valid fb_fix_screeninfo */
973
974         ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
975
976         /* Generate valid fb_info */
977
978         oi->ivtvfb_info.node = -1;
979         oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
980         oi->ivtvfb_info.fbops = &ivtvfb_ops;
981         oi->ivtvfb_info.par = itv;
982         oi->ivtvfb_info.var = oi->ivtvfb_defined;
983         oi->ivtvfb_info.fix = oi->ivtvfb_fix;
984         oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
985         oi->ivtvfb_info.fbops = &ivtvfb_ops;
986
987         /* Supply some monitor specs. Bogus values will do for now */
988         oi->ivtvfb_info.monspecs.hfmin = 8000;
989         oi->ivtvfb_info.monspecs.hfmax = 70000;
990         oi->ivtvfb_info.monspecs.vfmin = 10;
991         oi->ivtvfb_info.monspecs.vfmax = 100;
992
993         /* Allocate color map */
994         if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
995                 IVTV_FB_ERR("abort, unable to alloc cmap\n");
996                 return -ENOMEM;
997         }
998
999         /* Allocate the pseudo palette */
1000         oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
1001
1002         if (!oi->ivtvfb_info.pseudo_palette) {
1003                 IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n");
1004                 return -ENOMEM;
1005         }
1006
1007         return 0;
1008 }
1009
1010 /* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
1011
1012 static int ivtvfb_init_io(struct ivtv *itv)
1013 {
1014         struct osd_info *oi = itv->osd_info;
1015
1016         ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
1017
1018         /* The osd buffer size depends on the number of video buffers allocated
1019            on the PVR350 itself. For now we'll hardcode the smallest osd buffer
1020            size to prevent any overlap. */
1021         oi->video_buffer_size = 1704960;
1022
1023         oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1024         oi->video_vbase = itv->dec_mem + oi->video_rbase;
1025
1026         if (!oi->video_vbase) {
1027                 IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1028                      oi->video_buffer_size, oi->video_pbase);
1029                 return -EIO;
1030         }
1031
1032         IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1033                         oi->video_pbase, oi->video_vbase,
1034                         oi->video_buffer_size / 1024);
1035
1036 #ifdef CONFIG_MTRR
1037         {
1038                 /* Find the largest power of two that maps the whole buffer */
1039                 int size_shift = 31;
1040
1041                 while (!(oi->video_buffer_size & (1 << size_shift))) {
1042                         size_shift--;
1043                 }
1044                 size_shift++;
1045                 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1046                 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1047                 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1048                 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1049                 if (mtrr_add(oi->fb_start_aligned_physaddr,
1050                         oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
1051                              MTRR_TYPE_WRCOMB, 1) < 0) {
1052                         IVTV_FB_WARN("cannot use mttr\n");
1053                         oi->fb_start_aligned_physaddr = 0;
1054                         oi->fb_end_aligned_physaddr = 0;
1055                 }
1056         }
1057 #endif
1058
1059         /* Blank the entire osd. */
1060         memset_io(oi->video_vbase, 0, oi->video_buffer_size);
1061
1062         return 0;
1063 }
1064
1065 /* Release any memory we've grabbed & remove mtrr entry */
1066 static void ivtvfb_release_buffers (struct ivtv *itv)
1067 {
1068         struct osd_info *oi = itv->osd_info;
1069
1070         /* Release cmap */
1071         if (oi->ivtvfb_info.cmap.len);
1072         fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
1073
1074         /* Release pseudo palette */
1075         if (oi->ivtvfb_info.pseudo_palette)
1076                 kfree(oi->ivtvfb_info.pseudo_palette);
1077
1078 #ifdef CONFIG_MTRR
1079         if (oi->fb_end_aligned_physaddr) {
1080                 mtrr_del(-1, oi->fb_start_aligned_physaddr,
1081                         oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1082         }
1083 #endif
1084
1085         kfree(oi);
1086         itv->osd_info = NULL;
1087 }
1088
1089 /* Initialize the specified card */
1090
1091 static int ivtvfb_init_card(struct ivtv *itv)
1092 {
1093         int rc;
1094
1095         if (itv->osd_info) {
1096                 IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id);
1097                 return -EBUSY;
1098         }
1099
1100         itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
1101         if (itv->osd_info == 0) {
1102                 IVTV_FB_ERR("Failed to allocate memory for osd_info\n");
1103                 return -ENOMEM;
1104         }
1105
1106         /* Find & setup the OSD buffer */
1107         if ((rc = ivtvfb_init_io(itv)))
1108                 return rc;
1109
1110         /* Set the startup video mode information */
1111         if ((rc = ivtvfb_init_vidmode(itv))) {
1112                 ivtvfb_release_buffers(itv);
1113                 return rc;
1114         }
1115
1116         /* Register the framebuffer */
1117         if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1118                 ivtvfb_release_buffers(itv);
1119                 return -EINVAL;
1120         }
1121
1122         itv->osd_video_pbase = itv->osd_info->video_pbase;
1123
1124         /* Set the card to the requested mode */
1125         ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1126
1127         /* Set color 0 to black */
1128         write_reg(0, 0x02a30);
1129         write_reg(0, 0x02a34);
1130
1131         /* Enable the osd */
1132         ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1133
1134         /* Note if we're running in compatibility mode */
1135         if (osd_compat)
1136                 IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
1137
1138         /* Allocate DMA */
1139         ivtv_udma_alloc(itv);
1140         return 0;
1141
1142 }
1143
1144 static int __init ivtvfb_init(void)
1145 {
1146         struct ivtv *itv;
1147         int i, registered = 0;
1148
1149         if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) {
1150                 printk(KERN_ERR "ivtv-fb:  ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n",
1151                      IVTV_MAX_CARDS - 1);
1152                 return -EINVAL;
1153         }
1154
1155         /* Locate & initialise all cards supporting an OSD. */
1156         for (i = 0; i < ivtv_cards_active; i++) {
1157                 if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id)
1158                         continue;
1159                 itv = ivtv_cards[i];
1160                 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1161                         if (ivtvfb_init_card(itv) == 0) {
1162                                 IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i);
1163                                 registered++;
1164                         }
1165                 }
1166         }
1167         if (!registered) {
1168                 printk(KERN_ERR "ivtv-fb:  no cards found");
1169                 return -ENODEV;
1170         }
1171         return 0;
1172 }
1173
1174 static void ivtvfb_cleanup(void)
1175 {
1176         struct ivtv *itv;
1177         int i;
1178
1179         printk(KERN_INFO "ivtv-fb:  Unloading framebuffer module\n");
1180
1181         for (i = 0; i < ivtv_cards_active; i++) {
1182                 itv = ivtv_cards[i];
1183                 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
1184                         IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i);
1185                         ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
1186                         unregister_framebuffer(&itv->osd_info->ivtvfb_info);
1187                         ivtvfb_release_buffers(itv);
1188                         itv->osd_video_pbase = 0;
1189                 }
1190         }
1191 }
1192
1193 module_init(ivtvfb_init);
1194 module_exit(ivtvfb_cleanup);