[media] V4L: sh-mobile-ceu-camera: prepare to support multi-size buffers
Prepare the sh_mobile_ceu_camera friver to support the new VIDIOC_CREATE_BUFS and VIDIOC_PREPARE_BUF ioctl()s. The .queue_setup() vb2 operation must be able to handle buffer sizes, provided by the caller, and the .buf_prepare() operation must not use the currently configured frame format for its operation. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
91b6286ff3
commit
b5518a4151
|
@ -90,7 +90,6 @@
|
||||||
struct sh_mobile_ceu_buffer {
|
struct sh_mobile_ceu_buffer {
|
||||||
struct vb2_buffer vb; /* v4l buffer must be first */
|
struct vb2_buffer vb; /* v4l buffer must be first */
|
||||||
struct list_head queue;
|
struct list_head queue;
|
||||||
enum v4l2_mbus_pixelcode code;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sh_mobile_ceu_dev {
|
struct sh_mobile_ceu_dev {
|
||||||
|
@ -100,7 +99,8 @@ struct sh_mobile_ceu_dev {
|
||||||
|
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
unsigned long video_limit;
|
size_t video_limit;
|
||||||
|
size_t buf_total;
|
||||||
|
|
||||||
spinlock_t lock; /* Protects video buffer lists */
|
spinlock_t lock; /* Protects video buffer lists */
|
||||||
struct list_head capture;
|
struct list_head capture;
|
||||||
|
@ -192,6 +192,12 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
|
||||||
/*
|
/*
|
||||||
* Videobuf operations
|
* Videobuf operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* .queue_setup() is called to check, whether the driver can accept the
|
||||||
|
* requested number of buffers and to fill in plane sizes
|
||||||
|
* for the current frame format if required
|
||||||
|
*/
|
||||||
static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
|
static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
|
||||||
const struct v4l2_format *fmt,
|
const struct v4l2_format *fmt,
|
||||||
unsigned int *count, unsigned int *num_planes,
|
unsigned int *count, unsigned int *num_planes,
|
||||||
|
@ -200,26 +206,47 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
|
||||||
struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
|
struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
|
||||||
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
||||||
struct sh_mobile_ceu_dev *pcdev = ici->priv;
|
struct sh_mobile_ceu_dev *pcdev = ici->priv;
|
||||||
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
int bytes_per_line;
|
||||||
icd->current_fmt->host_fmt);
|
unsigned int height;
|
||||||
|
|
||||||
|
if (fmt) {
|
||||||
|
const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
|
||||||
|
fmt->fmt.pix.pixelformat);
|
||||||
|
if (!xlate)
|
||||||
|
return -EINVAL;
|
||||||
|
bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
|
||||||
|
xlate->host_fmt);
|
||||||
|
height = fmt->fmt.pix.height;
|
||||||
|
} else {
|
||||||
|
/* Called from VIDIOC_REQBUFS or in compatibility mode */
|
||||||
|
bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
||||||
|
icd->current_fmt->host_fmt);
|
||||||
|
height = icd->user_height;
|
||||||
|
}
|
||||||
if (bytes_per_line < 0)
|
if (bytes_per_line < 0)
|
||||||
return bytes_per_line;
|
return bytes_per_line;
|
||||||
|
|
||||||
*num_planes = 1;
|
sizes[0] = bytes_per_line * height;
|
||||||
|
|
||||||
pcdev->sequence = 0;
|
|
||||||
sizes[0] = bytes_per_line * icd->user_height;
|
|
||||||
alloc_ctxs[0] = pcdev->alloc_ctx;
|
alloc_ctxs[0] = pcdev->alloc_ctx;
|
||||||
|
|
||||||
|
if (!vq->num_buffers)
|
||||||
|
pcdev->sequence = 0;
|
||||||
|
|
||||||
if (!*count)
|
if (!*count)
|
||||||
*count = 2;
|
*count = 2;
|
||||||
|
|
||||||
if (pcdev->video_limit) {
|
/* If *num_planes != 0, we have already verified *count. */
|
||||||
if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit)
|
if (pcdev->video_limit && !*num_planes) {
|
||||||
*count = pcdev->video_limit / PAGE_ALIGN(sizes[0]);
|
size_t size = PAGE_ALIGN(sizes[0]) * *count;
|
||||||
|
|
||||||
|
if (size + pcdev->buf_total > pcdev->video_limit)
|
||||||
|
*count = (pcdev->video_limit - pcdev->buf_total) /
|
||||||
|
PAGE_ALIGN(sizes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*num_planes = 1;
|
||||||
|
|
||||||
dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]);
|
dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -331,44 +358,11 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
|
||||||
|
|
||||||
static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
|
static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
|
||||||
{
|
{
|
||||||
struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
|
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
|
||||||
struct sh_mobile_ceu_buffer *buf;
|
|
||||||
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
|
||||||
icd->current_fmt->host_fmt);
|
|
||||||
unsigned long size;
|
|
||||||
|
|
||||||
if (bytes_per_line < 0)
|
|
||||||
return bytes_per_line;
|
|
||||||
|
|
||||||
buf = to_ceu_vb(vb);
|
|
||||||
|
|
||||||
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
|
|
||||||
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
|
|
||||||
|
|
||||||
/* Added list head initialization on alloc */
|
/* Added list head initialization on alloc */
|
||||||
WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb);
|
WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb);
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
/*
|
|
||||||
* This can be useful if you want to see if we actually fill
|
|
||||||
* the buffer with something
|
|
||||||
*/
|
|
||||||
if (vb2_plane_vaddr(vb, 0))
|
|
||||||
memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BUG_ON(NULL == icd->current_fmt);
|
|
||||||
|
|
||||||
size = icd->user_height * bytes_per_line;
|
|
||||||
|
|
||||||
if (vb2_plane_size(vb, 0) < size) {
|
|
||||||
dev_err(icd->parent, "Buffer too small (%lu < %lu)\n",
|
|
||||||
vb2_plane_size(vb, 0), size);
|
|
||||||
return -ENOBUFS;
|
|
||||||
}
|
|
||||||
|
|
||||||
vb2_set_plane_payload(vb, 0, size);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,10 +372,35 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
|
||||||
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
||||||
struct sh_mobile_ceu_dev *pcdev = ici->priv;
|
struct sh_mobile_ceu_dev *pcdev = ici->priv;
|
||||||
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
|
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
|
||||||
|
unsigned long size;
|
||||||
|
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
||||||
|
icd->current_fmt->host_fmt);
|
||||||
|
|
||||||
|
if (bytes_per_line < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
size = icd->user_height * bytes_per_line;
|
||||||
|
|
||||||
|
if (vb2_plane_size(vb, 0) < size) {
|
||||||
|
dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n",
|
||||||
|
vb->v4l2_buf.index, vb2_plane_size(vb, 0), size);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
vb2_set_plane_payload(vb, 0, size);
|
||||||
|
|
||||||
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
|
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
|
||||||
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
|
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
/*
|
||||||
|
* This can be useful if you want to see if we actually fill
|
||||||
|
* the buffer with something
|
||||||
|
*/
|
||||||
|
if (vb2_plane_vaddr(vb, 0))
|
||||||
|
memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0));
|
||||||
|
#endif
|
||||||
|
|
||||||
spin_lock_irq(&pcdev->lock);
|
spin_lock_irq(&pcdev->lock);
|
||||||
list_add_tail(&buf->queue, &pcdev->capture);
|
list_add_tail(&buf->queue, &pcdev->capture);
|
||||||
|
|
||||||
|
@ -395,6 +414,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
|
||||||
sh_mobile_ceu_capture(pcdev);
|
sh_mobile_ceu_capture(pcdev);
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&pcdev->lock);
|
spin_unlock_irq(&pcdev->lock);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
|
static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
|
||||||
|
@ -419,11 +443,23 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
|
||||||
if (buf->queue.next)
|
if (buf->queue.next)
|
||||||
list_del_init(&buf->queue);
|
list_del_init(&buf->queue);
|
||||||
|
|
||||||
|
pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0));
|
||||||
|
dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__,
|
||||||
|
pcdev->buf_total);
|
||||||
|
|
||||||
spin_unlock_irq(&pcdev->lock);
|
spin_unlock_irq(&pcdev->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
|
static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
|
||||||
{
|
{
|
||||||
|
struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
|
||||||
|
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
||||||
|
struct sh_mobile_ceu_dev *pcdev = ici->priv;
|
||||||
|
|
||||||
|
pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0));
|
||||||
|
dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__,
|
||||||
|
pcdev->buf_total);
|
||||||
|
|
||||||
/* This is for locking debugging only */
|
/* This is for locking debugging only */
|
||||||
INIT_LIST_HEAD(&to_ceu_vb(vb)->queue);
|
INIT_LIST_HEAD(&to_ceu_vb(vb)->queue);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -525,6 +561,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
|
||||||
|
|
||||||
pm_runtime_get_sync(ici->v4l2_dev.dev);
|
pm_runtime_get_sync(ici->v4l2_dev.dev);
|
||||||
|
|
||||||
|
pcdev->buf_total = 0;
|
||||||
|
|
||||||
ret = sh_mobile_ceu_soft_reset(pcdev);
|
ret = sh_mobile_ceu_soft_reset(pcdev);
|
||||||
|
|
||||||
csi2_sd = find_csi2(pcdev);
|
csi2_sd = find_csi2(pcdev);
|
||||||
|
@ -1712,7 +1750,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
|
||||||
image_mode = false;
|
image_mode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code,
|
dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code,
|
||||||
pix->width, pix->height);
|
pix->width, pix->height);
|
||||||
|
|
||||||
dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);
|
dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height);
|
||||||
|
|
Loading…
Reference in New Issue