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