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