V4L/DVB (6092): ivtv: more cleanups, merged ivtv-audio.c and ivtv-video.c into ivtv...
[safe/jmp/linux-2.6] / drivers / media / video / ivtv / ivtv-fb.c
1 /*
2     On Screen Display cx23415 Framebuffer driver
3
4     This module presents the cx23415 OSD (onscreen display) framebuffer memory
5     as a standard Linux /dev/fb style framebuffer device. The framebuffer has
6     support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
7     mode, there is a choice of a three color depths (12, 15 or 16 bits), but no
8     local alpha. The colorspace is selectable between rgb & yuv.
9     Depending on the TV standard configured in the ivtv module at load time,
10     the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp.
11     Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL)
12     or 59.94 (NTSC)
13
14     Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
15
16     Derived from drivers/video/vesafb.c
17     Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
18
19     2.6 kernel port:
20     Copyright (C) 2004 Matthias Badaire
21
22     Copyright (C) 2004  Chris Kennedy <c@groovy.org>
23
24     Copyright (C) 2006  Ian Armstrong <ian@iarmst.demon.co.uk>
25
26     This program is free software; you can redistribute it and/or modify
27     it under the terms of the GNU General Public License as published by
28     the Free Software Foundation; either version 2 of the License, or
29     (at your option) any later version.
30
31     This program is distributed in the hope that it will be useful,
32     but WITHOUT ANY WARRANTY; without even the implied warranty of
33     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34     GNU General Public License for more details.
35
36     You should have received a copy of the GNU General Public License
37     along with this program; if not, write to the Free Software
38     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
39  */
40
41 #include <linux/module.h>
42 #include <linux/kernel.h>
43 #include <linux/string.h>
44 #include <linux/mm.h>
45 #include <linux/tty.h>
46 #include <linux/fb.h>
47 #include <linux/console.h>
48 #include <linux/bitops.h>
49 #include <linux/pagemap.h>
50 #include <linux/matroxfb.h>
51
52 #include <asm/io.h>
53 #include <asm/ioctl.h>
54
55 #ifdef CONFIG_MTRR
56 #include <asm/mtrr.h>
57 #endif
58
59 #include "ivtv-driver.h"
60 #include "ivtv-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_DECODER_OFFSET + 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                 /* To find out the true mode, check green length */
612                 switch (var->green.length) {
613                         case 4:
614                                 var->red.offset = 8;
615                                 var->red.length = 4;
616                                 var->green.offset = 4;
617                                 var->green.length = 4;
618                                 var->blue.offset = 0;
619                                 var->blue.length = 4;
620                                 var->transp.offset = 12;
621                                 var->transp.length = 1;
622                                 break;
623                         case 5:
624                                 var->red.offset = 10;
625                                 var->red.length = 5;
626                                 var->green.offset = 5;
627                                 var->green.length = 5;
628                                 var->blue.offset = 0;
629                                 var->blue.length = 5;
630                                 var->transp.offset = 15;
631                                 var->transp.length = 1;
632                                 break;
633                         default:
634                                 var->red.offset = 11;
635                                 var->red.length = 5;
636                                 var->green.offset = 5;
637                                 var->green.length = 6;
638                                 var->blue.offset = 0;
639                                 var->blue.length = 5;
640                                 var->transp.offset = 0;
641                                 var->transp.length = 0;
642                                 break;
643                 }
644         }
645         else {
646                 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
647                 return -EINVAL;
648         }
649
650         /* Check the resolution */
651         if (osd_compat) {
652                 if (var->xres != oi->ivtvfb_defined.xres ||
653                     var->yres != oi->ivtvfb_defined.yres ||
654                     var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
655                     var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
656                         IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
657                                 var->xres, var->yres, var->xres_virtual, var->yres_virtual);
658                         return -EINVAL;
659                 }
660         }
661         else {
662                 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
663                         IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n",
664                                         var->xres, var->yres);
665                         return -EINVAL;
666                 }
667
668                 /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
669                 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
670                     var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
671                     var->xres_virtual < var->xres ||
672                     var->yres_virtual < var->yres) {
673                         IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
674                                 var->xres_virtual, var->yres_virtual);
675                         return -EINVAL;
676                 }
677         }
678
679         /* Some extra checks if in 8 bit mode */
680         if (var->bits_per_pixel == 8) {
681                 /* Width must be a multiple of 4 */
682                 if (var->xres & 3) {
683                         IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
684                         return -EINVAL;
685                 }
686                 if (var->xres_virtual & 3) {
687                         IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
688                         return -EINVAL;
689                 }
690         }
691         else if (var->bits_per_pixel == 16) {
692                 /* Width must be a multiple of 2 */
693                 if (var->xres & 1) {
694                         IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
695                         return -EINVAL;
696                 }
697                 if (var->xres_virtual & 1) {
698                         IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
699                         return -EINVAL;
700                 }
701         }
702
703         /* Now check the offsets */
704         if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
705                 IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
706                         var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
707                 return -EINVAL;
708         }
709
710         /* Check pixel format */
711         if (var->nonstd > 1) {
712                 IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
713                 return -EINVAL;
714         }
715
716         /* Check video mode */
717         if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
718                 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
719                 IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
720                 return -EINVAL;
721         }
722
723         /* Check the left & upper margins
724            If the margins are too large, just center the screen
725            (enforcing margins causes too many problems) */
726
727         if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
728                 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
729         }
730         if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
731                 var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
732         }
733
734         /* Maintain overall 'size' for a constant refresh rate */
735         var->right_margin = hlimit - var->left_margin - var->xres;
736         var->lower_margin = vlimit - var->upper_margin - var->yres;
737
738         /* Fixed sync times */
739         var->hsync_len = 24;
740         var->vsync_len = 2;
741
742         /* Non-interlaced / interlaced mode is used to switch the OSD filter
743            on or off. Adjust the clock timings to maintain a constant
744            vertical refresh rate. */
745         if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
746                 var->pixclock = pixclock / 2;
747         else
748                 var->pixclock = pixclock;
749
750         IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
751                       var->xres, var->yres,
752                       var->xres_virtual, var->yres_virtual,
753                       var->bits_per_pixel);
754
755         IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
756                       var->left_margin, var->upper_margin);
757
758         IVTV_FB_DEBUG_INFO("Display filter: %s\n",
759                         (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
760         IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
761         return 0;
762 }
763
764 static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
765 {
766         struct ivtv *itv = (struct ivtv *) info->par;
767         IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
768         return _ivtvfb_check_var(var, itv);
769 }
770
771 static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
772 {
773         u32 osd_pan_index;
774         struct ivtv *itv = (struct ivtv *) info->par;
775
776         osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
777         write_reg(osd_pan_index, 0x02A0C);
778
779         /* Pass this info back the yuv handler */
780         itv->yuv_info.osd_x_pan = var->xoffset;
781         itv->yuv_info.osd_y_pan = var->yoffset;
782         /* Force update of yuv registers */
783         itv->yuv_info.yuv_forced_update = 1;
784         return 0;
785 }
786
787 static int ivtvfb_set_par(struct fb_info *info)
788 {
789         int rc = 0;
790         struct ivtv *itv = (struct ivtv *) info->par;
791
792         IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n");
793
794         rc = ivtvfb_set_var(itv, &info->var);
795         ivtvfb_pan_display(&info->var, info);
796         ivtvfb_get_fix(itv, &info->fix);
797         return rc;
798 }
799
800 static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
801                                 unsigned blue, unsigned transp,
802                                 struct fb_info *info)
803 {
804         u32 color, *palette;
805         struct ivtv *itv = (struct ivtv *)info->par;
806
807         if (regno >= info->cmap.len)
808                 return -EINVAL;
809
810         color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
811         if (info->var.bits_per_pixel <= 8) {
812                 write_reg(regno, 0x02a30);
813                 write_reg(color, 0x02a34);
814                 return 0;
815         }
816         if (regno >= 16)
817                 return -EINVAL;
818
819         palette = info->pseudo_palette;
820         if (info->var.bits_per_pixel == 16) {
821                 switch (info->var.green.length) {
822                         case 4:
823                                 color = ((red & 0xf000) >> 4) |
824                                         ((green & 0xf000) >> 8) |
825                                         ((blue & 0xf000) >> 12);
826                                 break;
827                         case 5:
828                                 color = ((red & 0xf800) >> 1) |
829                                         ((green & 0xf800) >> 6) |
830                                         ((blue & 0xf800) >> 11);
831                                 break;
832                         case 6:
833                                 color = (red & 0xf800 ) |
834                                         ((green & 0xfc00) >> 5) |
835                                         ((blue & 0xf800) >> 11);
836                                 break;
837                 }
838         }
839         palette[regno] = color;
840         return 0;
841 }
842
843 /* We don't really support blanking. All this does is enable or
844    disable the OSD. */
845 static int ivtvfb_blank(int blank_mode, struct fb_info *info)
846 {
847         struct ivtv *itv = (struct ivtv *)info->par;
848
849         IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
850         switch (blank_mode) {
851         case FB_BLANK_UNBLANK:
852                 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
853                 break;
854         case FB_BLANK_NORMAL:
855         case FB_BLANK_HSYNC_SUSPEND:
856         case FB_BLANK_VSYNC_SUSPEND:
857         case FB_BLANK_POWERDOWN:
858                 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
859                 break;
860         }
861         return 0;
862 }
863
864 static struct fb_ops ivtvfb_ops = {
865         .owner = THIS_MODULE,
866         .fb_check_var   = ivtvfb_check_var,
867         .fb_set_par     = ivtvfb_set_par,
868         .fb_setcolreg   = ivtvfb_setcolreg,
869         .fb_fillrect    = cfb_fillrect,
870         .fb_copyarea    = cfb_copyarea,
871         .fb_imageblit   = cfb_imageblit,
872         .fb_cursor      = NULL,
873         .fb_ioctl       = ivtvfb_ioctl,
874         .fb_pan_display = ivtvfb_pan_display,
875         .fb_blank       = ivtvfb_blank,
876 };
877
878 /* Initialization */
879
880
881 /* Setup our initial video mode */
882 static int ivtvfb_init_vidmode(struct ivtv *itv)
883 {
884         struct osd_info *oi = itv->osd_info;
885         struct v4l2_rect start_window;
886         int max_height;
887
888         /* Color mode */
889
890         if (osd_compat) osd_depth = 32;
891         if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
892         oi->bits_per_pixel = osd_depth;
893         oi->bytes_per_pixel = oi->bits_per_pixel / 8;
894
895         /* Invalidate current osd mode to force a mode switch later */
896         oi->osd_mode = -1;
897
898         /* Horizontal size & position */
899
900         if (osd_xres > 720) osd_xres = 720;
901
902         /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
903         if (osd_depth == 8)
904                 osd_xres &= ~3;
905         else if (osd_depth == 16)
906                 osd_xres &= ~1;
907
908         if (osd_xres)
909                 start_window.width = osd_xres;
910         else
911                 start_window.width = osd_compat ? 720: 640;
912
913         /* Check horizontal start (osd_left). */
914         if (osd_left && osd_left + start_window.width > 721) {
915                 IVTV_FB_ERR("Invalid osd_left - assuming default\n");
916                 osd_left = 0;
917         }
918
919         /* Hardware coords start at 0, user coords start at 1. */
920         osd_left--;
921
922         start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
923
924         oi->display_byte_stride =
925                         start_window.width * oi->bytes_per_pixel;
926
927         /* Vertical size & position */
928
929         max_height = itv->is_50hz ? 576 : 480;
930
931         if (osd_yres > max_height)
932                 osd_yres = max_height;
933
934         if (osd_yres)
935                 start_window.height = osd_yres;
936         else
937                 start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
938
939         /* Check vertical start (osd_upper). */
940         if (osd_upper + start_window.height > max_height + 1) {
941                 IVTV_FB_ERR("Invalid osd_upper - assuming default\n");
942                 osd_upper = 0;
943         }
944
945         /* Hardware coords start at 0, user coords start at 1. */
946         osd_upper--;
947
948         start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
949
950         oi->display_width = start_window.width;
951         oi->display_height = start_window.height;
952
953         /* Generate a valid fb_var_screeninfo */
954
955         oi->ivtvfb_defined.xres = oi->display_width;
956         oi->ivtvfb_defined.yres = oi->display_height;
957         oi->ivtvfb_defined.xres_virtual = oi->display_width;
958         oi->ivtvfb_defined.yres_virtual = oi->display_height;
959         oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
960         oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
961         oi->ivtvfb_defined.left_margin = start_window.left + 1;
962         oi->ivtvfb_defined.upper_margin = start_window.top + 1;
963         oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
964         oi->ivtvfb_defined.nonstd = 0;
965
966         /* We've filled in the most data, let the usual mode check
967            routine fill in the rest. */
968         _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
969
970         /* Generate valid fb_fix_screeninfo */
971
972         ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
973
974         /* Generate valid fb_info */
975
976         oi->ivtvfb_info.node = -1;
977         oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
978         oi->ivtvfb_info.fbops = &ivtvfb_ops;
979         oi->ivtvfb_info.par = itv;
980         oi->ivtvfb_info.var = oi->ivtvfb_defined;
981         oi->ivtvfb_info.fix = oi->ivtvfb_fix;
982         oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
983         oi->ivtvfb_info.fbops = &ivtvfb_ops;
984
985         /* Supply some monitor specs. Bogus values will do for now */
986         oi->ivtvfb_info.monspecs.hfmin = 8000;
987         oi->ivtvfb_info.monspecs.hfmax = 70000;
988         oi->ivtvfb_info.monspecs.vfmin = 10;
989         oi->ivtvfb_info.monspecs.vfmax = 100;
990
991         /* Allocate color map */
992         if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
993                 IVTV_FB_ERR("abort, unable to alloc cmap\n");
994                 return -ENOMEM;
995         }
996
997         /* Allocate the pseudo palette */
998         oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
999
1000         if (!oi->ivtvfb_info.pseudo_palette) {
1001                 IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n");
1002                 return -ENOMEM;
1003         }
1004
1005         return 0;
1006 }
1007
1008 /* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
1009
1010 static int ivtvfb_init_io(struct ivtv *itv)
1011 {
1012         struct osd_info *oi = itv->osd_info;
1013
1014         if (ivtv_init_on_first_open(itv)) {
1015                 IVTV_FB_ERR("Failed to initialize ivtv\n");
1016                 return -ENXIO;
1017         }
1018
1019         ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
1020
1021         /* The osd buffer size depends on the number of video buffers allocated
1022            on the PVR350 itself. For now we'll hardcode the smallest osd buffer
1023            size to prevent any overlap. */
1024         oi->video_buffer_size = 1704960;
1025
1026         oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1027         oi->video_vbase = itv->dec_mem + oi->video_rbase;
1028
1029         if (!oi->video_vbase) {
1030                 IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1031                      oi->video_buffer_size, oi->video_pbase);
1032                 return -EIO;
1033         }
1034
1035         IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1036                         oi->video_pbase, oi->video_vbase,
1037                         oi->video_buffer_size / 1024);
1038
1039 #ifdef CONFIG_MTRR
1040         {
1041                 /* Find the largest power of two that maps the whole buffer */
1042                 int size_shift = 31;
1043
1044                 while (!(oi->video_buffer_size & (1 << size_shift))) {
1045                         size_shift--;
1046                 }
1047                 size_shift++;
1048                 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1049                 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1050                 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1051                 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1052                 if (mtrr_add(oi->fb_start_aligned_physaddr,
1053                         oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
1054                              MTRR_TYPE_WRCOMB, 1) < 0) {
1055                         IVTV_FB_WARN("cannot use mttr\n");
1056                         oi->fb_start_aligned_physaddr = 0;
1057                         oi->fb_end_aligned_physaddr = 0;
1058                 }
1059         }
1060 #endif
1061
1062         /* Blank the entire osd. */
1063         memset_io(oi->video_vbase, 0, oi->video_buffer_size);
1064
1065         return 0;
1066 }
1067
1068 /* Release any memory we've grabbed & remove mtrr entry */
1069 static void ivtvfb_release_buffers (struct ivtv *itv)
1070 {
1071         struct osd_info *oi = itv->osd_info;
1072
1073         /* Release cmap */
1074         if (oi->ivtvfb_info.cmap.len);
1075         fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
1076
1077         /* Release pseudo palette */
1078         if (oi->ivtvfb_info.pseudo_palette)
1079                 kfree(oi->ivtvfb_info.pseudo_palette);
1080
1081 #ifdef CONFIG_MTRR
1082         if (oi->fb_end_aligned_physaddr) {
1083                 mtrr_del(-1, oi->fb_start_aligned_physaddr,
1084                         oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1085         }
1086 #endif
1087
1088         kfree(oi);
1089         itv->osd_info = NULL;
1090 }
1091
1092 /* Initialize the specified card */
1093
1094 static int ivtvfb_init_card(struct ivtv *itv)
1095 {
1096         int rc;
1097
1098         if (itv->osd_info) {
1099                 IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id);
1100                 return -EBUSY;
1101         }
1102
1103         itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
1104         if (itv->osd_info == 0) {
1105                 IVTV_FB_ERR("Failed to allocate memory for osd_info\n");
1106                 return -ENOMEM;
1107         }
1108
1109         /* Find & setup the OSD buffer */
1110         if ((rc = ivtvfb_init_io(itv)))
1111                 return rc;
1112
1113         /* Set the startup video mode information */
1114         if ((rc = ivtvfb_init_vidmode(itv))) {
1115                 ivtvfb_release_buffers(itv);
1116                 return rc;
1117         }
1118
1119         /* Register the framebuffer */
1120         if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1121                 ivtvfb_release_buffers(itv);
1122                 return -EINVAL;
1123         }
1124
1125         itv->osd_video_pbase = itv->osd_info->video_pbase;
1126
1127         /* Set the card to the requested mode */
1128         ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1129
1130         /* Set color 0 to black */
1131         write_reg(0, 0x02a30);
1132         write_reg(0, 0x02a34);
1133
1134         /* Enable the osd */
1135         ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1136
1137         /* Note if we're running in compatibility mode */
1138         if (osd_compat)
1139                 IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
1140
1141         /* Allocate DMA */
1142         ivtv_udma_alloc(itv);
1143         return 0;
1144
1145 }
1146
1147 static int __init ivtvfb_init(void)
1148 {
1149         struct ivtv *itv;
1150         int i, registered = 0;
1151
1152         if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) {
1153                 printk(KERN_ERR "ivtv-fb:  ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n",
1154                      IVTV_MAX_CARDS - 1);
1155                 return -EINVAL;
1156         }
1157
1158         /* Locate & initialise all cards supporting an OSD. */
1159         for (i = 0; i < ivtv_cards_active; i++) {
1160                 if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id)
1161                         continue;
1162                 itv = ivtv_cards[i];
1163                 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1164                         if (ivtvfb_init_card(itv) == 0) {
1165                                 IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i);
1166                                 registered++;
1167                         }
1168                 }
1169         }
1170         if (!registered) {
1171                 printk(KERN_ERR "ivtv-fb:  no cards found");
1172                 return -ENODEV;
1173         }
1174         return 0;
1175 }
1176
1177 static void ivtvfb_cleanup(void)
1178 {
1179         struct ivtv *itv;
1180         int i;
1181
1182         printk(KERN_INFO "ivtv-fb:  Unloading framebuffer module\n");
1183
1184         for (i = 0; i < ivtv_cards_active; i++) {
1185                 itv = ivtv_cards[i];
1186                 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
1187                         IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i);
1188                         ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
1189                         unregister_framebuffer(&itv->osd_info->ivtvfb_info);
1190                         ivtvfb_release_buffers(itv);
1191                         itv->osd_video_pbase = 0;
1192                 }
1193         }
1194 }
1195
1196 module_init(ivtvfb_init);
1197 module_exit(ivtvfb_cleanup);