msm camera: migrate to videobuf2 framework
add necessary changes in camera driver to
migrate to videobuf2 framework.
Signed-off-by: Kiran Kumar H N <hurlisal@codeaurora.org>
Signed-off-by: Mingcheng Zhu <mingchen@codeaurora.org>
Conflicts:
drivers/media/video/Makefile
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 724c7a3..c4b240f 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -10,8 +10,11 @@
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
-videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
- v4l2-event.o v4l2-ctrls.o v4l2-subdev.o videobuf-core.o videobuf-msm-mem.o videobuf-dma-contig.o
+videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
+ v4l2-event.o v4l2-ctrls.o v4l2-subdev.o videobuf2-core.o \
+ videobuf2-memops.o videobuf2-msm-mem.o videobuf2-dma-contig.o \
+ videobuf2-vmalloc.o videobuf2-dma-sg.o
+
# V4L2 core modules
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 0e8054f..24fbcda 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -4,7 +4,7 @@
endif
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
- obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o
+ obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o
else
obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
endif
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index c42f97b..6ded98b 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -265,7 +265,6 @@
pix->pixelformat;
pcam->dev_inst[idx]->vid_fmt.fmt.pix.bytesperline =
pix->bytesperline;
- pcam->dev_inst[idx]->vid_bufq.field = pix->field;
pcam->dev_inst[idx]->sensor_pxlcode
= pcam->usr_fmts[i].pxlcode;
D("%s:inst=0x%x,idx=%d,width=%d,heigth=%d\n",
@@ -608,36 +607,12 @@
struct v4l2_requestbuffers *pb)
{
int rc = 0;
- int i = 0;
- /*struct msm_cam_v4l2_device *pcam = video_drvdata(f);*/
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
-
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
-
- if (!pb->count) {
- if (pcam_inst->vid_bufq.streaming)
- videobuf_stop(&pcam_inst->vid_bufq);
- else
- videobuf_queue_cancel(&pcam_inst->vid_bufq);
-
- /* free the queue: function name is ambiguous it frees all
- types of buffers (mmap or userptr - it doesn't matter) */
- rc = videobuf_mmap_free(&pcam_inst->vid_bufq);
- } else {
- rc = videobuf_reqbufs(&pcam_inst->vid_bufq, pb);
- if (rc < 0)
- return rc;
- /* Now initialize the local msm_frame_buffer structure */
- for (i = 0; i < pb->count; i++) {
- struct msm_frame_buffer *buf = container_of(
- pcam_inst->vid_bufq.bufs[i],
- struct msm_frame_buffer,
- vidbuf);
- buf->inuse = 0;
- INIT_LIST_HEAD(&buf->vidbuf.queue);
- }
- }
+ rc = vb2_reqbufs(&pcam_inst->vid_bufq, pb);
pcam_inst->buf_count = pb->count;
return rc;
}
@@ -646,12 +621,13 @@
struct v4l2_buffer *pb)
{
/* get the video device */
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
-
- return videobuf_querybuf(&pcam_inst->vid_bufq, pb);
+ return vb2_querybuf(&pcam_inst->vid_bufq, pb);
}
static int msm_camera_v4l2_qbuf(struct file *f, void *pctx,
@@ -659,12 +635,17 @@
{
int rc = 0;
/* get the camera device */
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
- rc = videobuf_qbuf(&pcam_inst->vid_bufq, pb);
+ D("%s stored reserved info %d", __func__, pb->reserved);
+ pcam_inst->buf_offset[pb->index] = pb->reserved;
+
+ rc = vb2_qbuf(&pcam_inst->vid_bufq, pb);
D("%s, videobuf_qbuf returns %d\n", __func__, rc);
return rc;
@@ -675,12 +656,14 @@
{
int rc = 0;
/* get the camera device */
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
- rc = videobuf_dqbuf(&pcam_inst->vid_bufq, pb, f->f_flags & O_NONBLOCK);
+ rc = vb2_dqbuf(&pcam_inst->vid_bufq, pb, f->f_flags & O_NONBLOCK);
D("%s, videobuf_dqbuf returns %d\n", __func__, rc);
return rc;
@@ -690,18 +673,18 @@
enum v4l2_buf_type i)
{
int rc = 0;
- struct videobuf_buffer *buf;
- int cnt = 0;
/* get the camera device */
struct msm_cam_v4l2_device *pcam = video_drvdata(f);
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
D("%s Calling videobuf_streamon", __func__);
/* if HW streaming on is successful, start buffer streaming */
- rc = videobuf_streamon(&pcam_inst->vid_bufq);
+ rc = vb2_streamon(&pcam_inst->vid_bufq, V4L2_BUF_TYPE_VIDEO_CAPTURE);
D("%s, videobuf_streamon returns %d\n", __func__, rc);
mutex_lock(&pcam->vid_lock);
@@ -709,16 +692,8 @@
rc = msm_server_streamon(pcam, pcam_inst->my_index);
mutex_unlock(&pcam->vid_lock);
D("%s rc = %d\n", __func__, rc);
- if (rc < 0) {
+ if (rc < 0)
pr_err("%s: hw failed to start streaming\n", __func__);
- return rc;
- }
-
- list_for_each_entry(buf, &pcam_inst->vid_bufq.stream, stream) {
- D("%s index %d, state %d\n", __func__, cnt, buf->state);
- cnt++;
- }
-
return rc;
}
@@ -728,7 +703,9 @@
int rc = 0;
/* get the camera device */
struct msm_cam_v4l2_device *pcam = video_drvdata(f);
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
@@ -742,7 +719,7 @@
pr_err("%s: hw failed to stop streaming\n", __func__);
/* stop buffer streaming */
- rc = videobuf_streamoff(&pcam_inst->vid_bufq);
+ rc = vb2_streamoff(&pcam_inst->vid_bufq, V4L2_BUF_TYPE_VIDEO_CAPTURE);
D("%s, videobuf_streamoff returns %d\n", __func__, rc);
return rc;
@@ -783,7 +760,9 @@
int rc = 0;
/* get the video device */
struct msm_cam_v4l2_device *pcam = video_drvdata(f);
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
WARN_ON(pctx != f->private_data);
@@ -829,7 +808,9 @@
void __user *uptr;
/* get the video device */
struct msm_cam_v4l2_device *pcam = video_drvdata(f);
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
D("%s\n", __func__);
D("%s, inst=0x%x,idx=%d,priv = 0x%p\n",
@@ -950,7 +931,9 @@
struct v4l2_streamparm *a)
{
int rc = 0;
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
pcam_inst->image_mode = a->parm.capture.extendedmode;
pcam_inst->pcam->dev_inst_map[pcam_inst->image_mode] = pcam_inst;
pcam_inst->path = msm_vidbuf_get_path(pcam_inst->image_mode);
@@ -1197,8 +1180,7 @@
return rc;
}
-
- f->private_data = pcam_inst;
+ f->private_data = &pcam_inst->eventHandle;
D("f->private_data = 0x%x, pcam = 0x%x\n",
(u32)f->private_data, (u32)pcam_inst);
@@ -1220,12 +1202,13 @@
static int msm_mmap(struct file *f, struct vm_area_struct *vma)
{
int rc = 0;
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
D("mmap called, vma=0x%08lx\n", (unsigned long)vma);
- rc = videobuf_mmap_mapper(&pcam_inst->vid_bufq, vma);
-
+ rc = vb2_mmap(&pcam_inst->vid_bufq, vma);
D("vma start=0x%08lx, size=%ld, ret=%d\n",
(unsigned long)vma->vm_start,
(unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
@@ -1237,9 +1220,11 @@
static int msm_close(struct file *f)
{
int rc = 0;
- struct msm_cam_v4l2_device *pcam = video_drvdata(f);
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
-
+ struct msm_cam_v4l2_device *pcam;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
+ pcam = pcam_inst->pcam;
D("%s\n", __func__);
if (!pcam) {
pr_err("%s NULL pointer of camera device!\n", __func__);
@@ -1250,12 +1235,7 @@
mutex_lock(&pcam->vid_lock);
pcam->use_count--;
pcam->dev_inst_map[pcam_inst->image_mode] = NULL;
- videobuf_stop(&pcam_inst->vid_bufq);
- /* free the queue: function name is ambiguous it frees all
- types of buffers (mmap or userptr - it doesn't matter) */
- rc = videobuf_mmap_free(&pcam_inst->vid_bufq);
- if (rc < 0)
- pr_err("%s: unable to free buffers\n", __func__);
+ vb2_queue_release(&pcam_inst->vid_bufq);
pcam->dev_inst[pcam_inst->my_index] = NULL;
kfree(pcam_inst);
f->private_data = NULL;
@@ -1286,9 +1266,11 @@
static unsigned int msm_poll(struct file *f, struct poll_table_struct *wait)
{
int rc = 0;
- struct msm_cam_v4l2_device *pcam = video_drvdata(f);
- struct msm_cam_v4l2_dev_inst *pcam_inst = f->private_data;
-
+ struct msm_cam_v4l2_device *pcam;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
+ pcam = pcam_inst->pcam;
D("%s\n", __func__);
if (!pcam) {
pr_err("%s NULL pointer of camera device!\n", __func__);
@@ -1301,7 +1283,7 @@
return -EINVAL;
}
- rc |= videobuf_poll_stream(f, &pcam_inst->vid_bufq, wait);
+ rc |= vb2_poll(&pcam_inst->vid_bufq, f, wait);
D("%s returns, rc = 0x%x\n", __func__, rc);
return rc;
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 0049cc1..7390f10 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -26,8 +26,8 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mediabus.h>
-#include <media/videobuf-dma-contig.h>
-#include <media/videobuf-msm-mem.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-msm-mem.h>
#include <mach/camera.h>
#define MSM_V4L2_DIMENSION_SIZE 96
@@ -98,7 +98,8 @@
/* buffer for one video frame */
struct msm_frame_buffer {
/* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vidbuf;
+ struct vb2_buffer vidbuf;
+ struct list_head list;
enum v4l2_mbus_pixelcode pxlcode;
int inuse;
int active;
@@ -138,11 +139,12 @@
extern int msm_ispif_init_module(struct msm_ispif_ops *p_ispif);
-/*"Media Controller" represents a camera steaming session, which consists
- of a "sensor" device and an "isp" device (such as VFE, if needed),
- connected via an "IO" device, (such as IPIF on 8960, or none on 8660)
- plus other extra sub devices such as VPE and flash
-*/
+/* "Media Controller" represents a camera steaming session,
+ * which consists of a "sensor" device and an "isp" device
+ * (such as VFE, if needed), connected via an "IO" device,
+ * (such as IPIF on 8960, or none on 8660) plus other extra
+ * sub devices such as VPE and flash.
+ */
struct msm_cam_media_controller {
@@ -155,7 +157,7 @@
unsigned int cmd, unsigned long arg);
int (*mctl_release)(struct msm_cam_media_controller *p_mctl);
int (*mctl_vidbuf_init)(struct msm_cam_v4l2_dev_inst *pcam,
- struct videobuf_queue *);
+ struct vb2_queue *q);
int (*mctl_ufmt_init)(struct msm_cam_media_controller *p_mctl);
struct v4l2_device v4l2_dev;
@@ -203,18 +205,27 @@
unsigned long buffer;
int fd;
};
+struct msm_free_buf {
+ uint32_t paddr;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+};
#define MSM_DEV_INST_MAX 16
struct msm_cam_v4l2_dev_inst {
- struct videobuf_queue vid_bufq;
- spinlock_t vb_irqlock;
+ struct v4l2_fh eventHandle;
+ struct vb2_queue vid_bufq;
+ spinlock_t vq_irqlock;
+ struct list_head free_vq;
struct v4l2_format vid_fmt;
- /* senssor pixel code*/
+ /* sensor pixel code*/
enum v4l2_mbus_pixelcode sensor_pxlcode;
struct msm_cam_v4l2_device *pcam;
int my_index;
int image_mode;
int path;
int buf_count;
+ /* buffer offset, if any */
+ uint32_t buf_offset[VIDEO_MAX_FRAME];
};
#define MSM_MAX_IMG_MODE 5
/* abstract camera device for each sensor successfully probed*/
@@ -339,9 +350,12 @@
int msm_isp_init_module(int g_num_config_nodes);
int msm_mctl_init_module(struct msm_cam_v4l2_device *pcam);
+int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam);
int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam);
int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl,
int msg_type, uint32_t y_phy);
+int msm_mctl_fetch_free_buf(struct msm_cam_media_controller *pmctl,
+ int path, struct msm_free_buf *free_buf);
/*Memory(PMEM) functions*/
int msm_register_pmem(struct hlist_head *ptype, void __user *arg);
int msm_pmem_table_del(struct hlist_head *ptype, void __user *arg);
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 35cb68a..4875d6d 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -82,337 +82,6 @@
},
};
-/* master controller instance counter
-static atomic_t mctl_instance = ATOMIC_INIT(0);
-*/
-
-static int buffer_size(int width, int height, int pixelformat)
-{
- int size;
-
- switch (pixelformat) {
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV12:
- size = width * height * 3/2;
- break;
- case V4L2_PIX_FMT_SBGGR10:
- case V4L2_PIX_FMT_SGBRG10:
- case V4L2_PIX_FMT_SGRBG10:
- case V4L2_PIX_FMT_SRGGB10:
- size = width * height;
- break;
- default:
- pr_err("%s: pixelformat %d not supported.\n",
- __func__, pixelformat);
- size = -EINVAL;
- }
-
- return size;
-}
-/*
- * Videobuf operations
- */
-
-static void free_buffer(struct videobuf_queue *vq,
- struct msm_frame_buffer *buf)
-{
- struct videobuf_buffer *vb = &buf->vidbuf;
-
- BUG_ON(in_interrupt());
-
- D("%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- /* This waits until this buffer is out of danger, i.e.,
- * until it is no longer in STATE_QUEUED or STATE_ACTIVE */
- videobuf_waiton(vq, vb, 0, 0);
- videobuf_pmem_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-/* Setup # of buffers and size of each buffer for the videobuf_queue.
- This is called when videobuf_reqbufs() is called, so this function
- should tell how many buffer should be used and how big the size is.
-
- The caller will allocate the real buffers, either in user space or
- in kernel */
-static int msm_vidbuf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- /* get the video device */
- struct msm_cam_v4l2_dev_inst *pcam_inst = vq->priv_data;
- struct msm_cam_v4l2_device *pcam = NULL;
-
- pcam = pcam_inst->pcam;
-
- D("%s\n", __func__);
- if (!pcam || !count || !size) {
- pr_err("%s error : invalid input\n", __func__);
- return -EINVAL;
- }
-
- D("%s, inst=0x%x,idx=%d, width = %d\n", __func__,
- (u32)pcam_inst, pcam_inst->my_index,
- pcam_inst->vid_fmt.fmt.pix.width);
- D("%s, inst=0x%x,idx=%d, height = %d\n", __func__,
- (u32)pcam_inst, pcam_inst->my_index,
- pcam_inst->vid_fmt.fmt.pix.height);
- *size = buffer_size(pcam_inst->vid_fmt.fmt.pix.width,
- pcam_inst->vid_fmt.fmt.pix.height,
- pcam_inst->vid_fmt.fmt.pix.pixelformat);
- D("%s:inst=0x%x,idx=%d,count=%d, size=%d\n", __func__,
- (u32)pcam_inst, pcam_inst->my_index, *count, *size);
- return 0;
-}
-
-/* Prepare the buffer before it is put into the videobuf_queue for streaming.
- This is called when videobuf_qbuf() is called, so this function should
- setup the video buffer to receieve the VFE output. */
-static int msm_vidbuf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb, enum v4l2_field field)
-{
- int rc = 0;
- /*struct msm_cam_v4l2_device *pcam = vq->priv_data;*/
- struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
- struct msm_cam_v4l2_device *pcam = NULL;
- struct msm_frame_buffer *buf = NULL;
-
- D("%s\n", __func__);
- if (!vb || !vq) {
- pr_err("%s error : input is NULL\n", __func__);
- return -EINVAL;
- }
- pcam_inst = vq->priv_data;
- pcam = pcam_inst->pcam;
- buf = container_of(vb, struct msm_frame_buffer, vidbuf);
-
- if (!pcam || !buf) {
- pr_err("%s error : pointer is NULL\n", __func__);
- return -EINVAL;
- }
-
- D("%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- /* by this time vid_fmt should be already set */
- /* return error if it is not */
- if ((pcam_inst->vid_fmt.fmt.pix.width == 0) ||
- (pcam_inst->vid_fmt.fmt.pix.height == 0)) {
- pr_err("%s error : pcam vid_fmt is not set\n", __func__);
- return -EINVAL;
- }
-
- buf->inuse = 1;
-
- D("buf->pxlcode=%d, pcam->sensor_pxlcode=%d, vb->width=%d,"
- "pcam->vid_fmt.fmt.pix.width = %d, vb->height = %d,"
- "pcam->vid_fmt.fmt.pix.height=%d, vb->field=%d, field=%d\n",
- buf->pxlcode, pcam_inst->sensor_pxlcode, vb->width,
- pcam_inst->vid_fmt.fmt.pix.width, vb->height,
- pcam_inst->vid_fmt.fmt.pix.height, vb->field, field);
-
- if (buf->pxlcode != pcam_inst->sensor_pxlcode ||
- vb->width != pcam_inst->vid_fmt.fmt.pix.width ||
- vb->height != pcam_inst->vid_fmt.fmt.pix.height ||
- vb->field != field) {
- buf->pxlcode = pcam_inst->sensor_pxlcode;
- vb->width = pcam_inst->vid_fmt.fmt.pix.width;
- vb->height = pcam_inst->vid_fmt.fmt.pix.height;
- vb->field = field;
- vb->state = VIDEOBUF_NEEDS_INIT;
- D("VIDEOBUF_NEEDS_INIT\n");
- }
-
- vb->size = buffer_size(pcam_inst->vid_fmt.fmt.pix.width, vb->height,
- pcam_inst->vid_fmt.fmt.pix.pixelformat);
-
- D("vb->size=%lu, vb->bsize=%u, vb->baddr=0x%x\n",
- vb->size, vb->bsize, (uint32_t)vb->baddr);
-
- if (0 != vb->baddr && vb->bsize < vb->size) {
- pr_err("Something wrong vb->size=%lu, vb->bsize=%u,\
- vb->baddr=0x%x\n",
- vb->size, vb->bsize,
- (uint32_t)vb->baddr);
- rc = -EINVAL;
- goto out;
- }
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- rc = videobuf_iolock(vq, vb, NULL);
- if (rc)
- goto fail;
- D("%s: setting buffer state to prepared\n", __func__);
- vb->state = VIDEOBUF_PREPARED;
- }
-
- buf->inuse = 0;
-
- /* finally if everything is oK, set the VIDEOBUF_PREPARED state*/
- if (0 == rc)
- vb->state = VIDEOBUF_PREPARED;
- return rc;
-
-fail:
- free_buffer(vq, buf);
-
-out:
- buf->inuse = 0;
- return rc;
-}
-
-/* Called under spin_lock_irqsave(q->irqlock, flags) in videobuf-core.c*/
-static void msm_vidbuf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- /*struct msm_cam_v4l2_device *pcam = vq->priv_data;*/
- struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
- struct msm_cam_v4l2_device *pcam = NULL;
- unsigned long phyaddr = 0;
- int rc;
-
- D("%s\n", __func__);
- if (!vb || !vq) {
- pr_err("%s error : input is NULL\n", __func__);
- return ;
- }
- pcam_inst = vq->priv_data;
- pcam = pcam_inst->pcam;
- if (!pcam) {
- pr_err("%s error : pcam is NULL\n", __func__);
- return;
- }
- D("%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize);
-
-
- vb->state = VIDEOBUF_QUEUED;
- if (vq->streaming) {
- struct msm_frame frame;
- struct msm_vfe_cfg_cmd cfgcmd;
- /* we are returning a buffer to the queue */
- struct videobuf_contig_pmem *mem = vb->priv;
- /* get the physcial address of the buffer */
- phyaddr = (unsigned long) videobuf_to_pmem_contig(vb);
-
- D("%s buffer type is %d\n", __func__, mem->buffer_type);
- frame.path = pcam_inst->path;
- frame.buffer = 0;
- frame.y_off = mem->y_off;
- frame.cbcr_off = mem->cbcr_off;
-
- /* now release frame to vfe */
- cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE;
- cfgcmd.value = (void *)&frame;
- /* yyan: later change to mctl APIs*/
- rc = msm_isp_subdev_ioctl(&pcam->mctl.isp_sdev->sd,
- &cfgcmd, &phyaddr);
- }
-}
-
-/* This will be called when streamingoff is called. */
-static void msm_vidbuf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct msm_cam_v4l2_dev_inst *pcam_inst = vq->priv_data;
- struct msm_cam_v4l2_device *pcam = pcam_inst->pcam;
- struct msm_frame_buffer *buf = container_of(vb, struct msm_frame_buffer,
- vidbuf);
-
- D("%s\n", __func__);
- if (!pcam || !vb || !vq) {
- pr_err("%s error : input is NULL\n", __func__);
- return ;
- }
-#ifdef DEBUG
- D("%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- switch (vb->state) {
- case VIDEOBUF_ACTIVE:
- D("%s (active)\n", __func__);
- break;
- case VIDEOBUF_QUEUED:
- D("%s (queued)\n", __func__);
- break;
- case VIDEOBUF_PREPARED:
- D("%s (prepared)\n", __func__);
- break;
- default:
- D("%s (unknown) state = %d\n", __func__, vb->state);
- break;
- }
-#endif
-
- /* free the buffer */
- free_buffer(vq, buf);
-}
-
-
-static struct videobuf_queue_ops msm_vidbuf_ops = {
- .buf_setup = msm_vidbuf_setup,
- .buf_prepare = msm_vidbuf_prepare,
- .buf_queue = msm_vidbuf_queue,
- .buf_release = msm_vidbuf_release,
-};
-
-
-
-/* prepare a video buffer queue for a vl42 device*/
-static int msm_vidbuf_init(struct msm_cam_v4l2_dev_inst *pcam_inst,
- struct videobuf_queue *q)
-{
- int rc = 0;
- struct resource *res;
- struct platform_device *pdev = NULL;
- struct msm_cam_v4l2_device *pcam = pcam_inst->pcam;
- D("%s\n", __func__);
- if (!pcam || !q) {
- pr_err("%s error : input is NULL\n", __func__);
- return -EINVAL;
- } else
- pdev = pcam->mctl.sync.pdev;
-
- if (!pdev) {
- pr_err("%s error : pdev is NULL\n", __func__);
- return -EINVAL;
- }
- if (pcam->use_count == 1) {
- /* first check if we have resources */
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (res) {
- D("res->start = 0x%x\n", (u32)res->start);
- D("res->size = 0x%x\n", (u32)resource_size(res));
- D("res->end = 0x%x\n", (u32)res->end);
- rc = dma_declare_coherent_memory(&pdev->dev, res->start,
- res->start,
- resource_size(res),
- DMA_MEMORY_MAP |
- DMA_MEMORY_EXCLUSIVE);
- if (!rc) {
- pr_err("%s: Unable to declare coherent memory.\n",
- __func__);
- rc = -ENXIO;
- return rc;
- }
-
- /*pcam->memsize = resource_size(res);*/
- D("%s: found DMA capable resource\n", __func__);
- } else {
- pr_err("%s: no DMA capable resource\n", __func__);
- return -ENOMEM;
- }
- }
- spin_lock_init(&pcam_inst->vb_irqlock);
-
- videobuf_queue_pmem_contig_init(q, &msm_vidbuf_ops, &pdev->dev,
- &pcam_inst->vb_irqlock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
- sizeof(struct msm_frame_buffer), pcam_inst, NULL);
-
-
- return 0;
-}
/*
* V4l2 subdevice operations
@@ -762,77 +431,13 @@
pmctl->mctl_open = msm_mctl_open;
pmctl->mctl_cmd = msm_mctl_cmd;
pmctl->mctl_notify = msm_mctl_notify;
- pmctl->mctl_vidbuf_init = msm_vidbuf_init;
pmctl->mctl_release = msm_mctl_release;
-
pmctl->plat_dev = pcam->pdev;
+ /* init mctl buf */
+ msm_mctl_buf_init(pcam);
/* init sub device*/
v4l2_subdev_init(&(pmctl->mctl_sdev), &mctl_subdev_ops);
v4l2_set_subdevdata(&(pmctl->mctl_sdev), pmctl);
return 0;
}
-static int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
- int out_type)
-{
- switch (out_type) {
- case VFE_MSG_OUTPUT_P:
- return pcam->dev_inst_map
- [MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW]->my_index;
- case VFE_MSG_OUTPUT_V:
- return pcam->dev_inst_map
- [MSM_V4L2_EXT_CAPTURE_MODE_VIDEO]->my_index;
- case VFE_MSG_OUTPUT_S:
- return pcam->dev_inst_map
- [MSM_V4L2_EXT_CAPTURE_MODE_MAIN]->my_index;
- case VFE_MSG_OUTPUT_T:
- return pcam->dev_inst_map
- [MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL]->my_index;
- default:
- return 0;
- }
- return 0;
-}
-
-int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl,
- int msg_type, uint32_t y_phy)
-{
- struct videobuf_queue *q;
- struct videobuf_buffer *buf = NULL;
- uint32_t buf_phyaddr = 0;
- int i, idx;
- unsigned long flags = 0;
-
- idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, msg_type);
- q = &(pmctl->sync.pcam_sync->dev_inst[idx]->vid_bufq);
-
- D("q=0x%x\n", (u32)q);
-
- /* find the videobuf which is done */
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (NULL == q->bufs[i])
- continue;
- buf = q->bufs[i];
- buf_phyaddr = videobuf_to_pmem_contig(buf);
- D("buf_phyaddr=0x%x\n", (u32)buf_phyaddr);
- D("data->phy.y_phy=0x%x\n",
- y_phy);
- D("buf = 0x%x\n", (u32)buf);
- if (buf_phyaddr == y_phy) {
- /* signal that buffer is done */
- /* get the buf lock first */
- spin_lock_irqsave(q->irqlock, flags);
- buf->state = VIDEOBUF_DONE;
- D("queuedequeue video_buffer 0x%x,"
- "phyaddr = 0x%x\n",
- (u32)buf, y_phy);
-
- do_gettimeofday(&buf->ts);
- buf->field_count++;
- wake_up(&buf->done);
- spin_unlock_irqrestore(q->irqlock, flags);
- break;
- }
- }
- return 0;
-}
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
new file mode 100644
index 0000000..d084f9c
--- /dev/null
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -0,0 +1,471 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+#include <linux/android_pmem.h>
+
+#include "msm.h"
+#include "msm_ispif.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_mctl_buf: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+#define PAD_TO_WORD(a) (((a) + 3) & ~3)
+
+static int buffer_size(uint32_t *yoffset, uint32_t *cbcroffset,
+ int width, int height,
+ int pixelformat, int ext_mode)
+{
+ int size;
+
+ *yoffset = 0;
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV12:
+ if (ext_mode == MSM_V4L2_EXT_CAPTURE_MODE_VIDEO) {
+ size = PAD_TO_2K(width * height, 1)
+ + PAD_TO_2K(width * height/2, 1);
+ *cbcroffset = PAD_TO_2K(width * height, 1);
+ } else {
+ size = PAD_TO_WORD(width * height)
+ + PAD_TO_WORD(width * height/2);
+ *cbcroffset = PAD_TO_WORD(width * height);
+ }
+ break;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ size = PAD_TO_WORD(width * height);
+ break;
+ default:
+ pr_err("%s: pixelformat %d not supported.\n",
+ __func__, pixelformat);
+ size = -EINVAL;
+ }
+ size = PAGE_ALIGN(size);
+ return size;
+}
+
+static int msm_vb2_ops_queue_setup(struct vb2_queue *vq,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned long sizes[],
+ void *alloc_ctxs[])
+{
+ /* get the video device */
+ struct msm_cam_v4l2_dev_inst *pcam_inst = vb2_get_drv_priv(vq);
+ struct msm_cam_v4l2_device *pcam = pcam_inst->pcam;
+ uint32_t yoffset, cbcroffset;
+
+ D("%s\n", __func__);
+ if (!pcam || !(*num_buffers)) {
+ pr_err("%s error : invalid input\n", __func__);
+ return -EINVAL;
+ }
+ /* TBD: need to set based on format */
+ *num_planes = 1;
+ D("%s, inst=0x%x,idx=%d, width = %d\n", __func__,
+ (u32)pcam_inst, pcam_inst->my_index,
+ pcam_inst->vid_fmt.fmt.pix.width);
+ D("%s, inst=0x%x,idx=%d, height = %d\n", __func__,
+ (u32)pcam_inst, pcam_inst->my_index,
+ pcam_inst->vid_fmt.fmt.pix.height);
+ sizes[0] = buffer_size(&yoffset, &cbcroffset,
+ pcam_inst->vid_fmt.fmt.pix.width,
+ pcam_inst->vid_fmt.fmt.pix.height,
+ pcam_inst->vid_fmt.fmt.pix.pixelformat,
+ pcam_inst->image_mode);
+ return 0;
+}
+
+static void msm_vb2_ops_wait_prepare(struct vb2_queue *q)
+{
+ /* we use polling so do not use this fn now */
+}
+static void msm_vb2_ops_wait_finish(struct vb2_queue *q)
+{
+ /* we use polling so do not use this fn now */
+}
+
+static int msm_vb2_ops_buf_init(struct vb2_buffer *vb)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ struct msm_cam_v4l2_device *pcam;
+ struct videobuf2_contig_pmem *mem;
+ struct vb2_queue *vq;
+ uint32_t yoffset, cbcroffset;
+ int size, rc = 0;
+ vq = vb->vb2_queue;
+ pcam_inst = vb2_get_drv_priv(vq);
+ pcam = pcam_inst->pcam;
+ D("%s\n", __func__);
+ D("%s, inst=0x%x,idx=%d, width = %d\n", __func__,
+ (u32)pcam_inst, pcam_inst->my_index,
+ pcam_inst->vid_fmt.fmt.pix.width);
+ D("%s, inst=0x%x,idx=%d, height = %d\n", __func__,
+ (u32)pcam_inst, pcam_inst->my_index,
+ pcam_inst->vid_fmt.fmt.pix.height);
+ mem = vb2_plane_cookie(vb, 0);
+ size = buffer_size(&yoffset, &cbcroffset,
+ pcam_inst->vid_fmt.fmt.pix.width,
+ pcam_inst->vid_fmt.fmt.pix.height,
+ pcam_inst->vid_fmt.fmt.pix.pixelformat,
+ pcam_inst->image_mode);
+ if (size < 0)
+ return size;
+ if (vb->v4l2_buf.memory == V4L2_MEMORY_USERPTR)
+ rc = videobuf2_pmem_contig_user_get(mem, yoffset, cbcroffset,
+ pcam_inst->buf_offset[vb->v4l2_buf.index],
+ pcam_inst->path);
+ else
+ rc = videobuf2_pmem_contig_mmap_get(mem, yoffset, cbcroffset,
+ pcam_inst->path);
+
+ return rc;
+}
+
+static int msm_vb2_ops_buf_prepare(struct vb2_buffer *vb)
+{
+ int i, rc = 0;
+ uint32_t len;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ struct msm_cam_v4l2_device *pcam;
+ struct msm_frame_buffer *buf;
+ struct vb2_queue *vq = vb->vb2_queue;
+
+ D("%s\n", __func__);
+ if (!vb || !vq) {
+ pr_err("%s error : input is NULL\n", __func__);
+ return -EINVAL;
+ }
+ pcam_inst = vb2_get_drv_priv(vq);
+ pcam = pcam_inst->pcam;
+ buf = container_of(vb, struct msm_frame_buffer, vidbuf);
+
+ if (!pcam || !buf) {
+ pr_err("%s error : pointer is NULL\n", __func__);
+ return -EINVAL;
+ }
+ /* by this time vid_fmt should be already set.
+ * return error if it is not. */
+ if ((pcam_inst->vid_fmt.fmt.pix.width == 0) ||
+ (pcam_inst->vid_fmt.fmt.pix.height == 0)) {
+ pr_err("%s error : pcam vid_fmt is not set\n", __func__);
+ return -EINVAL;
+ }
+ /* prefill in the byteused field */
+ for (i = 0; i < vb->num_planes; i++) {
+ len = vb2_plane_size(vb, i);
+ vb2_set_plane_payload(vb, i, len);
+ }
+ buf->inuse = 0;
+ return rc;
+}
+
+static int msm_vb2_ops_buf_finish(struct vb2_buffer *vb)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ struct msm_cam_v4l2_device *pcam;
+ struct msm_frame_buffer *buf;
+
+ pcam_inst = vb2_get_drv_priv(vb->vb2_queue);
+ pcam = pcam_inst->pcam;
+ buf = container_of(vb, struct msm_frame_buffer, vidbuf);
+ D("%s: inst=0x%x, buf=0x, %x, idx=%d\n", __func__,
+ (uint32_t)pcam_inst, (uint32_t)buf, vb->v4l2_buf.index);
+ return 0;
+}
+
+static void msm_vb2_ops_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ struct msm_cam_v4l2_device *pcam;
+ struct videobuf2_contig_pmem *mem;
+ struct msm_frame_buffer *buf;
+ uint32_t i, vb_phyaddr = 0, buf_phyaddr = 0;
+ pcam_inst = vb2_get_drv_priv(vb->vb2_queue);
+ pcam = pcam_inst->pcam;
+ buf = container_of(vb, struct msm_frame_buffer, vidbuf);
+ D("%s: inst=0x%x, buf=0x%x, idx=%d\n", __func__,
+ (uint32_t)pcam_inst, (uint32_t)buf, vb->v4l2_buf.index);
+ vb_phyaddr = (unsigned long) videobuf2_to_pmem_contig(vb, 0);
+ list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+ buf_phyaddr = (unsigned long)
+ videobuf2_to_pmem_contig(&buf->vidbuf, 0);
+ D("%s vb_idx=%d,vb_paddr=0x%x,phyaddr=0x%x\n",
+ __func__, buf->vidbuf.v4l2_buf.index,
+ buf_phyaddr, vb_phyaddr);
+ if (vb_phyaddr == buf_phyaddr) {
+ list_del(&buf->list);
+ break;
+ }
+ }
+ for (i = 0; i < vb->num_planes; i++) {
+ mem = vb2_plane_cookie(vb, i);
+ videobuf2_pmem_contig_user_put(mem);
+ }
+}
+
+static int msm_vb2_ops_start_streaming(struct vb2_queue *q)
+{
+ return 0;
+}
+
+static int msm_vb2_ops_stop_streaming(struct vb2_queue *q)
+{
+ return 0;
+}
+
+static void msm_vb2_ops_buf_queue(struct vb2_buffer *vb)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst = NULL;
+ struct msm_cam_v4l2_device *pcam = NULL;
+ unsigned long phyaddr = 0;
+ unsigned long flags = 0;
+ int rc;
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct msm_frame frame;
+ struct msm_vfe_cfg_cmd cfgcmd;
+ struct videobuf2_contig_pmem *mem;
+ struct msm_frame_buffer *buf;
+ D("%s\n", __func__);
+ if (!vb || !vq) {
+ pr_err("%s error : input is NULL\n", __func__);
+ return ;
+ }
+ pcam_inst = vb2_get_drv_priv(vq);
+ pcam = pcam_inst->pcam;
+ D("%s pcam_inst=%p,(vb=0x%p),idx=%d,len=%d\n", __func__, pcam_inst,
+ vb, vb->v4l2_buf.index, vb->v4l2_buf.length);
+ buf = container_of(vb, struct msm_frame_buffer, vidbuf);
+ /* we are returning a buffer to the queue */
+ mem = vb2_plane_cookie(vb, 0);
+ /* get the physcial address of the buffer */
+ phyaddr = (unsigned long) videobuf2_to_pmem_contig(vb, 0);
+ D("%s buffer type is %d\n", __func__, mem->buffer_type);
+ frame.path = pcam_inst->path;
+ frame.buffer = 0;
+ frame.y_off = mem->y_off;
+ frame.cbcr_off = mem->cbcr_off;
+ /* now release frame to vfe */
+ cfgcmd.cmd_type = CMD_FRAME_BUF_RELEASE;
+ cfgcmd.value = (void *)&frame;
+ spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+ list_add_tail(&buf->list, &pcam_inst->free_vq);
+ /* TBD: need to remove. VFE is going to call
+ msm_mctl_fetch_free_buf to get free buf.
+ Work with Shuzhen to hash out details tomorrow */
+ rc = msm_isp_subdev_ioctl(&pcam->mctl.isp_sdev->sd,
+ &cfgcmd, &phyaddr);
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+}
+
+static struct vb2_ops msm_vb2_ops = {
+ .queue_setup = msm_vb2_ops_queue_setup,
+ .wait_prepare = msm_vb2_ops_wait_prepare,
+ .wait_finish = msm_vb2_ops_wait_finish,
+ .buf_init = msm_vb2_ops_buf_init,
+ .buf_prepare = msm_vb2_ops_buf_prepare,
+ .buf_finish = msm_vb2_ops_buf_finish,
+ .buf_cleanup = msm_vb2_ops_buf_cleanup,
+ .start_streaming = msm_vb2_ops_start_streaming,
+ .stop_streaming = msm_vb2_ops_stop_streaming,
+ .buf_queue = msm_vb2_ops_buf_queue,
+};
+
+
+/* prepare a video buffer queue for a vl42 device*/
+static int msm_vidbuf_init(struct msm_cam_v4l2_dev_inst *pcam_inst,
+ struct vb2_queue *q)
+{
+ int rc = 0;
+ struct resource *res;
+ struct platform_device *pdev = NULL;
+ struct msm_cam_v4l2_device *pcam = NULL;
+
+ D("%s\n", __func__);
+ pcam = pcam_inst->pcam;
+ if (!pcam || !q) {
+ pr_err("%s error : input is NULL\n", __func__);
+ return -EINVAL;
+ } else
+ pdev = pcam->mctl.sync.pdev;
+
+ if (!pdev) {
+ pr_err("%s error : pdev is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (pcam->use_count == 1) {
+ /* first check if we have resources */
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (res) {
+ D("res->start = 0x%x\n", (u32)res->start);
+ D("res->size = 0x%x\n", (u32)resource_size(res));
+ D("res->end = 0x%x\n", (u32)res->end);
+ rc = dma_declare_coherent_memory(&pdev->dev, res->start,
+ res->start,
+ resource_size(res),
+ DMA_MEMORY_MAP |
+ DMA_MEMORY_EXCLUSIVE);
+ if (!rc) {
+ pr_err("%s: Unable to declare coherent memory.\n",
+ __func__);
+ rc = -ENXIO;
+ return rc;
+ }
+ D("%s: found DMA capable resource\n", __func__);
+ } else {
+ pr_err("%s: no DMA capable resource\n", __func__);
+ return -ENOMEM;
+ }
+ }
+ spin_lock_init(&pcam_inst->vq_irqlock);
+ INIT_LIST_HEAD(&pcam_inst->free_vq);
+ videobuf2_queue_pmem_contig_init(q, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &msm_vb2_ops,
+ sizeof(struct msm_frame_buffer),
+ (void *)pcam_inst);
+ return 0;
+}
+
+static int msm_mctl_out_type_to_inst_index(struct msm_cam_v4l2_device *pcam,
+ int out_type)
+{
+ switch (out_type) {
+ case VFE_MSG_OUTPUT_P:
+ return pcam->dev_inst_map
+ [MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW]->my_index;
+ case VFE_MSG_OUTPUT_V:
+ return pcam->dev_inst_map
+ [MSM_V4L2_EXT_CAPTURE_MODE_VIDEO]->my_index;
+ case VFE_MSG_OUTPUT_S:
+ return pcam->dev_inst_map
+ [MSM_V4L2_EXT_CAPTURE_MODE_MAIN]->my_index;
+ case VFE_MSG_OUTPUT_T:
+ return pcam->dev_inst_map
+ [MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL]->my_index;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static int msm_mctl_get_pcam_inst_idx(int out_put_type)
+{
+ switch (out_put_type) {
+ case OUTPUT_TYPE_T:
+ return MSM_V4L2_EXT_CAPTURE_MODE_THUMBNAIL;
+ case OUTPUT_TYPE_S:
+ return MSM_V4L2_EXT_CAPTURE_MODE_MAIN;
+ case OUTPUT_TYPE_V:
+ return MSM_V4L2_EXT_CAPTURE_MODE_VIDEO;
+ case OUTPUT_TYPE_P:
+ return MSM_V4L2_EXT_CAPTURE_MODE_PREVIEW;
+ default:
+ return 0;
+ }
+}
+
+
+int msm_mctl_buf_done(struct msm_cam_media_controller *pmctl,
+ int msg_type, uint32_t y_phy)
+{
+ struct msm_frame_buffer *buf = NULL;
+ uint32_t buf_phyaddr = 0;
+ int idx, got = 0;
+ unsigned long flags = 0;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+
+ idx = msm_mctl_out_type_to_inst_index(pmctl->sync.pcam_sync, msg_type);
+ pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+ /* we actually need a list, not a queue */
+ spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+ list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+ buf_phyaddr = (unsigned long)
+ videobuf2_to_pmem_contig(&buf->vidbuf, 0);
+ D("%s vb_idx=%d,vb_paddr=0x%x,y_phy=0x%x\n",
+ __func__, buf->vidbuf.v4l2_buf.index,
+ buf_phyaddr, y_phy);
+ if (y_phy == buf_phyaddr) {
+ got = 1;
+ break;
+ }
+ }
+ if (!got) {
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ pr_err("%s: buf_done addr 0x%x != free buf queue head 0x%x\n",
+ __func__, (uint32_t)y_phy, (uint32_t)buf_phyaddr);
+ return -EINVAL;
+ }
+ list_del(&buf->list);
+ buf->vidbuf.v4l2_buf.sequence++;
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ do_gettimeofday(&buf->vidbuf.v4l2_buf.timestamp);
+ vb2_buffer_done(&buf->vidbuf, VB2_BUF_STATE_DONE);
+ return 0;
+}
+
+int msm_mctl_buf_init(struct msm_cam_v4l2_device *pcam)
+{
+ pcam->mctl.mctl_vidbuf_init = msm_vidbuf_init;
+ return 0;
+}
+
+int msm_mctl_fetch_free_buf(struct msm_cam_media_controller *pmctl,
+ int path, struct msm_free_buf *free_buf)
+{
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ struct videobuf2_contig_pmem *mem;
+ int idx = msm_mctl_get_pcam_inst_idx(path);
+ unsigned long flags = 0;
+ struct msm_frame_buffer *buf = NULL;
+ int rc = -1;
+
+ pcam_inst = pmctl->sync.pcam_sync->dev_inst[idx];
+ spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
+ list_for_each_entry(buf, &pcam_inst->free_vq, list) {
+ if (buf->inuse == 0) {
+ mem = vb2_plane_cookie(&buf->vidbuf, 0);
+ free_buf->paddr =
+ (uint32_t) videobuf2_to_pmem_contig(&buf->vidbuf, 0);
+ free_buf->y_off = mem->y_off;
+ free_buf->cbcr_off = mem->cbcr_off;
+ D("%s path=%d,inst=0x%p,idx=%d,paddr=0x%x, "
+ "y_off=%d,cbcroff=%d\n", __func__, path,
+ pcam_inst, buf->vidbuf.v4l2_buf.index,
+ free_buf->paddr, free_buf->y_off,
+ free_buf->cbcr_off);
+ /* mark it used */
+ buf->inuse = 1;
+ rc = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&pcam_inst->vq_irqlock, flags);
+ return rc;
+}
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index 5232f7c..b887f1e 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -303,37 +303,39 @@
struct msm_pmem_region *reg,
int mem_type)
{
- struct videobuf_contig_pmem *mem;
+ struct videobuf2_contig_pmem *mem;
+ struct vb2_queue *q = &pcam->dev_inst[idx]->vid_bufq;
+ int i;
uint8_t rc = 0;
- struct videobuf_queue *q = &pcam->dev_inst[idx]->vid_bufq;
- struct videobuf_buffer *buf = NULL;
- videobuf_queue_lock(q);
- list_for_each_entry(buf, &q->stream, stream) {
- mem = buf->priv;
- reg->paddr = mem->phyaddr;
- D("%s paddr for buf %d is 0x%p\n", __func__,
- buf->i,
- (void *)reg->paddr);
- reg->len = sizeof(struct msm_pmem_info);
- reg->file = NULL;
- reg->info.len = mem->size;
-
- reg->info.vaddr =
- (void *)(buf->baddr);
-
- reg->info.type = mem_type;
-
- reg->info.offset = 0;
- reg->info.y_off = mem->y_off;
- reg->info.cbcr_off = PAD_TO_WORD(mem->cbcr_off);
- D("%s y_off = %d, cbcr_off = %d\n", __func__,
+ mutex_lock(&hlist_mut);
+ for (i = 0; i < pcam->dev_inst[idx]->buf_count ; i++) {
+ if (q->bufs[i] != NULL) {
+ mem = vb2_plane_cookie(q->bufs[i], 0);
+ if (!mem) {
+ pr_err("%s mem is null. Return ", __func__);
+ break;
+ }
+ reg->paddr = mem->phyaddr;
+ D("%s paddr for buf %d is 0x%p\n", __func__,
+ i,
+ (void *)reg->paddr);
+ reg->len = sizeof(struct msm_pmem_info);
+ reg->file = NULL;
+ reg->info.len = mem->size;
+ reg->info.vaddr = vb2_plane_vaddr(q->bufs[i], 0);
+ reg->info.type = mem_type;
+ reg->info.offset = 0;
+ reg->info.y_off = mem->y_off;
+ reg->info.cbcr_off = PAD_TO_WORD(mem->cbcr_off);
+ D("%s y_off = %d, cbcr_off = %d\n", __func__,
reg->info.y_off, reg->info.cbcr_off);
- rc += 1;
- reg++;
+ rc += 1;
+ reg++;
+ }
}
- videobuf_queue_unlock(q);
-
+ mutex_unlock(&hlist_mut);
+ D("%s returning rc= %d\n", __func__, rc);
return rc;
}
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
new file mode 100644
index 0000000..13fbd1f
--- /dev/null
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -0,0 +1,275 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Based on videobuf-dma-contig.c,
+ * (c) 2008 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * helper functions for physically contiguous pmem capture buffers
+ * The functions support contiguous memory allocations using pmem
+ * kernel API.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <linux/memory_alloc.h>
+#include <media/videobuf2-msm-mem.h>
+#include <media/msm_camera.h>
+#include <mach/memory.h>
+
+#include <media/videobuf2-core.h>
+
+#define MAGIC_PMEM 0x0733ac64
+#define MAGIC_CHECK(is, should) \
+ if (unlikely((is) != (should))) { \
+ pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
+ BUG(); \
+ }
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("videobuf-msm-mem: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static int32_t msm_mem_allocate(const size_t size)
+{
+ int32_t phyaddr;
+ phyaddr = allocate_contiguous_ebi_nomap(size, SZ_4K);
+ return phyaddr;
+}
+
+static int32_t msm_mem_free(const int32_t phyaddr)
+{
+ int32_t rc = 0;
+ free_contiguous_memory_by_paddr(phyaddr);
+ return rc;
+}
+
+static void videobuf2_vm_close(struct vm_area_struct *vma)
+{
+ struct videobuf2_contig_pmem *mem = vma->vm_private_data;
+ D("vm_close %p [count=%u,vma=%08lx-%08lx]\n",
+ mem, mem->count, vma->vm_start, vma->vm_end);
+ mem->count--;
+}
+static void videobuf2_vm_open(struct vm_area_struct *vma)
+{
+ struct videobuf2_contig_pmem *mem = vma->vm_private_data;
+ D("vm_open %p [count=%u,vma=%08lx-%08lx]\n",
+ mem, mem->count, vma->vm_start, vma->vm_end);
+ mem->count++;
+}
+
+static const struct vm_operations_struct videobuf2_vm_ops = {
+ .open = videobuf2_vm_open,
+ .close = videobuf2_vm_close,
+};
+
+static void *msm_vb2_mem_ops_alloc(void *alloc_ctx, unsigned long size)
+{
+ struct videobuf2_contig_pmem *mem;
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return ERR_PTR(-ENOMEM);
+
+ mem->magic = MAGIC_PMEM;
+ mem->size = PAGE_ALIGN(size);
+ mem->alloc_ctx = alloc_ctx;
+ mem->is_userptr = 0;
+ mem->phyaddr = msm_mem_allocate(mem->size);
+ if (IS_ERR((void *)mem->phyaddr)) {
+ pr_err("%s : pmem memory allocation failed\n", __func__);
+ kfree(mem);
+ return ERR_PTR(-ENOMEM);
+ }
+ return mem;
+}
+static void msm_vb2_mem_ops_put(void *buf_priv)
+{
+ struct videobuf2_contig_pmem *mem = buf_priv;
+ if (!mem->is_userptr)
+ msm_mem_free(mem->phyaddr);
+ kfree(mem);
+}
+int videobuf2_pmem_contig_mmap_get(struct videobuf2_contig_pmem *mem,
+ uint32_t yoffset,
+ uint32_t cbcroffset, int path)
+{
+ mem->y_off = yoffset;
+ mem->cbcr_off = cbcroffset;
+ mem->buffer_type = path;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(videobuf2_pmem_contig_mmap_get);
+
+/**
+ * videobuf_pmem_contig_user_get() - setup user space memory pointer
+ * @mem: per-buffer private videobuf-contig-pmem data
+ * @vb: video buffer to map
+ *
+ * This function validates and sets up a pointer to user space memory.
+ * Only physically contiguous pfn-mapped memory is accepted.
+ *
+ * Returns 0 if successful.
+ */
+int videobuf2_pmem_contig_user_get(struct videobuf2_contig_pmem *mem,
+ uint32_t yoffset, uint32_t cbcroffset,
+ uint32_t addr_offset, int path)
+{
+ unsigned long kvstart;
+ unsigned long len;
+ int rc;
+
+ if (mem->phyaddr != 0)
+ return 0;
+
+ rc = get_pmem_file((int)mem->vaddr, (unsigned long *)&mem->phyaddr,
+ &kvstart, &len, &mem->file);
+ if (rc < 0) {
+ pr_err("%s: get_pmem_file fd %d error %d\n",
+ __func__, (int)mem->vaddr, rc);
+ return rc;
+ }
+ mem->phyaddr += addr_offset;
+ mem->y_off = yoffset;
+ mem->cbcr_off = cbcroffset;
+ mem->buffer_type = path;
+ return rc;
+}
+EXPORT_SYMBOL_GPL(videobuf2_pmem_contig_user_get);
+
+void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem)
+{
+ if (mem->is_userptr)
+ put_pmem_file(mem->file);
+ mem->is_userptr = 0;
+ mem->phyaddr = 0;
+ mem->size = 0;
+}
+EXPORT_SYMBOL_GPL(videobuf2_pmem_contig_user_put);
+
+static void *msm_vb2_mem_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, int write)
+{
+ struct videobuf2_contig_pmem *mem;
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return ERR_PTR(-ENOMEM);
+ mem->magic = MAGIC_PMEM;
+ mem->is_userptr = 1;
+ mem->vaddr = (void *)vaddr;
+ mem->size = size;
+ mem->alloc_ctx = alloc_ctx;
+ return mem;
+}
+static void msm_vb2_mem_ops_put_userptr(void *buf_priv)
+{
+ kfree(buf_priv);
+}
+
+static void *msm_vb2_mem_ops_vaddr(void *buf_priv)
+{
+ struct videobuf2_contig_pmem *mem = buf_priv;
+ return mem->vaddr;
+}
+static void *msm_vb2_mem_ops_cookie(void *buf_priv)
+{
+ return buf_priv;
+}
+static unsigned int msm_vb2_mem_ops_num_users(void *buf_priv)
+{
+ struct videobuf2_contig_pmem *mem = buf_priv;
+ MAGIC_CHECK(mem->magic, MAGIC_PMEM);
+ return mem->count;
+}
+static int msm_vb2_mem_ops_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+ struct videobuf2_contig_pmem *mem;
+ int retval;
+ unsigned long size;
+ D("%s\n", __func__);
+ mem = buf_priv;
+ D("mem = 0x%x\n", (u32)mem);
+ BUG_ON(!mem);
+ MAGIC_CHECK(mem->magic, MAGIC_PMEM);
+
+ /* Try to remap memory */
+ size = vma->vm_end - vma->vm_start;
+ size = (size < mem->size) ? size : mem->size;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ retval = remap_pfn_range(vma, vma->vm_start,
+ mem->phyaddr >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+ if (retval) {
+ pr_err("mmap: remap failed with error %d. ", retval);
+ goto error;
+ }
+ mem->vaddr = (void *)vma->vm_start;
+ vma->vm_ops = &videobuf2_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND;
+ vma->vm_private_data = mem;
+
+ D("mmap %p: %08lx-%08lx (%lx) pgoff %08lx\n",
+ map, vma->vm_start, vma->vm_end,
+ (long int)mem->bsize, vma->vm_pgoff);
+ videobuf2_vm_open(vma);
+ return 0;
+error:
+ return -ENOMEM;
+}
+
+static struct vb2_mem_ops msm_vb2_mem_ops = {
+ .alloc = msm_vb2_mem_ops_alloc,
+ .put = msm_vb2_mem_ops_put,
+ .get_userptr = msm_vb2_mem_ops_get_userptr,
+ .put_userptr = msm_vb2_mem_ops_put_userptr,
+ .vaddr = msm_vb2_mem_ops_vaddr,
+ .cookie = msm_vb2_mem_ops_cookie,
+ .num_users = msm_vb2_mem_ops_num_users,
+ .mmap = msm_vb2_mem_ops_mmap
+};
+
+void videobuf2_queue_pmem_contig_init(struct vb2_queue *q,
+ enum v4l2_buf_type type,
+ const struct vb2_ops *ops,
+ unsigned int size,
+ void *priv)
+{
+ memset(q, 0, sizeof(struct vb2_queue));
+ q->mem_ops = &msm_vb2_mem_ops;
+ q->ops = ops;
+ q->drv_priv = priv;
+ q->type = type;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->io_flags = 0;
+ q->buf_struct_size = size;
+ vb2_queue_init(q);
+}
+EXPORT_SYMBOL_GPL(videobuf2_queue_pmem_contig_init);
+
+int videobuf2_to_pmem_contig(struct vb2_buffer *vb, unsigned int plane_no)
+{
+ struct videobuf2_contig_pmem *mem;
+ mem = vb2_plane_cookie(vb, plane_no);
+ BUG_ON(!mem);
+ MAGIC_CHECK(mem->magic, MAGIC_PMEM);
+ return mem->phyaddr;
+}
+EXPORT_SYMBOL_GPL(videobuf2_to_pmem_contig);
+
+MODULE_DESCRIPTION("helper module to manage video4linux PMEM contig buffers");
+MODULE_LICENSE("GPL v2");