📄 ivtvfb.c
字号:
itv->yuv_info.yuv_forced_update = 1; return 0;}static int ivtvfb_set_par(struct fb_info *info){ int rc = 0; struct ivtv *itv = (struct ivtv *) info->par; IVTVFB_DEBUG_INFO("ivtvfb_set_par\n"); rc = ivtvfb_set_var(itv, &info->var); ivtvfb_pan_display(&info->var, info); ivtvfb_get_fix(itv, &info->fix); return rc;}static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info){ u32 color, *palette; struct ivtv *itv = (struct ivtv *)info->par; if (regno >= info->cmap.len) return -EINVAL; color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); if (info->var.bits_per_pixel <= 8) { write_reg(regno, 0x02a30); write_reg(color, 0x02a34); return 0; } if (regno >= 16) return -EINVAL; palette = info->pseudo_palette; if (info->var.bits_per_pixel == 16) { switch (info->var.green.length) { case 4: color = ((red & 0xf000) >> 4) | ((green & 0xf000) >> 8) | ((blue & 0xf000) >> 12); break; case 5: color = ((red & 0xf800) >> 1) | ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11); break; case 6: color = (red & 0xf800 ) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); break; } } palette[regno] = color; return 0;}/* We don't really support blanking. All this does is enable or disable the OSD. */static int ivtvfb_blank(int blank_mode, struct fb_info *info){ struct ivtv *itv = (struct ivtv *)info->par; IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode); switch (blank_mode) { case FB_BLANK_UNBLANK: ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1); ivtv_saa7127(itv, VIDIOC_STREAMON, NULL); break; case FB_BLANK_NORMAL: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_VSYNC_SUSPEND: ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); ivtv_saa7127(itv, VIDIOC_STREAMON, NULL); break; case FB_BLANK_POWERDOWN: ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL); ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0); break; } return 0;}static struct fb_ops ivtvfb_ops = { .owner = THIS_MODULE, .fb_write = ivtvfb_write, .fb_check_var = ivtvfb_check_var, .fb_set_par = ivtvfb_set_par, .fb_setcolreg = ivtvfb_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_cursor = NULL, .fb_ioctl = ivtvfb_ioctl, .fb_pan_display = ivtvfb_pan_display, .fb_blank = ivtvfb_blank,};/* Initialization *//* Setup our initial video mode */static int ivtvfb_init_vidmode(struct ivtv *itv){ struct osd_info *oi = itv->osd_info; struct v4l2_rect start_window; int max_height; /* Color mode */ if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8; oi->bits_per_pixel = osd_depth; oi->bytes_per_pixel = oi->bits_per_pixel / 8; /* Horizontal size & position */ if (osd_xres > 720) osd_xres = 720; /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */ if (osd_depth == 8) osd_xres &= ~3; else if (osd_depth == 16) osd_xres &= ~1; start_window.width = osd_xres ? osd_xres : 640; /* Check horizontal start (osd_left). */ if (osd_left && osd_left + start_window.width > 721) { IVTVFB_ERR("Invalid osd_left - assuming default\n"); osd_left = 0; } /* Hardware coords start at 0, user coords start at 1. */ osd_left--; start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2); oi->display_byte_stride = start_window.width * oi->bytes_per_pixel; /* Vertical size & position */ max_height = itv->is_50hz ? 576 : 480; if (osd_yres > max_height) osd_yres = max_height; start_window.height = osd_yres ? osd_yres : itv->is_50hz ? 480 : 400; /* Check vertical start (osd_upper). */ if (osd_upper + start_window.height > max_height + 1) { IVTVFB_ERR("Invalid osd_upper - assuming default\n"); osd_upper = 0; } /* Hardware coords start at 0, user coords start at 1. */ osd_upper--; start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2); oi->display_width = start_window.width; oi->display_height = start_window.height; /* Generate a valid fb_var_screeninfo */ oi->ivtvfb_defined.xres = oi->display_width; oi->ivtvfb_defined.yres = oi->display_height; oi->ivtvfb_defined.xres_virtual = oi->display_width; oi->ivtvfb_defined.yres_virtual = oi->display_height; oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel; oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED); oi->ivtvfb_defined.left_margin = start_window.left + 1; oi->ivtvfb_defined.upper_margin = start_window.top + 1; oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE; oi->ivtvfb_defined.nonstd = 0; /* We've filled in the most data, let the usual mode check routine fill in the rest. */ _ivtvfb_check_var(&oi->ivtvfb_defined, itv); /* Generate valid fb_fix_screeninfo */ ivtvfb_get_fix(itv, &oi->ivtvfb_fix); /* Generate valid fb_info */ oi->ivtvfb_info.node = -1; oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT; oi->ivtvfb_info.fbops = &ivtvfb_ops; oi->ivtvfb_info.par = itv; oi->ivtvfb_info.var = oi->ivtvfb_defined; oi->ivtvfb_info.fix = oi->ivtvfb_fix; oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase; oi->ivtvfb_info.fbops = &ivtvfb_ops; /* Supply some monitor specs. Bogus values will do for now */ oi->ivtvfb_info.monspecs.hfmin = 8000; oi->ivtvfb_info.monspecs.hfmax = 70000; oi->ivtvfb_info.monspecs.vfmin = 10; oi->ivtvfb_info.monspecs.vfmax = 100; /* Allocate color map */ if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) { IVTVFB_ERR("abort, unable to alloc cmap\n"); return -ENOMEM; } /* Allocate the pseudo palette */ oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN); if (!oi->ivtvfb_info.pseudo_palette) { IVTVFB_ERR("abort, unable to alloc pseudo pallete\n"); return -ENOMEM; } return 0;}/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */static int ivtvfb_init_io(struct ivtv *itv){ struct osd_info *oi = itv->osd_info; mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) { mutex_unlock(&itv->serialize_lock); IVTVFB_ERR("Failed to initialize ivtv\n"); return -ENXIO; } mutex_unlock(&itv->serialize_lock); ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size); /* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer size to prevent any overlap. */ oi->video_buffer_size = 1704960; oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase; oi->video_vbase = itv->dec_mem + oi->video_rbase; if (!oi->video_vbase) { IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n", oi->video_buffer_size, oi->video_pbase); return -EIO; } IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", oi->video_pbase, oi->video_vbase, oi->video_buffer_size / 1024);#ifdef CONFIG_MTRR { /* Find the largest power of two that maps the whole buffer */ int size_shift = 31; while (!(oi->video_buffer_size & (1 << size_shift))) { size_shift--; } size_shift++; oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); if (mtrr_add(oi->fb_start_aligned_physaddr, oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, MTRR_TYPE_WRCOMB, 1) < 0) { IVTVFB_INFO("disabled mttr\n"); oi->fb_start_aligned_physaddr = 0; oi->fb_end_aligned_physaddr = 0; } }#endif /* Blank the entire osd. */ memset_io(oi->video_vbase, 0, oi->video_buffer_size); return 0;}/* Release any memory we've grabbed & remove mtrr entry */static void ivtvfb_release_buffers (struct ivtv *itv){ struct osd_info *oi = itv->osd_info; /* Release cmap */ if (oi->ivtvfb_info.cmap.len) fb_dealloc_cmap(&oi->ivtvfb_info.cmap); /* Release pseudo palette */ if (oi->ivtvfb_info.pseudo_palette) kfree(oi->ivtvfb_info.pseudo_palette);#ifdef CONFIG_MTRR if (oi->fb_end_aligned_physaddr) { mtrr_del(-1, oi->fb_start_aligned_physaddr, oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); }#endif kfree(oi); itv->osd_info = NULL;}/* Initialize the specified card */static int ivtvfb_init_card(struct ivtv *itv){ int rc; if (itv->osd_info) { IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id); return -EBUSY; } itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC|__GFP_NOWARN); if (itv->osd_info == NULL) { IVTVFB_ERR("Failed to allocate memory for osd_info\n"); return -ENOMEM; } /* Find & setup the OSD buffer */ if ((rc = ivtvfb_init_io(itv))) return rc; /* Set the startup video mode information */ if ((rc = ivtvfb_init_vidmode(itv))) { ivtvfb_release_buffers(itv); return rc; } /* Register the framebuffer */ if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) { ivtvfb_release_buffers(itv); return -EINVAL; } itv->osd_video_pbase = itv->osd_info->video_pbase; /* Set the card to the requested mode */ ivtvfb_set_par(&itv->osd_info->ivtvfb_info); /* Set color 0 to black */ write_reg(0, 0x02a30); write_reg(0, 0x02a34); /* Enable the osd */ ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info); /* Allocate DMA */ ivtv_udma_alloc(itv); return 0;}static int __init ivtvfb_init(void){ struct ivtv *itv; int i, registered = 0; if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) { printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n", IVTV_MAX_CARDS - 1); return -EINVAL; } /* Locate & initialise all cards supporting an OSD. */ for (i = 0; i < ivtv_cards_active; i++) { if (ivtvfb_card_id != -1 && i != ivtvfb_card_id) continue; itv = ivtv_cards[i]; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { if (ivtvfb_init_card(itv) == 0) { IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i); registered++; } } } if (!registered) { printk(KERN_ERR "ivtvfb: no cards found"); return -ENODEV; } return 0;}static void ivtvfb_cleanup(void){ struct ivtv *itv; int i; printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n"); for (i = 0; i < ivtv_cards_active; i++) { itv = ivtv_cards[i]; if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) { if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) { IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", i); return; } IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i); ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info); ivtvfb_release_buffers(itv); itv->osd_video_pbase = 0; } }}module_init(ivtvfb_init);module_exit(ivtvfb_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -