1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41#include <linux/module.h>
42#include <linux/kernel.h>
43#include <linux/fb.h>
44#include <linux/ivtvfb.h>
45
46#ifdef CONFIG_MTRR
47#include <asm/mtrr.h>
48#endif
49
50#include "ivtv-driver.h"
51#include "ivtv-cards.h"
52#include "ivtv-i2c.h"
53#include "ivtv-udma.h"
54#include "ivtv-mailbox.h"
55
56
57static int ivtvfb_card_id = -1;
58static int ivtvfb_debug = 0;
59static int osd_laced;
60static int osd_depth;
61static int osd_upper;
62static int osd_left;
63static int osd_yres;
64static int osd_xres;
65
66module_param(ivtvfb_card_id, int, 0444);
67module_param_named(debug,ivtvfb_debug, int, 0644);
68module_param(osd_laced, bool, 0444);
69module_param(osd_depth, int, 0444);
70module_param(osd_upper, int, 0444);
71module_param(osd_left, int, 0444);
72module_param(osd_yres, int, 0444);
73module_param(osd_xres, int, 0444);
74
75MODULE_PARM_DESC(ivtvfb_card_id,
76 "Only use framebuffer of the specified ivtv card (0-31)\n"
77 "\t\t\tdefault -1: initialize all available framebuffers");
78
79MODULE_PARM_DESC(debug,
80 "Debug level (bitmask). Default: errors only\n"
81 "\t\t\t(debug = 3 gives full debugging)");
82
83
84
85
86
87MODULE_PARM_DESC(osd_laced,
88 "Interlaced mode\n"
89 "\t\t\t0=off\n"
90 "\t\t\t1=on\n"
91 "\t\t\tdefault off");
92
93MODULE_PARM_DESC(osd_depth,
94 "Bits per pixel - 8, 16, 32\n"
95 "\t\t\tdefault 8");
96
97MODULE_PARM_DESC(osd_upper,
98 "Vertical start position\n"
99 "\t\t\tdefault 0 (Centered)");
100
101MODULE_PARM_DESC(osd_left,
102 "Horizontal start position\n"
103 "\t\t\tdefault 0 (Centered)");
104
105MODULE_PARM_DESC(osd_yres,
106 "Display height\n"
107 "\t\t\tdefault 480 (PAL)\n"
108 "\t\t\t 400 (NTSC)");
109
110MODULE_PARM_DESC(osd_xres,
111 "Display width\n"
112 "\t\t\tdefault 640");
113
114MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
115MODULE_LICENSE("GPL");
116
117
118
119#define IVTVFB_DBGFLG_WARN (1 << 0)
120#define IVTVFB_DBGFLG_INFO (1 << 1)
121
122#define IVTVFB_DEBUG(x, type, fmt, args...) \
123 do { \
124 if ((x) & ivtvfb_debug) \
125 printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \
126 } while (0)
127#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
128#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
129
130
131#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->instance , ## args)
132#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->instance , ## args)
133#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args)
134
135
136
137#define IVTV_OSD_MAX_WIDTH 720
138#define IVTV_OSD_MAX_HEIGHT 576
139
140#define IVTV_OSD_BPP_8 0x00
141#define IVTV_OSD_BPP_16_444 0x03
142#define IVTV_OSD_BPP_16_555 0x02
143#define IVTV_OSD_BPP_16_565 0x01
144#define IVTV_OSD_BPP_32 0x04
145
146struct osd_info {
147
148 unsigned long video_pbase;
149
150 u32 video_rbase;
151
152 volatile char __iomem *video_vbase;
153
154 u32 video_buffer_size;
155
156#ifdef CONFIG_MTRR
157
158 unsigned long fb_start_aligned_physaddr;
159
160 unsigned long fb_end_aligned_physaddr;
161#endif
162
163
164 int set_osd_coords_x;
165 int set_osd_coords_y;
166
167
168 int display_width;
169 int display_height;
170 int display_byte_stride;
171
172
173 int bits_per_pixel;
174 int bytes_per_pixel;
175
176
177 struct fb_info ivtvfb_info;
178 struct fb_var_screeninfo ivtvfb_defined;
179 struct fb_fix_screeninfo ivtvfb_fix;
180};
181
182struct ivtv_osd_coords {
183 unsigned long offset;
184 unsigned long max_offset;
185 int pixel_stride;
186 int lines;
187 int x;
188 int y;
189};
190
191
192
193
194
195static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
196 u32 *fblength)
197{
198 u32 data[CX2341X_MBOX_MAX_DATA];
199 int rc;
200
201 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
202 *fbbase = data[0];
203 *fblength = data[1];
204 return rc;
205}
206
207static int ivtvfb_get_osd_coords(struct ivtv *itv,
208 struct ivtv_osd_coords *osd)
209{
210 struct osd_info *oi = itv->osd_info;
211 u32 data[CX2341X_MBOX_MAX_DATA];
212
213 ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
214
215 osd->offset = data[0] - oi->video_rbase;
216 osd->max_offset = oi->display_width * oi->display_height * 4;
217 osd->pixel_stride = data[1];
218 osd->lines = data[2];
219 osd->x = data[3];
220 osd->y = data[4];
221 return 0;
222}
223
224static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
225{
226 struct osd_info *oi = itv->osd_info;
227
228 oi->display_width = osd->pixel_stride;
229 oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
230 oi->set_osd_coords_x += osd->x;
231 oi->set_osd_coords_y = osd->y;
232
233 return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
234 osd->offset + oi->video_rbase,
235 osd->pixel_stride,
236 osd->lines, osd->x, osd->y);
237}
238
239static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
240{
241 int osd_height_limit = itv->is_50hz ? 576 : 480;
242
243
244 if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
245 return -EINVAL;
246
247
248 if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
249 IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
250 ivtv_window->top, ivtv_window->height);
251 ivtv_window->top = osd_height_limit - ivtv_window->height;
252 }
253
254 if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
255 IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
256 ivtv_window->left, ivtv_window->width);
257 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
258 }
259
260
261 write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
262
263
264 write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
265
266
267 itv->yuv_info.osd_vis_w = ivtv_window->width;
268 itv->yuv_info.osd_vis_h = ivtv_window->height;
269 itv->yuv_info.osd_x_offset = ivtv_window->left;
270 itv->yuv_info.osd_y_offset = ivtv_window->top;
271
272 return 0;
273}
274
275static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
276 unsigned long ivtv_dest_addr, void __user *userbuf,
277 int size_in_bytes)
278{
279 DEFINE_WAIT(wait);
280 int got_sig = 0;
281
282 mutex_lock(&itv->udma.lock);
283
284 if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
285 mutex_unlock(&itv->udma.lock);
286 IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, "
287 "Error with get_user_pages: %d bytes, %d pages returned\n",
288 size_in_bytes, itv->udma.page_count);
289
290
291 return -EIO;
292 }
293
294 IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
295 size_in_bytes, itv->udma.page_count);
296
297 ivtv_udma_prepare(itv);
298 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
299
300
301 while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
302 test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
303
304
305 got_sig = signal_pending(current);
306 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
307 break;
308 got_sig = 0;
309 schedule();
310 }
311 finish_wait(&itv->dma_waitq, &wait);
312
313
314 ivtv_udma_unmap(itv);
315 mutex_unlock(&itv->udma.lock);
316 if (got_sig) {
317 IVTV_DEBUG_INFO("User stopped OSD\n");
318 return -EINTR;
319 }
320
321 return 0;
322}
323
324static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
325 unsigned long dest_offset, int count)
326{
327 DEFINE_WAIT(wait);
328 struct osd_info *oi = itv->osd_info;
329
330
331 if (count == 0) {
332 IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n");
333 return -EINVAL;
334 }
335
336
337 if ((dest_offset + count) > oi->video_buffer_size) {
338 IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
339 dest_offset + count, oi->video_buffer_size);
340 return -E2BIG;
341 }
342
343
344 if ((unsigned long)source & 3)
345 IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
346 (unsigned long)source);
347
348 if (dest_offset & 3)
349 IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
350
351 if (count & 3)
352 IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
353
354
355 if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
356 IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
357 (unsigned long)source);
358
359 IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
360 dest_offset, (unsigned long)source,
361 count);
362 return -EINVAL;
363 }
364
365
366 dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
367
368
369 return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
370}
371
372static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
373 size_t count, loff_t *ppos)
374{
375 unsigned long p = *ppos;
376 void *dst;
377 int err = 0;
378 int dma_err;
379 unsigned long total_size;
380 struct ivtv *itv = (struct ivtv *) info->par;
381 unsigned long dma_offset =
382 IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
383 unsigned long dma_size;
384 u16 lead = 0, tail = 0;
385
386 if (info->state != FBINFO_STATE_RUNNING)
387 return -EPERM;
388
389 total_size = info->screen_size;
390
391 if (total_size == 0)
392 total_size = info->fix.smem_len;
393
394 if (p > total_size)
395 return -EFBIG;
396
397 if (count > total_size) {
398 err = -EFBIG;
399 count = total_size;
400 }
401
402 if (count + p > total_size) {
403 if (!err)
404 err = -ENOSPC;
405 count = total_size - p;
406 }
407
408 dst = (void __force *) (info->screen_base + p);
409
410 if (info->fbops->fb_sync)
411 info->fbops->fb_sync(info);
412
413
414
415 if (count >= 4096 &&
416 ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
417
418 if ((unsigned long)dst & 3) {
419 lead = 4 - ((unsigned long)dst & 3);
420 if (copy_from_user(dst, buf, lead))
421 return -EFAULT;
422 buf += lead;
423 dst += lead;
424 }
425
426 if ((count - lead) & 3)
427 tail = (count - lead) & 3;
428
429 dma_size = count - lead - tail;
430 dma_err = ivtvfb_prep_dec_dma_to_device(itv,
431 p + lead + dma_offset, (void __user *)buf, dma_size);
432 if (dma_err)
433 return dma_err;
434 dst += dma_size;
435 buf += dma_size;
436
437 if (tail && copy_from_user(dst, buf, tail))
438 return -EFAULT;
439 } else if (copy_from_user(dst, buf, count)) {
440 return -EFAULT;
441 }
442
443 if (!err)
444 *ppos += count;
445
446 return (err) ? err : count;
447}
448
449static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
450{
451 DEFINE_WAIT(wait);
452 struct ivtv *itv = (struct ivtv *)info->par;
453 int rc = 0;
454
455 switch (cmd) {
456 case FBIOGET_VBLANK: {
457 struct fb_vblank vblank;
458 u32 trace;
459
460 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
461 FB_VBLANK_HAVE_VSYNC;
462 trace = read_reg(0x028c0) >> 16;
463 if (itv->is_50hz && trace > 312)
464 trace -= 312;
465 else if (itv->is_60hz && trace > 262)
466 trace -= 262;
467 if (trace == 1)
468 vblank.flags |= FB_VBLANK_VSYNCING;
469 vblank.count = itv->last_vsync_field;
470 vblank.vcount = trace;
471 vblank.hcount = 0;
472 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
473 return -EFAULT;
474 return 0;
475 }
476
477 case FBIO_WAITFORVSYNC:
478 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
479 if (!schedule_timeout(msecs_to_jiffies(50)))
480 rc = -ETIMEDOUT;
481 finish_wait(&itv->vsync_waitq, &wait);
482 return rc;
483
484 case IVTVFB_IOC_DMA_FRAME: {
485 struct ivtvfb_dma_frame args;
486
487 IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
488 if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
489 return -EFAULT;
490
491 return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
492 }
493
494 default:
495 IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
496 return -EINVAL;
497 }
498 return 0;
499}
500
501
502
503static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
504{
505 struct osd_info *oi = itv->osd_info;
506 struct ivtv_osd_coords ivtv_osd;
507 struct v4l2_rect ivtv_window;
508 int osd_mode = -1;
509
510 IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
511
512
513 if (var->nonstd)
514 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
515 else
516 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
517
518
519 switch (var->bits_per_pixel) {
520 case 8:
521 osd_mode = IVTV_OSD_BPP_8;
522 break;
523 case 32:
524 osd_mode = IVTV_OSD_BPP_32;
525 break;
526 case 16:
527 switch (var->green.length) {
528 case 4:
529 osd_mode = IVTV_OSD_BPP_16_444;
530 break;
531 case 5:
532 osd_mode = IVTV_OSD_BPP_16_555;
533 break;
534 case 6:
535 osd_mode = IVTV_OSD_BPP_16_565;
536 break;
537 default:
538 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
539 }
540 break;
541 default:
542 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
543 }
544
545
546
547 if (osd_mode != -1) {
548 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
549 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
550 }
551
552 oi->bits_per_pixel = var->bits_per_pixel;
553 oi->bytes_per_pixel = var->bits_per_pixel / 8;
554
555
556 switch (var->vmode & FB_VMODE_MASK) {
557 case FB_VMODE_NONINTERLACED:
558 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
559 break;
560 case FB_VMODE_INTERLACED:
561 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
562 break;
563 default:
564 IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
565 }
566
567
568 ivtvfb_get_osd_coords(itv, &ivtv_osd);
569
570
571 ivtv_osd.pixel_stride = var->xres_virtual;
572 ivtv_osd.lines = var->yres_virtual;
573 ivtv_osd.x = 0;
574 ivtv_osd.y = 0;
575 ivtvfb_set_osd_coords(itv, &ivtv_osd);
576
577
578
579 ivtv_window.width = var->xres;
580 ivtv_window.height = var->yres;
581
582
583 if (!var->upper_margin) var->upper_margin++;
584 if (!var->left_margin) var->left_margin++;
585 ivtv_window.top = var->upper_margin - 1;
586 ivtv_window.left = var->left_margin - 1;
587
588 ivtvfb_set_display_window(itv, &ivtv_window);
589
590
591 itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
592 itv->yuv_info.osd_full_h = ivtv_osd.lines;
593
594
595 itv->yuv_info.yuv_forced_update = 1;
596
597 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
598 var->xres, var->yres,
599 var->xres_virtual, var->yres_virtual,
600 var->bits_per_pixel);
601
602 IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
603 var->left_margin, var->upper_margin);
604
605 IVTVFB_DEBUG_INFO("Display filter: %s\n",
606 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
607 IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
608
609 return 0;
610}
611
612static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
613{
614 struct osd_info *oi = itv->osd_info;
615
616 IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
617 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
618 strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));
619 fix->smem_start = oi->video_pbase;
620 fix->smem_len = oi->video_buffer_size;
621 fix->type = FB_TYPE_PACKED_PIXELS;
622 fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
623 fix->xpanstep = 1;
624 fix->ypanstep = 1;
625 fix->ywrapstep = 0;
626 fix->line_length = oi->display_byte_stride;
627 fix->accel = FB_ACCEL_NONE;
628 return 0;
629}
630
631
632
633
634static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
635{
636 struct osd_info *oi = itv->osd_info;
637 int osd_height_limit;
638 u32 pixclock, hlimit, vlimit;
639
640 IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
641
642
643 if (itv->is_50hz) {
644 pixclock = 84316;
645 hlimit = 776;
646 vlimit = 591;
647 osd_height_limit = 576;
648 }
649 else {
650 pixclock = 83926;
651 hlimit = 776;
652 vlimit = 495;
653 osd_height_limit = 480;
654 }
655
656 if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
657 var->transp.offset = 24;
658 var->transp.length = 8;
659 var->red.offset = 16;
660 var->red.length = 8;
661 var->green.offset = 8;
662 var->green.length = 8;
663 var->blue.offset = 0;
664 var->blue.length = 8;
665 }
666 else if (var->bits_per_pixel == 16) {
667
668 switch (var->green.length) {
669 case 4:
670 var->red.offset = 8;
671 var->red.length = 4;
672 var->green.offset = 4;
673 var->green.length = 4;
674 var->blue.offset = 0;
675 var->blue.length = 4;
676 var->transp.offset = 12;
677 var->transp.length = 1;
678 break;
679 case 5:
680 var->red.offset = 10;
681 var->red.length = 5;
682 var->green.offset = 5;
683 var->green.length = 5;
684 var->blue.offset = 0;
685 var->blue.length = 5;
686 var->transp.offset = 15;
687 var->transp.length = 1;
688 break;
689 default:
690 var->red.offset = 11;
691 var->red.length = 5;
692 var->green.offset = 5;
693 var->green.length = 6;
694 var->blue.offset = 0;
695 var->blue.length = 5;
696 var->transp.offset = 0;
697 var->transp.length = 0;
698 break;
699 }
700 }
701 else {
702 IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
703 return -EINVAL;
704 }
705
706
707 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
708 IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
709 var->xres, var->yres);
710 return -EINVAL;
711 }
712
713
714 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
715 var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
716 var->xres_virtual < var->xres ||
717 var->yres_virtual < var->yres) {
718 IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
719 var->xres_virtual, var->yres_virtual);
720 return -EINVAL;
721 }
722
723
724 if (var->bits_per_pixel == 8) {
725
726 if (var->xres & 3) {
727 IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
728 return -EINVAL;
729 }
730 if (var->xres_virtual & 3) {
731 IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
732 return -EINVAL;
733 }
734 }
735 else if (var->bits_per_pixel == 16) {
736
737 if (var->xres & 1) {
738 IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
739 return -EINVAL;
740 }
741 if (var->xres_virtual & 1) {
742 IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
743 return -EINVAL;
744 }
745 }
746
747
748 if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
749 IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
750 var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
751 return -EINVAL;
752 }
753
754
755 if (var->nonstd > 1) {
756 IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
757 return -EINVAL;
758 }
759
760
761 if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
762 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
763 IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
764 return -EINVAL;
765 }
766
767
768
769
770
771 if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
772 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
773 }
774 if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
775 var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
776 }
777
778
779 var->right_margin = hlimit - var->left_margin - var->xres;
780 var->lower_margin = vlimit - var->upper_margin - var->yres;
781
782
783 var->hsync_len = 24;
784 var->vsync_len = 2;
785
786
787
788
789 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
790 var->pixclock = pixclock / 2;
791 else
792 var->pixclock = pixclock;
793
794 itv->osd_rect.width = var->xres;
795 itv->osd_rect.height = var->yres;
796
797 IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
798 var->xres, var->yres,
799 var->xres_virtual, var->yres_virtual,
800 var->bits_per_pixel);
801
802 IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
803 var->left_margin, var->upper_margin);
804
805 IVTVFB_DEBUG_INFO("Display filter: %s\n",
806 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
807 IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
808 return 0;
809}
810
811static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
812{
813 struct ivtv *itv = (struct ivtv *) info->par;
814 IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
815 return _ivtvfb_check_var(var, itv);
816}
817
818static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
819{
820 u32 osd_pan_index;
821 struct ivtv *itv = (struct ivtv *) info->par;
822
823 osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
824 write_reg(osd_pan_index, 0x02A0C);
825
826
827 itv->yuv_info.osd_x_pan = var->xoffset;
828 itv->yuv_info.osd_y_pan = var->yoffset;
829
830 itv->yuv_info.yuv_forced_update = 1;
831 return 0;
832}
833
834static int ivtvfb_set_par(struct fb_info *info)
835{
836 int rc = 0;
837 struct ivtv *itv = (struct ivtv *) info->par;
838
839 IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
840
841 rc = ivtvfb_set_var(itv, &info->var);
842 ivtvfb_pan_display(&info->var, info);
843 ivtvfb_get_fix(itv, &info->fix);
844 return rc;
845}
846
847static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
848 unsigned blue, unsigned transp,
849 struct fb_info *info)
850{
851 u32 color, *palette;
852 struct ivtv *itv = (struct ivtv *)info->par;
853
854 if (regno >= info->cmap.len)
855 return -EINVAL;
856
857 color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
858 if (info->var.bits_per_pixel <= 8) {
859 write_reg(regno, 0x02a30);
860 write_reg(color, 0x02a34);
861 return 0;
862 }
863 if (regno >= 16)
864 return -EINVAL;
865
866 palette = info->pseudo_palette;
867 if (info->var.bits_per_pixel == 16) {
868 switch (info->var.green.length) {
869 case 4:
870 color = ((red & 0xf000) >> 4) |
871 ((green & 0xf000) >> 8) |
872 ((blue & 0xf000) >> 12);
873 break;
874 case 5:
875 color = ((red & 0xf800) >> 1) |
876 ((green & 0xf800) >> 6) |
877 ((blue & 0xf800) >> 11);
878 break;
879 case 6:
880 color = (red & 0xf800 ) |
881 ((green & 0xfc00) >> 5) |
882 ((blue & 0xf800) >> 11);
883 break;
884 }
885 }
886 palette[regno] = color;
887 return 0;
888}
889
890
891
892static int ivtvfb_blank(int blank_mode, struct fb_info *info)
893{
894 struct ivtv *itv = (struct ivtv *)info->par;
895
896 IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
897 switch (blank_mode) {
898 case FB_BLANK_UNBLANK:
899 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
900 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
901 break;
902 case FB_BLANK_NORMAL:
903 case FB_BLANK_HSYNC_SUSPEND:
904 case FB_BLANK_VSYNC_SUSPEND:
905 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
906 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
907 break;
908 case FB_BLANK_POWERDOWN:
909 ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
910 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
911 break;
912 }
913 return 0;
914}
915
916static struct fb_ops ivtvfb_ops = {
917 .owner = THIS_MODULE,
918 .fb_write = ivtvfb_write,
919 .fb_check_var = ivtvfb_check_var,
920 .fb_set_par = ivtvfb_set_par,
921 .fb_setcolreg = ivtvfb_setcolreg,
922 .fb_fillrect = cfb_fillrect,
923 .fb_copyarea = cfb_copyarea,
924 .fb_imageblit = cfb_imageblit,
925 .fb_cursor = NULL,
926 .fb_ioctl = ivtvfb_ioctl,
927 .fb_pan_display = ivtvfb_pan_display,
928 .fb_blank = ivtvfb_blank,
929};
930
931
932
933
934
935static int ivtvfb_init_vidmode(struct ivtv *itv)
936{
937 struct osd_info *oi = itv->osd_info;
938 struct v4l2_rect start_window;
939 int max_height;
940
941
942
943 if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32)
944 osd_depth = 8;
945 oi->bits_per_pixel = osd_depth;
946 oi->bytes_per_pixel = oi->bits_per_pixel / 8;
947
948
949
950 if (osd_xres > 720)
951 osd_xres = 720;
952
953
954 if (osd_depth == 8)
955 osd_xres &= ~3;
956 else if (osd_depth == 16)
957 osd_xres &= ~1;
958
959 start_window.width = osd_xres ? osd_xres : 640;
960
961
962 if (osd_left && osd_left + start_window.width > 721) {
963 IVTVFB_ERR("Invalid osd_left - assuming default\n");
964 osd_left = 0;
965 }
966
967
968 osd_left--;
969
970 start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
971
972 oi->display_byte_stride =
973 start_window.width * oi->bytes_per_pixel;
974
975
976
977 max_height = itv->is_50hz ? 576 : 480;
978
979 if (osd_yres > max_height)
980 osd_yres = max_height;
981
982 start_window.height = osd_yres ? osd_yres : itv->is_50hz ? 480 : 400;
983
984
985 if (osd_upper + start_window.height > max_height + 1) {
986 IVTVFB_ERR("Invalid osd_upper - assuming default\n");
987 osd_upper = 0;
988 }
989
990
991 osd_upper--;
992
993 start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
994
995 oi->display_width = start_window.width;
996 oi->display_height = start_window.height;
997
998
999
1000 oi->ivtvfb_defined.xres = oi->display_width;
1001 oi->ivtvfb_defined.yres = oi->display_height;
1002 oi->ivtvfb_defined.xres_virtual = oi->display_width;
1003 oi->ivtvfb_defined.yres_virtual = oi->display_height;
1004 oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
1005 oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
1006 oi->ivtvfb_defined.left_margin = start_window.left + 1;
1007 oi->ivtvfb_defined.upper_margin = start_window.top + 1;
1008 oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
1009 oi->ivtvfb_defined.nonstd = 0;
1010
1011
1012
1013 _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
1014
1015
1016
1017 ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
1018
1019
1020
1021 oi->ivtvfb_info.node = -1;
1022 oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
1023 oi->ivtvfb_info.fbops = &ivtvfb_ops;
1024 oi->ivtvfb_info.par = itv;
1025 oi->ivtvfb_info.var = oi->ivtvfb_defined;
1026 oi->ivtvfb_info.fix = oi->ivtvfb_fix;
1027 oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
1028 oi->ivtvfb_info.fbops = &ivtvfb_ops;
1029
1030
1031 oi->ivtvfb_info.monspecs.hfmin = 8000;
1032 oi->ivtvfb_info.monspecs.hfmax = 70000;
1033 oi->ivtvfb_info.monspecs.vfmin = 10;
1034 oi->ivtvfb_info.monspecs.vfmax = 100;
1035
1036
1037 if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
1038 IVTVFB_ERR("abort, unable to alloc cmap\n");
1039 return -ENOMEM;
1040 }
1041
1042
1043 oi->ivtvfb_info.pseudo_palette =
1044 kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN);
1045
1046 if (!oi->ivtvfb_info.pseudo_palette) {
1047 IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
1048 return -ENOMEM;
1049 }
1050
1051 return 0;
1052}
1053
1054
1055
1056static int ivtvfb_init_io(struct ivtv *itv)
1057{
1058 struct osd_info *oi = itv->osd_info;
1059
1060 mutex_lock(&itv->serialize_lock);
1061 if (ivtv_init_on_first_open(itv)) {
1062 mutex_unlock(&itv->serialize_lock);
1063 IVTVFB_ERR("Failed to initialize ivtv\n");
1064 return -ENXIO;
1065 }
1066 mutex_unlock(&itv->serialize_lock);
1067
1068 ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
1069
1070
1071
1072
1073 oi->video_buffer_size = 1704960;
1074
1075 oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1076 oi->video_vbase = itv->dec_mem + oi->video_rbase;
1077
1078 if (!oi->video_vbase) {
1079 IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1080 oi->video_buffer_size, oi->video_pbase);
1081 return -EIO;
1082 }
1083
1084 IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1085 oi->video_pbase, oi->video_vbase,
1086 oi->video_buffer_size / 1024);
1087
1088#ifdef CONFIG_MTRR
1089 {
1090
1091 int size_shift = 31;
1092
1093 while (!(oi->video_buffer_size & (1 << size_shift))) {
1094 size_shift--;
1095 }
1096 size_shift++;
1097 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1098 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1099 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1100 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1101 if (mtrr_add(oi->fb_start_aligned_physaddr,
1102 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
1103 MTRR_TYPE_WRCOMB, 1) < 0) {
1104 IVTVFB_INFO("disabled mttr\n");
1105 oi->fb_start_aligned_physaddr = 0;
1106 oi->fb_end_aligned_physaddr = 0;
1107 }
1108 }
1109#endif
1110
1111
1112 memset_io(oi->video_vbase, 0, oi->video_buffer_size);
1113
1114 return 0;
1115}
1116
1117
1118static void ivtvfb_release_buffers (struct ivtv *itv)
1119{
1120 struct osd_info *oi = itv->osd_info;
1121
1122
1123 if (oi->ivtvfb_info.cmap.len)
1124 fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
1125
1126
1127 if (oi->ivtvfb_info.pseudo_palette)
1128 kfree(oi->ivtvfb_info.pseudo_palette);
1129
1130#ifdef CONFIG_MTRR
1131 if (oi->fb_end_aligned_physaddr) {
1132 mtrr_del(-1, oi->fb_start_aligned_physaddr,
1133 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1134 }
1135#endif
1136
1137 kfree(oi);
1138 itv->osd_info = NULL;
1139}
1140
1141
1142
1143static int ivtvfb_init_card(struct ivtv *itv)
1144{
1145 int rc;
1146
1147 if (itv->osd_info) {
1148 IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
1149 return -EBUSY;
1150 }
1151
1152 itv->osd_info = kzalloc(sizeof(struct osd_info),
1153 GFP_ATOMIC|__GFP_NOWARN);
1154 if (itv->osd_info == NULL) {
1155 IVTVFB_ERR("Failed to allocate memory for osd_info\n");
1156 return -ENOMEM;
1157 }
1158
1159
1160 if ((rc = ivtvfb_init_io(itv)))
1161 return rc;
1162
1163
1164 if ((rc = ivtvfb_init_vidmode(itv))) {
1165 ivtvfb_release_buffers(itv);
1166 return rc;
1167 }
1168
1169
1170 if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1171 ivtvfb_release_buffers(itv);
1172 return -EINVAL;
1173 }
1174
1175 itv->osd_video_pbase = itv->osd_info->video_pbase;
1176
1177
1178 ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1179
1180
1181 write_reg(0, 0x02a30);
1182 write_reg(0, 0x02a34);
1183
1184
1185 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1186
1187
1188 ivtv_udma_alloc(itv);
1189 return 0;
1190
1191}
1192
1193static int __init ivtvfb_callback_init(struct device *dev, void *p)
1194{
1195 struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
1196 struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
1197
1198 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1199 if (ivtvfb_init_card(itv) == 0) {
1200 IVTVFB_INFO("Framebuffer registered on %s\n",
1201 itv->v4l2_dev.name);
1202 (*(int *)p)++;
1203 }
1204 }
1205 return 0;
1206}
1207
1208static int ivtvfb_callback_cleanup(struct device *dev, void *p)
1209{
1210 struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
1211 struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
1212
1213 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1214 if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
1215 IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
1216 itv->instance);
1217 return 0;
1218 }
1219 IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
1220 ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
1221 ivtvfb_release_buffers(itv);
1222 itv->osd_video_pbase = 0;
1223 }
1224 return 0;
1225}
1226
1227static int __init ivtvfb_init(void)
1228{
1229 struct device_driver *drv;
1230 int registered = 0;
1231 int err;
1232
1233 if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
1234 printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
1235 IVTV_MAX_CARDS - 1);
1236 return -EINVAL;
1237 }
1238
1239 drv = driver_find("ivtv", &pci_bus_type);
1240 err = driver_for_each_device(drv, NULL, ®istered, ivtvfb_callback_init);
1241 put_driver(drv);
1242 if (!registered) {
1243 printk(KERN_ERR "ivtvfb: no cards found\n");
1244 return -ENODEV;
1245 }
1246 return 0;
1247}
1248
1249static void ivtvfb_cleanup(void)
1250{
1251 struct device_driver *drv;
1252 int err;
1253
1254 printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n");
1255
1256 drv = driver_find("ivtv", &pci_bus_type);
1257 err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
1258 put_driver(drv);
1259}
1260
1261module_init(ivtvfb_init);
1262module_exit(ivtvfb_cleanup);
1263