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