aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mx3_camera.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2011-11-03 09:14:00 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-11-03 16:28:39 -0400
commit07f92448045a23d27dbc3ece3abcb6bafc618d43 (patch)
tree8cbd51322016cbd7a3dd35eae92c4c55ec44df8d /drivers/media/video/mx3_camera.c
parentb5518a415158320d41bc31d6887d5c2aa1c9a164 (diff)
[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>
Diffstat (limited to 'drivers/media/video/mx3_camera.c')
-rw-r--r--drivers/media/video/mx3_camera.c161
1 files changed, 85 insertions, 76 deletions
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 24c2fe0714c5..f96f92f00f92 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -114,6 +114,7 @@ struct mx3_camera_dev {
114 struct list_head capture; 114 struct list_head capture;
115 spinlock_t lock; /* Protects video buffer lists */ 115 spinlock_t lock; /* Protects video buffer lists */
116 struct mx3_camera_buffer *active; 116 struct mx3_camera_buffer *active;
117 size_t buf_total;
117 struct vb2_alloc_ctx *alloc_ctx; 118 struct vb2_alloc_ctx *alloc_ctx;
118 enum v4l2_field field; 119 enum v4l2_field field;
119 int sequence; 120 int sequence;
@@ -198,73 +199,46 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
198 struct soc_camera_device *icd = soc_camera_from_vb2q(vq); 199 struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
199 struct soc_camera_host *ici = to_soc_camera_host(icd->parent); 200 struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
200 struct mx3_camera_dev *mx3_cam = ici->priv; 201 struct mx3_camera_dev *mx3_cam = ici->priv;
201 int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, 202 int bytes_per_line;
202 icd->current_fmt->host_fmt); 203 unsigned int height;
203
204 if (bytes_per_line < 0)
205 return bytes_per_line;
206 204
207 if (!mx3_cam->idmac_channel[0]) 205 if (!mx3_cam->idmac_channel[0])
208 return -EINVAL; 206 return -EINVAL;
209 207
210 *num_planes = 1; 208 if (fmt) {
211 209 const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
212 mx3_cam->sequence = 0; 210 fmt->fmt.pix.pixelformat);
213 sizes[0] = bytes_per_line * icd->user_height; 211 if (!xlate)
214 alloc_ctxs[0] = mx3_cam->alloc_ctx; 212 return -EINVAL;
215 213 bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
216 if (!*count) 214 xlate->host_fmt);
217 *count = 32; 215 height = fmt->fmt.pix.height;
218 216 } else {
219 if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) 217 /* Called from VIDIOC_REQBUFS or in compatibility mode */
220 *count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0]; 218 bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
221
222 return 0;
223}
224
225static int mx3_videobuf_prepare(struct vb2_buffer *vb)
226{
227 struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
228 struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
229 struct mx3_camera_dev *mx3_cam = ici->priv;
230 struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
231 struct scatterlist *sg;
232 struct mx3_camera_buffer *buf;
233 size_t new_size;
234 int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
235 icd->current_fmt->host_fmt); 219 icd->current_fmt->host_fmt);
236 220 height = icd->user_height;
221 }
237 if (bytes_per_line < 0) 222 if (bytes_per_line < 0)
238 return bytes_per_line; 223 return bytes_per_line;
239 224
240 buf = to_mx3_vb(vb); 225 sizes[0] = bytes_per_line * height;
241 sg = &buf->sg;
242
243 new_size = bytes_per_line * icd->user_height;
244
245 if (vb2_plane_size(vb, 0) < new_size) {
246 dev_err(icd->parent, "Buffer too small (%lu < %zu)\n",
247 vb2_plane_size(vb, 0), new_size);
248 return -ENOBUFS;
249 }
250 226
251 if (buf->state == CSI_BUF_NEEDS_INIT) { 227 alloc_ctxs[0] = mx3_cam->alloc_ctx;
252 sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0);
253 sg_dma_len(sg) = new_size;
254 228
255 buf->txd = ichan->dma_chan.device->device_prep_slave_sg( 229 if (!vq->num_buffers)
256 &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, 230 mx3_cam->sequence = 0;
257 DMA_PREP_INTERRUPT);
258 if (!buf->txd)
259 return -EIO;
260 231
261 buf->txd->callback_param = buf->txd; 232 if (!*count)
262 buf->txd->callback = mx3_cam_dma_done; 233 *count = 2;
263 234
264 buf->state = CSI_BUF_PREPARED; 235 /* If *num_planes != 0, we have already verified *count. */
265 } 236 if (!*num_planes &&
237 sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024)
238 *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) /
239 sizes[0];
266 240
267 vb2_set_plane_payload(vb, 0, new_size); 241 *num_planes = 1;
268 242
269 return 0; 243 return 0;
270} 244}
@@ -288,28 +262,58 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
288 struct soc_camera_host *ici = to_soc_camera_host(icd->parent); 262 struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
289 struct mx3_camera_dev *mx3_cam = ici->priv; 263 struct mx3_camera_dev *mx3_cam = ici->priv;
290 struct mx3_camera_buffer *buf = to_mx3_vb(vb); 264 struct mx3_camera_buffer *buf = to_mx3_vb(vb);
291 struct dma_async_tx_descriptor *txd = buf->txd; 265 struct scatterlist *sg = &buf->sg;
292 struct idmac_channel *ichan = to_idmac_chan(txd->chan); 266 struct dma_async_tx_descriptor *txd;
267 struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
293 struct idmac_video_param *video = &ichan->params.video; 268 struct idmac_video_param *video = &ichan->params.video;
294 dma_cookie_t cookie; 269 const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
295 u32 fourcc = icd->current_fmt->host_fmt->fourcc; 270 int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, host_fmt);
296 unsigned long flags; 271 unsigned long flags;
272 dma_cookie_t cookie;
273 size_t new_size;
274
275 BUG_ON(bytes_per_line <= 0);
276
277 new_size = bytes_per_line * icd->user_height;
278
279 if (vb2_plane_size(vb, 0) < new_size) {
280 dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n",
281 vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size);
282 goto error;
283 }
284
285 if (buf->state == CSI_BUF_NEEDS_INIT) {
286 sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0);
287 sg_dma_len(sg) = new_size;
288
289 txd = ichan->dma_chan.device->device_prep_slave_sg(
290 &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE,
291 DMA_PREP_INTERRUPT);
292 if (!txd)
293 goto error;
294
295 txd->callback_param = txd;
296 txd->callback = mx3_cam_dma_done;
297
298 buf->state = CSI_BUF_PREPARED;
299 buf->txd = txd;
300 } else {
301 txd = buf->txd;
302 }
303
304 vb2_set_plane_payload(vb, 0, new_size);
297 305
298 /* This is the configuration of one sg-element */ 306 /* This is the configuration of one sg-element */
299 video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); 307 video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc);
300 308
301 if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { 309 if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) {
302 /* 310 /*
303 * If the IPU DMA channel is configured to transport 311 * If the IPU DMA channel is configured to transfer generic
304 * generic 8-bit data, we have to set up correctly the 312 * 8-bit data, we have to set up the geometry parameters
305 * geometry parameters upon the current pixel format. 313 * correctly, according to the current pixel format. The DMA
306 * So, since the DMA horizontal parameters are expressed 314 * horizontal parameters in this case are expressed in bytes,
307 * in bytes not pixels, convert these in the right unit. 315 * not in pixels.
308 */ 316 */
309 int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
310 icd->current_fmt->host_fmt);
311 BUG_ON(bytes_per_line <= 0);
312
313 video->out_width = bytes_per_line; 317 video->out_width = bytes_per_line;
314 video->out_height = icd->user_height; 318 video->out_height = icd->user_height;
315 video->out_stride = bytes_per_line; 319 video->out_stride = bytes_per_line;
@@ -353,6 +357,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
353 mx3_cam->active = NULL; 357 mx3_cam->active = NULL;
354 358
355 spin_unlock_irqrestore(&mx3_cam->lock, flags); 359 spin_unlock_irqrestore(&mx3_cam->lock, flags);
360error:
356 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); 361 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
357} 362}
358 363
@@ -386,17 +391,24 @@ static void mx3_videobuf_release(struct vb2_buffer *vb)
386 } 391 }
387 392
388 spin_unlock_irqrestore(&mx3_cam->lock, flags); 393 spin_unlock_irqrestore(&mx3_cam->lock, flags);
394
395 mx3_cam->buf_total -= vb2_plane_size(vb, 0);
389} 396}
390 397
391static int mx3_videobuf_init(struct vb2_buffer *vb) 398static int mx3_videobuf_init(struct vb2_buffer *vb)
392{ 399{
400 struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
401 struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
402 struct mx3_camera_dev *mx3_cam = ici->priv;
393 struct mx3_camera_buffer *buf = to_mx3_vb(vb); 403 struct mx3_camera_buffer *buf = to_mx3_vb(vb);
404
394 /* This is for locking debugging only */ 405 /* This is for locking debugging only */
395 INIT_LIST_HEAD(&buf->queue); 406 INIT_LIST_HEAD(&buf->queue);
396 sg_init_table(&buf->sg, 1); 407 sg_init_table(&buf->sg, 1);
397 408
398 buf->state = CSI_BUF_NEEDS_INIT; 409 buf->state = CSI_BUF_NEEDS_INIT;
399 buf->txd = NULL; 410
411 mx3_cam->buf_total += vb2_plane_size(vb, 0);
400 412
401 return 0; 413 return 0;
402} 414}
@@ -407,13 +419,12 @@ static int mx3_stop_streaming(struct vb2_queue *q)
407 struct soc_camera_host *ici = to_soc_camera_host(icd->parent); 419 struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
408 struct mx3_camera_dev *mx3_cam = ici->priv; 420 struct mx3_camera_dev *mx3_cam = ici->priv;
409 struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; 421 struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
410 struct dma_chan *chan;
411 struct mx3_camera_buffer *buf, *tmp; 422 struct mx3_camera_buffer *buf, *tmp;
412 unsigned long flags; 423 unsigned long flags;
413 424
414 if (ichan) { 425 if (ichan) {
415 chan = &ichan->dma_chan; 426 struct dma_chan *chan = &ichan->dma_chan;
416 chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); 427 chan->device->device_control(chan, DMA_PAUSE, 0);
417 } 428 }
418 429
419 spin_lock_irqsave(&mx3_cam->lock, flags); 430 spin_lock_irqsave(&mx3_cam->lock, flags);
@@ -421,8 +432,8 @@ static int mx3_stop_streaming(struct vb2_queue *q)
421 mx3_cam->active = NULL; 432 mx3_cam->active = NULL;
422 433
423 list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { 434 list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) {
424 buf->state = CSI_BUF_NEEDS_INIT;
425 list_del_init(&buf->queue); 435 list_del_init(&buf->queue);
436 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
426 } 437 }
427 438
428 spin_unlock_irqrestore(&mx3_cam->lock, flags); 439 spin_unlock_irqrestore(&mx3_cam->lock, flags);
@@ -432,7 +443,6 @@ static int mx3_stop_streaming(struct vb2_queue *q)
432 443
433static struct vb2_ops mx3_videobuf_ops = { 444static struct vb2_ops mx3_videobuf_ops = {
434 .queue_setup = mx3_videobuf_setup, 445 .queue_setup = mx3_videobuf_setup,
435 .buf_prepare = mx3_videobuf_prepare,
436 .buf_queue = mx3_videobuf_queue, 446 .buf_queue = mx3_videobuf_queue,
437 .buf_cleanup = mx3_videobuf_release, 447 .buf_cleanup = mx3_videobuf_release,
438 .buf_init = mx3_videobuf_init, 448 .buf_init = mx3_videobuf_init,
@@ -516,6 +526,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
516 526
517 mx3_camera_activate(mx3_cam, icd); 527 mx3_camera_activate(mx3_cam, icd);
518 528
529 mx3_cam->buf_total = 0;
519 mx3_cam->icd = icd; 530 mx3_cam->icd = icd;
520 531
521 dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", 532 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)
1263 1274
1264 dmaengine_put(); 1275 dmaengine_put();
1265 1276
1266 dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n");
1267
1268 return 0; 1277 return 0;
1269} 1278}
1270 1279