/*! * Shut down the voutera * * @param vout structure vout_data * * * @return status 0 Success */ static int mxc_v4l2out_streamoff(vout_data * vout) { int i, retval = 0; unsigned long lock_flag = 0; if (!vout) return -EINVAL; if (vout->state == STATE_STREAM_OFF) { return 0; } spin_lock_irqsave(&g_lock, lock_flag); del_timer(&vout->output_timer); pp_enable(0); /* Disable PP */ if (vout->state == STATE_STREAM_ON) { vout->state = STATE_STREAM_STOPPING; } spin_unlock_irqrestore(&g_lock, lock_flag); vout->ready_q.head = vout->ready_q.tail = 0; vout->done_q.head = vout->done_q.tail = 0; for (i = 0; i < vout->buffer_cnt; i++) { vout->v4l2_bufs[i].flags = 0; vout->v4l2_bufs[i].timestamp.tv_sec = 0; vout->v4l2_bufs[i].timestamp.tv_usec = 0; } vout->state = STATE_STREAM_OFF; if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) { struct fb_gwinfo gwinfo; /* Disable graphic window */ gwinfo.enabled = 0; mx2_gw_set(&gwinfo); } #ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC if (vout->tear_protection == TEARING_PROTECTION_ACTIVE) { g_output_fb = -1; g_fb_enabled = 0; g_pp_ready = 0; fb_unregister_client(&fb_event_notifier); mx2fb_unregister_client(&mx2fb_event_notifier); } #endif mxc_free_buffers(vout->display_bufs, vout->display_bufs_vaddr, 2, vout->sdc_fg_buf_size); return retval; }
/*! * @brief Enable graphic window. * @param info framebuffer information pointer */ static void _enable_graphic_window(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; g_gwinfo.enabled = 1; g_gwinfo.base = (var->yoffset * var->xres_virtual + var->xoffset); g_gwinfo.base *= (var->bits_per_pixel) / 8; g_gwinfo.base += info->fix.smem_start; g_gwinfo.xres = var->xres; g_gwinfo.yres = var->yres; g_gwinfo.xres_virtual = var->xres_virtual; mx2_gw_set(&g_gwinfo); }
irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id) { int last_buf; int index; unsigned long timeout; unsigned long lock_flags; vout_data *vout = dev_id; spin_lock_irqsave(&g_lock, lock_flags); g_irq_cnt++; if ((vout->state == STATE_STREAM_OFF) || (vout->state == STATE_STREAM_STOPPING)) { spin_unlock_irqrestore(&g_lock, lock_flags); return IRQ_HANDLED; } if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) { struct fb_gwinfo gwinfo; gwinfo.enabled = 1; gwinfo.alpha_value = 255; gwinfo.ck_enabled = 0; gwinfo.xpos = vout->crop_current.left; gwinfo.ypos = vout->crop_current.top; gwinfo.base = (unsigned long)vout->display_bufs[pp_num_last()]; gwinfo.xres = vout->crop_current.width; gwinfo.yres = vout->crop_current.height; gwinfo.xres_virtual = vout->crop_current.width; gwinfo.vs_reversed = 0; mx2_gw_set(&gwinfo); } /* Process previous buffer */ last_buf = vout->ipu_buf[0]; pr_debug("last_buf %d g_irq_cnt %d\n", last_buf, g_irq_cnt); if (last_buf != -1) { g_buf_output_cnt++; vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE; queue_buf(&vout->done_q, last_buf); vout->ipu_buf[0] = -1; wake_up_interruptible(&vout->v4l_bufq); } /* Setup timer for next buffer, when stream has been paused */ if ((vout->state == STATE_STREAM_PAUSED) && ((index = peek_next_buf(&vout->ready_q)) != -1)) { pr_debug("next index %d\n", index); /* if timestamp is 0, then default to 30fps */ if ((vout->v4l2_bufs[index].timestamp.tv_sec == 0) && (vout->v4l2_bufs[index].timestamp.tv_usec == 0)) timeout = vout->start_jiffies + vout->frame_count * HZ / 30; else timeout = get_jiffies(&vout->v4l2_bufs[index].timestamp); if (jiffies >= timeout) { pr_debug("warning: timer timeout already expired.\n"); } vout->state = STATE_STREAM_ON; if (mod_timer(&vout->output_timer, timeout)) pr_debug("warning: timer was already set\n"); pr_debug("timer handler next schedule: %lu\n", timeout); } spin_unlock_irqrestore(&g_lock, lock_flags); return IRQ_HANDLED; }