summaryrefslogtreecommitdiff
path: root/drivers/media/video/mxc/capture/mx27_v4l2_capture.c
diff options
context:
space:
mode:
authorQuinn Jensen <quinn.jensen@freescale.com>2007-10-24 21:27:32 -0600
committerQuinn Jensen <quinn.jensen@freescale.com>2007-10-24 21:27:32 -0600
commit04d61c58040f259b08e5170d62e2fb49ae8fd19b (patch)
treee1ab1a95a9f8c27741533ec0fcee94743329763c /drivers/media/video/mxc/capture/mx27_v4l2_capture.c
parent9e4175807497c24b82d5866076d8c7c80cdd5a94 (diff)
Bugzilla 605. Fix tearing when VPU rotates images.2.6.22-mx27ads-2007102503272.6.22-mx27-200710250327
Patch for Bugzilla 605. Fix tearing when VPU rotates images. A diagonal line appears when the VPU rotates the picture, at the encode stage. The PRP driver updates the buffer addresses while the PRP is processing data. Applies to linux 2.6.22 kernel for MX27 platform. http://www.bitshrine.org/gpp/linux-2.6.22-mx-Bugzilla-605.-Fix-tearing-when-VPU-rotates.patch
Diffstat (limited to 'drivers/media/video/mxc/capture/mx27_v4l2_capture.c')
-rw-r--r--drivers/media/video/mxc/capture/mx27_v4l2_capture.c151
1 files changed, 82 insertions, 69 deletions
diff --git a/drivers/media/video/mxc/capture/mx27_v4l2_capture.c b/drivers/media/video/mxc/capture/mx27_v4l2_capture.c
index d6d91bda3e98..7d92fbfaa333 100644
--- a/drivers/media/video/mxc/capture/mx27_v4l2_capture.c
+++ b/drivers/media/video/mxc/capture/mx27_v4l2_capture.c
@@ -44,10 +44,52 @@ static int video_nr = -1;
cam_data *g_cam;
EXPORT_SYMBOL(g_cam);
-static int dq_intr_cnt=0;
-static int dq_timeout_cnt=0;
-static int empty_wq_cnt=0;
+static int dq_intr_cnt = 0;
+static int dq_timeout_cnt = 0;
+static int empty_wq_cnt = 0;
+struct workqueue_struct *v4l2_work;
+static void prp_reset(struct work_struct *unused)
+{
+ struct mxc_v4l_frame *done_frame, *ready_frame, *temp_frame;
+
+ g_cam->ping_pong_csi = 0;
+ g_cam->enc_enable(g_cam);
+ if (!list_empty(&g_cam->working_q)) {
+ done_frame =
+ list_entry(g_cam->working_q.next, struct mxc_v4l_frame,
+ queue);
+ list_del(g_cam->working_q.next);
+ if (!list_empty(&g_cam->working_q)) {
+ temp_frame =
+ list_entry(g_cam->working_q.next,
+ struct mxc_v4l_frame, queue);
+ list_del(g_cam->working_q.next);
+ list_add_tail(&temp_frame->queue, &g_cam->working_q);
+ g_cam->enc_update_eba(temp_frame->paddress,
+ &g_cam->ping_pong_csi);
+ }
+ list_add_tail(&done_frame->queue, &g_cam->working_q);
+ g_cam->enc_update_eba(done_frame->paddress,
+ &g_cam->ping_pong_csi);
+ pr_debug("prp_reset - working_q\n");
+ } else if (list_empty(&g_cam->ready_q)) {
+ prphw_disable(PRP_CHANNEL_2);
+ g_cam->skip_frame++;
+ } else {
+ ready_frame =
+ list_entry(g_cam->ready_q.next, struct mxc_v4l_frame,
+ queue);
+ list_del(g_cam->ready_q.next);
+ list_add_tail(&ready_frame->queue, &g_cam->working_q);
+ g_cam->enc_update_eba(ready_frame->paddress,
+ &g_cam->ping_pong_csi);
+ }
+ g_cam->overflow = 0;
+ wake_up_interruptible(&g_cam->overflow_queue);
+}
+
+DECLARE_WORK(prp_reset_work, prp_reset);
/*!
* Free frame buffers
*
@@ -184,6 +226,7 @@ static int mxc_streamon(cam_data * cam)
}
cam->ping_pong_csi = 0;
+ cam->overflow = 0;
if (cam->enc_update_eba) {
frame =
list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
@@ -684,66 +727,23 @@ static int mxc_v4l_dqueue(cam_data * cam, struct v4l2_buffer *buf)
int retval = 0;
struct mxc_v4l_frame *frame;
- cont:
if (!wait_event_interruptible_timeout(cam->enc_queue,
cam->enc_counter != 0, 10 * HZ)) {
- if( (dq_timeout_cnt & 0x1f) == 0)
- printk(KERN_ERR "mxc_v4l_dqueue timeout enc_counter %x\n",
+ if ((dq_timeout_cnt & 0x1f) == 0)
+ printk(KERN_ERR
+ "mxc_v4l_dqueue timeout enc_counter %x\n",
cam->enc_counter);
dq_timeout_cnt++;
- if (cam->overflow == 1) {
- cam->enc_enable(cam);
- cam->overflow = 0;
- if (!list_empty(&cam->ready_q)) {
- frame =
- list_entry(cam->ready_q.next,
- struct mxc_v4l_frame, queue);
- list_del(cam->ready_q.next);
- list_add_tail(&frame->queue, &cam->working_q);
- cam->enc_update_eba(frame->paddress,
- &cam->ping_pong_csi);
- }
- goto cont;
- }
return -ETIME;
} else if (signal_pending(current)) {
- if(dq_intr_cnt == 0)
- printk(KERN_ERR "mxc_v4l_dqueue() interrupt received %d\n",dq_intr_cnt);
- dq_intr_cnt++;
- if (cam->overflow == 1) {
- cam->enc_enable(cam);
- cam->overflow = 0;
- if (!list_empty(&cam->ready_q)) {
- frame =
- list_entry(cam->ready_q.next,
- struct mxc_v4l_frame, queue);
- list_del(cam->ready_q.next);
- list_add_tail(&frame->queue, &cam->working_q);
- cam->enc_update_eba(frame->paddress,
- &cam->ping_pong_csi);
- }
- goto cont;
- }
+ if (dq_intr_cnt == 0)
+ printk(KERN_ERR
+ "mxc_v4l_dqueue() interrupt received %d\n",
+ dq_intr_cnt);
+ dq_intr_cnt++;
return -ERESTARTSYS;
}
- if (cam->overflow == 1) {
- cam->enc_enable(cam);
- cam->overflow = 0;
- if (!list_empty(&cam->ready_q)) {
- frame =
- list_entry(cam->ready_q.next, struct mxc_v4l_frame,
- queue);
- list_del(cam->ready_q.next);
- list_add_tail(&frame->queue, &cam->working_q);
- cam->enc_update_eba(frame->paddress,
- &cam->ping_pong_csi);
- }
- printk(KERN_INFO "mxc_v4l_dqueue - overflow\n");
-
- }
-
-
cam->enc_counter--;
frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue);
@@ -801,9 +801,9 @@ static int mxc_v4l_open(struct inode *inode, struct file *file)
cam_data *cam = dev->priv;
int err = 0;
- dq_intr_cnt = 0;
+ dq_intr_cnt = 0;
dq_timeout_cnt = 0;
- empty_wq_cnt = 0;
+ empty_wq_cnt = 0;
if (!cam) {
pr_info("Internal error, cam_data not found!\n");
return -ENODEV;
@@ -890,6 +890,7 @@ static int mxc_v4l_close(struct inode *inode, struct file *file)
err |= mxc_streamoff(cam);
cam->capture_on = false;
wake_up_interruptible(&cam->enc_queue);
+ wake_up_interruptible(&cam->overflow_queue);
}
if (--cam->open_count == 0) {
@@ -904,6 +905,7 @@ static int mxc_v4l_close(struct inode *inode, struct file *file)
/* capture off */
wake_up_interruptible(&cam->enc_queue);
+ wake_up_interruptible(&cam->overflow_queue);
mxc_free_frames(cam);
cam->enc_counter++;
prp_exit(cam);
@@ -1440,22 +1442,17 @@ mxc_v4l_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_QBUF:{
struct v4l2_buffer *buf = arg;
int index = buf->index;
- int overflow = 0;
pr_debug("VIDIOC_QBUF: %d\n", buf->index);
- if (cam->overflow == 1) {
- cam->enc_enable(cam);
- cam->overflow = 0;
- overflow = 1;
- printk(KERN_INFO "VIDIOC_QBUF - overflow\n");
- }
-
+ wait_event_interruptible(cam->overflow_queue,
+ cam->overflow == 0);
spin_lock_irqsave(&cam->int_lock, lock_flags);
if ((cam->frame[index].buffer.flags & 0x7) ==
V4L2_BUF_FLAG_MAPPED) {
cam->frame[index].buffer.flags |=
V4L2_BUF_FLAG_QUEUED;
- if ((cam->skip_frame > 0) || (overflow == 1)) {
+ if (cam->skip_frame > 0) {
+ prphw_enable(PRP_CHANNEL_2);
list_add_tail(&cam->frame[index].queue,
&cam->working_q);
retval =
@@ -1913,15 +1910,22 @@ static void camera_callback(u32 mask, void *dev)
return;
if (mask == 1) {
- cam->overflow = 1;
+ if (cam->overflow == 0) {
+ cam->overflow = 1;
+ queue_work(v4l2_work, &prp_reset_work);
+ }
+ return;
}
if (list_empty(&cam->working_q)) {
if (empty_wq_cnt == 0) {
- printk(KERN_ERR "camera_callback: working queue empty %d\n",empty_wq_cnt);
+ printk(KERN_ERR
+ "camera_callback: working queue empty %d\n",
+ empty_wq_cnt);
}
empty_wq_cnt++;
- if (list_empty(&cam->ready_q)) {
+ if (list_empty(&cam->ready_q)) {
+ prphw_disable(PRP_CHANNEL_2);
cam->skip_frame++;
} else {
ready_frame =
@@ -1941,7 +1945,10 @@ static void camera_callback(u32 mask, void *dev)
done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE;
done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
+ list_del(cam->working_q.next);
if (list_empty(&cam->ready_q)) {
+ if (list_empty(&cam->working_q))
+ prphw_disable(PRP_CHANNEL_2);
cam->skip_frame++;
} else {
ready_frame =
@@ -1954,7 +1961,6 @@ static void camera_callback(u32 mask, void *dev)
}
/* Added to the done queue */
- list_del(cam->working_q.next);
list_add_tail(&done_frame->queue, &cam->done_q);
/* Wake up the queue */
@@ -2000,6 +2006,8 @@ static void init_camera_struct(cam_data * cam)
init_waitqueue_head(&cam->enc_queue);
init_waitqueue_head(&cam->still_queue);
+ init_waitqueue_head(&cam->overflow_queue);
+ cam->overflow = 0;
/* setup cropping */
cam->crop_bounds.left = 0;
@@ -2158,6 +2166,8 @@ static __init int camera_init(void)
init_camera_struct(cam);
+ v4l2_work = create_singlethread_workqueue("v4l2_emma");
+
/* Register the I2C device */
err = platform_device_register(&mxc_v4l2_devices);
if (err != 0) {
@@ -2201,6 +2211,9 @@ static void __exit camera_exit(void)
{
pr_debug("unregistering video\n");
+ flush_workqueue(v4l2_work);
+ destroy_workqueue(v4l2_work);
+
video_unregister_device(g_cam->video_dev);
platform_driver_unregister(&mxc_v4l2_driver);