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