diff mbox

[PATCH-V1,09/10] VPFE Capture: Add support for USERPTR mode of operation

Message ID 1266914073-30135-10-git-send-email-hvaibhav@ti.com (mailing list archive)
State RFC
Headers show

Commit Message

Vaibhav Hiremath Feb. 23, 2010, 8:34 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/media/video/ti-media/vpfe_capture.c b/drivers/media/video/ti-media/vpfe_capture.c
index cece265..7d4ab44 100644
--- a/drivers/media/video/ti-media/vpfe_capture.c
+++ b/drivers/media/video/ti-media/vpfe_capture.c
@@ -538,7 +538,24 @@  static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev)
 					struct videobuf_buffer, queue);
 	list_del(&vpfe_dev->next_frm->queue);
 	vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE;
-	addr = videobuf_to_dma_contig(vpfe_dev->next_frm);
+	if (V4L2_MEMORY_USERPTR == vpfe_dev->memory)
+		addr = vpfe_dev->cur_frm->boff;
+	else
+		addr = videobuf_to_dma_contig(vpfe_dev->next_frm);
+
+	ccdc_dev->hw_ops.setfbaddr(addr);
+}
+
+static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev)
+{
+	unsigned long addr;
+
+	if (V4L2_MEMORY_USERPTR == vpfe_dev->memory)
+		addr = vpfe_dev->cur_frm->boff;
+	else
+		addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
+
+	addr += vpfe_dev->field_off;
 	ccdc_dev->hw_ops.setfbaddr(addr);
 }

@@ -559,7 +576,6 @@  static irqreturn_t vpfe_isr(int irq, void *dev_id)
 {
 	struct vpfe_device *vpfe_dev = dev_id;
 	enum v4l2_field field;
-	unsigned long addr;
 	int fid;

 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n");
@@ -604,10 +620,7 @@  static irqreturn_t vpfe_isr(int irq, void *dev_id)
 			 * the CCDC memory address
 			 */
 			if (field == V4L2_FIELD_SEQ_TB) {
-				addr =
-				  videobuf_to_dma_contig(vpfe_dev->cur_frm);
-				addr += vpfe_dev->field_off;
-				ccdc_dev->hw_ops.setfbaddr(addr);
+				vpfe_schedule_bottom_field(vpfe_dev);
 			}
 			goto clear_intr;
 		}
@@ -1234,7 +1247,10 @@  static int vpfe_videobuf_setup(struct videobuf_queue *vq,
 	struct vpfe_device *vpfe_dev = fh->vpfe_dev;

 	v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n");
-	*size = config_params.device_bufsize;
+	*size = vpfe_dev->fmt.fmt.pix.sizeimage;
+	if (vpfe_dev->memory == V4L2_MEMORY_MMAP &&
+		vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize)
+		*size = config_params.device_bufsize;

 	if (*count < config_params.min_numbuffers)
 		*count = config_params.min_numbuffers;
@@ -1243,6 +1259,46 @@  static int vpfe_videobuf_setup(struct videobuf_queue *vq,
 	return 0;
 }

+/*
+ * vpfe_uservirt_to_phys: This function is used to convert user
+ * space virtual address to physical address.
+ */
+static u32 vpfe_uservirt_to_phys(struct vpfe_device *vpfe_dev, u32 virtp)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long physp = 0;
+	struct vm_area_struct *vma;
+
+	vma = find_vma(mm, virtp);
+
+	/* For kernel direct-mapped memory, take the easy way */
+	if (virtp >= PAGE_OFFSET)
+		physp = virt_to_phys((void *)virtp);
+	else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff))
+		/* this will catch, kernel-allocated, mmaped-to-usermode addr */
+		physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
+	else {
+		/* otherwise, use get_user_pages() for general userland pages */
+		int res, nr_pages = 1;
+		struct page *pages;
+		down_read(&current->mm->mmap_sem);
+
+		res = get_user_pages(current, current->mm,
+				     virtp, nr_pages, 1, 0, &pages, NULL);
+		up_read(&current->mm->mmap_sem);
+
+		if (res == nr_pages)
+			physp = __pa(page_address(&pages[0]) +
+				     (virtp & ~PAGE_MASK));
+		else {
+			v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+				"get_user_pages failed\n");
+			return 0;
+		}
+	}
+	return physp;
+}
+
 static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
 				struct videobuf_buffer *vb,
 				enum v4l2_field field)
@@ -1259,6 +1315,18 @@  static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
 		vb->size = vpfe_dev->fmt.fmt.pix.sizeimage;
 		vb->field = field;
 	}
+
+	if (V4L2_MEMORY_USERPTR == vpfe_dev->memory) {
+		if (!vb->baddr) {
+			v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+				"buffer address is 0\n");
+			return -EINVAL;
+		}
+		vb->boff = vpfe_uservirt_to_phys(vpfe_dev, vb->baddr);
+		/* Make sure user addresses are aligned to 32 bytes */
+		if (!ALIGN(vb->boff, 32))
+			return -EINVAL;
+	}
 	vb->state = VIDEOBUF_PREPARED;
 	return 0;
 }
@@ -1327,13 +1395,6 @@  static int vpfe_reqbufs(struct file *file, void *priv,
 		return -EINVAL;
 	}

-	if (V4L2_MEMORY_USERPTR == req_buf->memory) {
-		/* we don't support user ptr IO */
-		v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs:"
-			 " USERPTR IO not supported\n");
-		return  -EINVAL;
-	}
-
 	ret = mutex_lock_interruptible(&vpfe_dev->lock);
 	if (ret)
 		return ret;
@@ -1541,7 +1602,10 @@  static int vpfe_streamon(struct file *file, void *priv,
 	vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE;
 	/* Initialize field_id and started member */
 	vpfe_dev->field_id = 0;
-	addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);
+	if (V4L2_MEMORY_USERPTR == vpfe_dev->memory)
+		addr = vpfe_dev->cur_frm->boff;
+	else
+		addr = videobuf_to_dma_contig(vpfe_dev->cur_frm);

 	/* Calculate field offset */
 	vpfe_calculate_offsets(vpfe_dev);