[media] V4L: mx3-camera: prepare to support multi-size buffers
Prepare the mx3_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, which makes it superfluous for this driver. Its functionality is moved into .buf_queue(). Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
b5518a4151
commit
07f9244804
|
@ -114,6 +114,7 @@ struct mx3_camera_dev {
|
||||||
struct list_head capture;
|
struct list_head capture;
|
||||||
spinlock_t lock; /* Protects video buffer lists */
|
spinlock_t lock; /* Protects video buffer lists */
|
||||||
struct mx3_camera_buffer *active;
|
struct mx3_camera_buffer *active;
|
||||||
|
size_t buf_total;
|
||||||
struct vb2_alloc_ctx *alloc_ctx;
|
struct vb2_alloc_ctx *alloc_ctx;
|
||||||
enum v4l2_field field;
|
enum v4l2_field field;
|
||||||
int sequence;
|
int sequence;
|
||||||
|
@ -198,73 +199,46 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
|
||||||
struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
|
struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
|
||||||
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
||||||
struct mx3_camera_dev *mx3_cam = ici->priv;
|
struct mx3_camera_dev *mx3_cam = 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 (bytes_per_line < 0)
|
|
||||||
return bytes_per_line;
|
|
||||||
|
|
||||||
if (!mx3_cam->idmac_channel[0])
|
if (!mx3_cam->idmac_channel[0])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
*num_planes = 1;
|
if (fmt) {
|
||||||
|
const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
|
||||||
mx3_cam->sequence = 0;
|
fmt->fmt.pix.pixelformat);
|
||||||
sizes[0] = bytes_per_line * icd->user_height;
|
if (!xlate)
|
||||||
alloc_ctxs[0] = mx3_cam->alloc_ctx;
|
return -EINVAL;
|
||||||
|
bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
|
||||||
if (!*count)
|
xlate->host_fmt);
|
||||||
*count = 32;
|
height = fmt->fmt.pix.height;
|
||||||
|
} else {
|
||||||
if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
|
/* Called from VIDIOC_REQBUFS or in compatibility mode */
|
||||||
*count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0];
|
bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mx3_videobuf_prepare(struct vb2_buffer *vb)
|
|
||||||
{
|
|
||||||
struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
|
|
||||||
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
|
||||||
struct mx3_camera_dev *mx3_cam = ici->priv;
|
|
||||||
struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
|
|
||||||
struct scatterlist *sg;
|
|
||||||
struct mx3_camera_buffer *buf;
|
|
||||||
size_t new_size;
|
|
||||||
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
|
||||||
icd->current_fmt->host_fmt);
|
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;
|
||||||
|
|
||||||
buf = to_mx3_vb(vb);
|
sizes[0] = bytes_per_line * height;
|
||||||
sg = &buf->sg;
|
|
||||||
|
|
||||||
new_size = bytes_per_line * icd->user_height;
|
alloc_ctxs[0] = mx3_cam->alloc_ctx;
|
||||||
|
|
||||||
if (vb2_plane_size(vb, 0) < new_size) {
|
if (!vq->num_buffers)
|
||||||
dev_err(icd->parent, "Buffer too small (%lu < %zu)\n",
|
mx3_cam->sequence = 0;
|
||||||
vb2_plane_size(vb, 0), new_size);
|
|
||||||
return -ENOBUFS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf->state == CSI_BUF_NEEDS_INIT) {
|
if (!*count)
|
||||||
sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0);
|
*count = 2;
|
||||||
sg_dma_len(sg) = new_size;
|
|
||||||
|
|
||||||
buf->txd = ichan->dma_chan.device->device_prep_slave_sg(
|
/* If *num_planes != 0, we have already verified *count. */
|
||||||
&ichan->dma_chan, sg, 1, DMA_FROM_DEVICE,
|
if (!*num_planes &&
|
||||||
DMA_PREP_INTERRUPT);
|
sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024)
|
||||||
if (!buf->txd)
|
*count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) /
|
||||||
return -EIO;
|
sizes[0];
|
||||||
|
|
||||||
buf->txd->callback_param = buf->txd;
|
*num_planes = 1;
|
||||||
buf->txd->callback = mx3_cam_dma_done;
|
|
||||||
|
|
||||||
buf->state = CSI_BUF_PREPARED;
|
|
||||||
}
|
|
||||||
|
|
||||||
vb2_set_plane_payload(vb, 0, new_size);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -288,28 +262,58 @@ static void mx3_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 mx3_camera_dev *mx3_cam = ici->priv;
|
struct mx3_camera_dev *mx3_cam = ici->priv;
|
||||||
struct mx3_camera_buffer *buf = to_mx3_vb(vb);
|
struct mx3_camera_buffer *buf = to_mx3_vb(vb);
|
||||||
struct dma_async_tx_descriptor *txd = buf->txd;
|
struct scatterlist *sg = &buf->sg;
|
||||||
struct idmac_channel *ichan = to_idmac_chan(txd->chan);
|
struct dma_async_tx_descriptor *txd;
|
||||||
|
struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
|
||||||
struct idmac_video_param *video = &ichan->params.video;
|
struct idmac_video_param *video = &ichan->params.video;
|
||||||
dma_cookie_t cookie;
|
const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
|
||||||
u32 fourcc = icd->current_fmt->host_fmt->fourcc;
|
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, host_fmt);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
dma_cookie_t cookie;
|
||||||
|
size_t new_size;
|
||||||
|
|
||||||
|
BUG_ON(bytes_per_line <= 0);
|
||||||
|
|
||||||
|
new_size = bytes_per_line * icd->user_height;
|
||||||
|
|
||||||
|
if (vb2_plane_size(vb, 0) < new_size) {
|
||||||
|
dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n",
|
||||||
|
vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf->state == CSI_BUF_NEEDS_INIT) {
|
||||||
|
sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0);
|
||||||
|
sg_dma_len(sg) = new_size;
|
||||||
|
|
||||||
|
txd = ichan->dma_chan.device->device_prep_slave_sg(
|
||||||
|
&ichan->dma_chan, sg, 1, DMA_FROM_DEVICE,
|
||||||
|
DMA_PREP_INTERRUPT);
|
||||||
|
if (!txd)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
txd->callback_param = txd;
|
||||||
|
txd->callback = mx3_cam_dma_done;
|
||||||
|
|
||||||
|
buf->state = CSI_BUF_PREPARED;
|
||||||
|
buf->txd = txd;
|
||||||
|
} else {
|
||||||
|
txd = buf->txd;
|
||||||
|
}
|
||||||
|
|
||||||
|
vb2_set_plane_payload(vb, 0, new_size);
|
||||||
|
|
||||||
/* This is the configuration of one sg-element */
|
/* This is the configuration of one sg-element */
|
||||||
video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc);
|
video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc);
|
||||||
|
|
||||||
if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) {
|
if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) {
|
||||||
/*
|
/*
|
||||||
* If the IPU DMA channel is configured to transport
|
* If the IPU DMA channel is configured to transfer generic
|
||||||
* generic 8-bit data, we have to set up correctly the
|
* 8-bit data, we have to set up the geometry parameters
|
||||||
* geometry parameters upon the current pixel format.
|
* correctly, according to the current pixel format. The DMA
|
||||||
* So, since the DMA horizontal parameters are expressed
|
* horizontal parameters in this case are expressed in bytes,
|
||||||
* in bytes not pixels, convert these in the right unit.
|
* not in pixels.
|
||||||
*/
|
*/
|
||||||
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
|
||||||
icd->current_fmt->host_fmt);
|
|
||||||
BUG_ON(bytes_per_line <= 0);
|
|
||||||
|
|
||||||
video->out_width = bytes_per_line;
|
video->out_width = bytes_per_line;
|
||||||
video->out_height = icd->user_height;
|
video->out_height = icd->user_height;
|
||||||
video->out_stride = bytes_per_line;
|
video->out_stride = bytes_per_line;
|
||||||
|
@ -353,6 +357,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
|
||||||
mx3_cam->active = NULL;
|
mx3_cam->active = NULL;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&mx3_cam->lock, flags);
|
spin_unlock_irqrestore(&mx3_cam->lock, flags);
|
||||||
|
error:
|
||||||
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
|
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,17 +391,24 @@ static void mx3_videobuf_release(struct vb2_buffer *vb)
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&mx3_cam->lock, flags);
|
spin_unlock_irqrestore(&mx3_cam->lock, flags);
|
||||||
|
|
||||||
|
mx3_cam->buf_total -= vb2_plane_size(vb, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mx3_videobuf_init(struct vb2_buffer *vb)
|
static int mx3_videobuf_init(struct vb2_buffer *vb)
|
||||||
{
|
{
|
||||||
|
struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
|
||||||
|
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
||||||
|
struct mx3_camera_dev *mx3_cam = ici->priv;
|
||||||
struct mx3_camera_buffer *buf = to_mx3_vb(vb);
|
struct mx3_camera_buffer *buf = to_mx3_vb(vb);
|
||||||
|
|
||||||
/* This is for locking debugging only */
|
/* This is for locking debugging only */
|
||||||
INIT_LIST_HEAD(&buf->queue);
|
INIT_LIST_HEAD(&buf->queue);
|
||||||
sg_init_table(&buf->sg, 1);
|
sg_init_table(&buf->sg, 1);
|
||||||
|
|
||||||
buf->state = CSI_BUF_NEEDS_INIT;
|
buf->state = CSI_BUF_NEEDS_INIT;
|
||||||
buf->txd = NULL;
|
|
||||||
|
mx3_cam->buf_total += vb2_plane_size(vb, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -407,13 +419,12 @@ static int mx3_stop_streaming(struct vb2_queue *q)
|
||||||
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
||||||
struct mx3_camera_dev *mx3_cam = ici->priv;
|
struct mx3_camera_dev *mx3_cam = ici->priv;
|
||||||
struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
|
struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
|
||||||
struct dma_chan *chan;
|
|
||||||
struct mx3_camera_buffer *buf, *tmp;
|
struct mx3_camera_buffer *buf, *tmp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (ichan) {
|
if (ichan) {
|
||||||
chan = &ichan->dma_chan;
|
struct dma_chan *chan = &ichan->dma_chan;
|
||||||
chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
|
chan->device->device_control(chan, DMA_PAUSE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&mx3_cam->lock, flags);
|
spin_lock_irqsave(&mx3_cam->lock, flags);
|
||||||
|
@ -421,8 +432,8 @@ static int mx3_stop_streaming(struct vb2_queue *q)
|
||||||
mx3_cam->active = NULL;
|
mx3_cam->active = NULL;
|
||||||
|
|
||||||
list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) {
|
list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) {
|
||||||
buf->state = CSI_BUF_NEEDS_INIT;
|
|
||||||
list_del_init(&buf->queue);
|
list_del_init(&buf->queue);
|
||||||
|
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&mx3_cam->lock, flags);
|
spin_unlock_irqrestore(&mx3_cam->lock, flags);
|
||||||
|
@ -432,7 +443,6 @@ static int mx3_stop_streaming(struct vb2_queue *q)
|
||||||
|
|
||||||
static struct vb2_ops mx3_videobuf_ops = {
|
static struct vb2_ops mx3_videobuf_ops = {
|
||||||
.queue_setup = mx3_videobuf_setup,
|
.queue_setup = mx3_videobuf_setup,
|
||||||
.buf_prepare = mx3_videobuf_prepare,
|
|
||||||
.buf_queue = mx3_videobuf_queue,
|
.buf_queue = mx3_videobuf_queue,
|
||||||
.buf_cleanup = mx3_videobuf_release,
|
.buf_cleanup = mx3_videobuf_release,
|
||||||
.buf_init = mx3_videobuf_init,
|
.buf_init = mx3_videobuf_init,
|
||||||
|
@ -516,6 +526,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
|
||||||
|
|
||||||
mx3_camera_activate(mx3_cam, icd);
|
mx3_camera_activate(mx3_cam, icd);
|
||||||
|
|
||||||
|
mx3_cam->buf_total = 0;
|
||||||
mx3_cam->icd = icd;
|
mx3_cam->icd = icd;
|
||||||
|
|
||||||
dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
|
dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
|
||||||
|
@ -1263,8 +1274,6 @@ static int __devexit mx3_camera_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
dmaengine_put();
|
dmaengine_put();
|
||||||
|
|
||||||
dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue