📄 ivtv-yuv.c
字号:
window->src_h &= ~3; window->dst_h = window->src_h / 4; window->dst_h += window->dst_h & 1; } /* Check again. If there's nothing to safe to display, stop now */ if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { return IVTV_YUV_UPDATE_INVALID; } /* Both x offset & width are linked, so they have to be done together */ if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) || (itv->yuv_info.old_frame_info.src_w != window->src_w) || (itv->yuv_info.old_frame_info.dst_x != window->dst_x) || (itv->yuv_info.old_frame_info.src_x != window->src_x) || (itv->yuv_info.old_frame_info.pan_x != window->pan_x) || (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) { yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; } if ((itv->yuv_info.old_frame_info.src_h != window->src_h) || (itv->yuv_info.old_frame_info.dst_h != window->dst_h) || (itv->yuv_info.old_frame_info.dst_y != window->dst_y) || (itv->yuv_info.old_frame_info.src_y != window->src_y) || (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) || (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { yuv_update |= IVTV_YUV_UPDATE_VERTICAL; } return yuv_update;}/* Update the scaling register to the requested value */void ivtv_yuv_work_handler (struct ivtv *itv){ struct yuv_frame_info window; u32 yuv_update; int frame = itv->yuv_info.update_frame;/* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */ memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window)); /* Update the osd pan info */ window.pan_x = itv->yuv_info.osd_x_pan; window.pan_y = itv->yuv_info.osd_y_pan; window.vis_w = itv->yuv_info.osd_vis_w; window.vis_h = itv->yuv_info.osd_vis_h; /* Calculate the display window coordinates. Exit if nothing left */ if (!(yuv_update = ivtv_yuv_window_setup (itv, &window))) return; if (yuv_update & IVTV_YUV_UPDATE_INVALID) { write_reg(0x01008080, 0x2898); } else if (yuv_update) { write_reg(0x00108080, 0x2898); if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) ivtv_yuv_handle_horizontal(itv, &window); if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) ivtv_yuv_handle_vertical(itv, &window); } memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));}static void ivtv_yuv_init (struct ivtv *itv){ struct yuv_playback_info *yi = &itv->yuv_info; IVTV_DEBUG_YUV("ivtv_yuv_init\n"); /* Take a snapshot of the current register settings */ yi->reg_2834 = read_reg(0x02834); yi->reg_2838 = read_reg(0x02838); yi->reg_283c = read_reg(0x0283c); yi->reg_2840 = read_reg(0x02840); yi->reg_2844 = read_reg(0x02844); yi->reg_2848 = read_reg(0x02848); yi->reg_2854 = read_reg(0x02854); yi->reg_285c = read_reg(0x0285c); yi->reg_2864 = read_reg(0x02864); yi->reg_2870 = read_reg(0x02870); yi->reg_2874 = read_reg(0x02874); yi->reg_2898 = read_reg(0x02898); yi->reg_2890 = read_reg(0x02890); yi->reg_289c = read_reg(0x0289c); yi->reg_2918 = read_reg(0x02918); yi->reg_291c = read_reg(0x0291c); yi->reg_2920 = read_reg(0x02920); yi->reg_2924 = read_reg(0x02924); yi->reg_2928 = read_reg(0x02928); yi->reg_292c = read_reg(0x0292c); yi->reg_2930 = read_reg(0x02930); yi->reg_2934 = read_reg(0x02934); yi->reg_2938 = read_reg(0x02938); yi->reg_293c = read_reg(0x0293c); yi->reg_2940 = read_reg(0x02940); yi->reg_2944 = read_reg(0x02944); yi->reg_2948 = read_reg(0x02948); yi->reg_294c = read_reg(0x0294c); yi->reg_2950 = read_reg(0x02950); yi->reg_2954 = read_reg(0x02954); yi->reg_2958 = read_reg(0x02958); yi->reg_295c = read_reg(0x0295c); yi->reg_2960 = read_reg(0x02960); yi->reg_2964 = read_reg(0x02964); yi->reg_2968 = read_reg(0x02968); yi->reg_296c = read_reg(0x0296c); yi->reg_2970 = read_reg(0x02970); yi->v_filter_1 = -1; yi->v_filter_2 = -1; yi->h_filter = -1; /* Set some valid size info */ yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF; yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF; /* Bit 2 of reg 2878 indicates current decoder output format 0 : NTSC 1 : PAL */ if (read_reg(0x2878) & 4) yi->decode_height = 576; else yi->decode_height = 480; if (!itv->osd_info) { yi->osd_vis_w = 720 - yi->osd_x_offset; yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; } else { /* If no visible size set, assume full size */ if (!yi->osd_vis_w) yi->osd_vis_w = 720 - yi->osd_x_offset; if (!yi->osd_vis_h) yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; else { /* If output video standard has changed, requested height may not be legal */ if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", yi->osd_vis_h + yi->osd_y_offset, yi->decode_height); yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; } } } /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL); if (yi->blanking_ptr) yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); else { yi->blanking_dmaptr = 0; IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); } /* Enable YUV decoder output */ write_reg_sync(0x01, IVTV_REG_VDM); set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); atomic_set(&yi->next_dma_frame, 0);}int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args){ DEFINE_WAIT(wait); int rc = 0; int got_sig = 0; int frame, next_fill_frame, last_fill_frame; int register_update = 0; IVTV_DEBUG_INFO("yuv_prep_frame\n"); if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv); frame = atomic_read(&itv->yuv_info.next_fill_frame); next_fill_frame = (frame + 1) & 0x3; last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3; if (next_fill_frame != last_fill_frame && last_fill_frame != frame) { /* Buffers are full - Overwrite the last frame */ next_fill_frame = frame; frame = (frame - 1) & 3; register_update = itv->yuv_info.new_frame_info[frame].update; } /* Take a snapshot of the yuv coordinate information */ itv->yuv_info.new_frame_info[frame].src_x = args->src.left; itv->yuv_info.new_frame_info[frame].src_y = args->src.top; itv->yuv_info.new_frame_info[frame].src_w = args->src.width; itv->yuv_info.new_frame_info[frame].src_h = args->src.height; itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left; itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top; itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width; itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height; itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left; itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; /* Snapshot field order */ itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field; /* Are we going to offset the Y plane */ if (args->src.height + args->src.top < 512-16) itv->yuv_info.new_frame_info[frame].offset_y = 1; else itv->yuv_info.new_frame_info[frame].offset_y = 0; /* Snapshot the osd pan info */ itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan; itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan; itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w; itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h; itv->yuv_info.new_frame_info[frame].update = 0; itv->yuv_info.new_frame_info[frame].interlaced_y = 0; itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.new_frame_info[frame]))) { memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args)); itv->yuv_info.new_frame_info[frame].update = 1;/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ } itv->yuv_info.new_frame_info[frame].update |= register_update; /* Should this frame be delayed ? */ if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) itv->yuv_info.field_delay[frame] = 1; else itv->yuv_info.field_delay[frame] = 0; /* DMA the frame */ mutex_lock(&itv->udma.lock); if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) { mutex_unlock(&itv->udma.lock); return rc; } ivtv_udma_prepare(itv); prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); /* if no UDMA is pending and no UDMA is in progress, then the DMA is finished */ while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { /* don't interrupt if the DMA is in progress but break off a still pending DMA. */ got_sig = signal_pending(current); if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) break; got_sig = 0; schedule(); } finish_wait(&itv->dma_waitq, &wait); /* Unmap Last DMA Xfer */ ivtv_udma_unmap(itv); if (got_sig) { IVTV_DEBUG_INFO("User stopped YUV UDMA\n"); mutex_unlock(&itv->udma.lock); return -EINTR; } atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame); mutex_unlock(&itv->udma.lock); return rc;}void ivtv_yuv_close(struct ivtv *itv){ int h_filter, v_filter_1, v_filter_2; IVTV_DEBUG_YUV("ivtv_yuv_close\n"); ivtv_waitq(&itv->vsync_waitq); atomic_set(&itv->yuv_info.next_dma_frame, -1); atomic_set(&itv->yuv_info.next_fill_frame, 0); /* Reset registers we have changed so mpeg playback works */ /* If we fully restore this register, the display may remain active. Restore, but set one bit to blank the video. Firmware will always clear this bit when needed, so not a problem. */ write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898); write_reg(itv->yuv_info.reg_2834, 0x02834); write_reg(itv->yuv_info.reg_2838, 0x02838); write_reg(itv->yuv_info.reg_283c, 0x0283c); write_reg(itv->yuv_info.reg_2840, 0x02840); write_reg(itv->yuv_info.reg_2844, 0x02844); write_reg(itv->yuv_info.reg_2848, 0x02848); write_reg(itv->yuv_info.reg_2854, 0x02854); write_reg(itv->yuv_info.reg_285c, 0x0285c); write_reg(itv->yuv_info.reg_2864, 0x02864); write_reg(itv->yuv_info.reg_2870, 0x02870); write_reg(itv->yuv_info.reg_2874, 0x02874); write_reg(itv->yuv_info.reg_2890, 0x02890); write_reg(itv->yuv_info.reg_289c, 0x0289c); write_reg(itv->yuv_info.reg_2918, 0x02918); write_reg(itv->yuv_info.reg_291c, 0x0291c); write_reg(itv->yuv_info.reg_2920, 0x02920); write_reg(itv->yuv_info.reg_2924, 0x02924); write_reg(itv->yuv_info.reg_2928, 0x02928); write_reg(itv->yuv_info.reg_292c, 0x0292c); write_reg(itv->yuv_info.reg_2930, 0x02930); write_reg(itv->yuv_info.reg_2934, 0x02934); write_reg(itv->yuv_info.reg_2938, 0x02938); write_reg(itv->yuv_info.reg_293c, 0x0293c); write_reg(itv->yuv_info.reg_2940, 0x02940); write_reg(itv->yuv_info.reg_2944, 0x02944); write_reg(itv->yuv_info.reg_2948, 0x02948); write_reg(itv->yuv_info.reg_294c, 0x0294c); write_reg(itv->yuv_info.reg_2950, 0x02950); write_reg(itv->yuv_info.reg_2954, 0x02954); write_reg(itv->yuv_info.reg_2958, 0x02958); write_reg(itv->yuv_info.reg_295c, 0x0295c); write_reg(itv->yuv_info.reg_2960, 0x02960); write_reg(itv->yuv_info.reg_2964, 0x02964); write_reg(itv->yuv_info.reg_2968, 0x02968); write_reg(itv->yuv_info.reg_296c, 0x0296c); write_reg(itv->yuv_info.reg_2970, 0x02970); /* Prepare to restore filters */ /* First the horizontal filter */ if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) { /* An exact size match uses filter 0 */ h_filter = 0; } else { /* Figure out which filter to use */ h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15; h_filter = (h_filter >> 1) + (h_filter & 1); /* Only an exact size match can use filter 0. */ if (h_filter < 1) h_filter = 1; } /* Now the vertical filter */ if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) { /* An exact size match uses filter 0/1 */ v_filter_1 = 0; v_filter_2 = 1; } else { /* Figure out which filter to use */ v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15; v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); /* Only an exact size match can use filter 0 */ if (v_filter_1 == 0) v_filter_1 = 1; v_filter_2 = v_filter_1; } /* Now restore the filters */ ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2); /* and clear a few registers */ write_reg(0, 0x02814); write_reg(0, 0x0282c); write_reg(0, 0x02904); write_reg(0, 0x02910); /* Release the blanking buffer */ if (itv->yuv_info.blanking_ptr) { kfree (itv->yuv_info.blanking_ptr); itv->yuv_info.blanking_ptr = NULL; pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); } /* Invalidate the old dimension information */ itv->yuv_info.old_frame_info.src_w = 0; itv->yuv_info.old_frame_info.src_h = 0; itv->yuv_info.old_frame_info_args.src_w = 0; itv->yuv_info.old_frame_info_args.src_h = 0; /* All done. */ clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -