diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2011-11-03 09:11:11 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-11-03 16:28:38 -0400 |
commit | b5518a415158320d41bc31d6887d5c2aa1c9a164 (patch) | |
tree | 90b9d857b5219231906526673bac62eaf47eeaa4 /drivers | |
parent | 91b6286ff3190fece7314b61ef330da96c4d644f (diff) |
[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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/sh_mobile_ceu_camera.c | 124 |
1 files changed, 81 insertions, 43 deletions
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 5d5781bd144..a3153ca1408 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -90,7 +90,6 @@ | |||
90 | struct sh_mobile_ceu_buffer { | 90 | struct sh_mobile_ceu_buffer { |
91 | struct vb2_buffer vb; /* v4l buffer must be first */ | 91 | struct vb2_buffer vb; /* v4l buffer must be first */ |
92 | struct list_head queue; | 92 | struct list_head queue; |
93 | enum v4l2_mbus_pixelcode code; | ||
94 | }; | 93 | }; |
95 | 94 | ||
96 | struct sh_mobile_ceu_dev { | 95 | struct sh_mobile_ceu_dev { |
@@ -100,7 +99,8 @@ struct sh_mobile_ceu_dev { | |||
100 | 99 | ||
101 | unsigned int irq; | 100 | unsigned int irq; |
102 | void __iomem *base; | 101 | void __iomem *base; |
103 | unsigned long video_limit; | 102 | size_t video_limit; |
103 | size_t buf_total; | ||
104 | 104 | ||
105 | spinlock_t lock; /* Protects video buffer lists */ | 105 | spinlock_t lock; /* Protects video buffer lists */ |
106 | struct list_head capture; | 106 | struct list_head capture; |
@@ -192,6 +192,12 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) | |||
192 | /* | 192 | /* |
193 | * Videobuf operations | 193 | * Videobuf operations |
194 | */ | 194 | */ |
195 | |||
196 | /* | ||
197 | * .queue_setup() is called to check, whether the driver can accept the | ||
198 | * requested number of buffers and to fill in plane sizes | ||
199 | * for the current frame format if required | ||
200 | */ | ||
195 | static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, | 201 | static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, |
196 | const struct v4l2_format *fmt, | 202 | const struct v4l2_format *fmt, |
197 | unsigned int *count, unsigned int *num_planes, | 203 | unsigned int *count, unsigned int *num_planes, |
@@ -200,26 +206,47 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, | |||
200 | struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); | 206 | struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); |
201 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 207 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
202 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 208 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
203 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 209 | int bytes_per_line; |
204 | icd->current_fmt->host_fmt); | 210 | unsigned int height; |
205 | 211 | ||
212 | if (fmt) { | ||
213 | const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, | ||
214 | fmt->fmt.pix.pixelformat); | ||
215 | if (!xlate) | ||
216 | return -EINVAL; | ||
217 | bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, | ||
218 | xlate->host_fmt); | ||
219 | height = fmt->fmt.pix.height; | ||
220 | } else { | ||
221 | /* Called from VIDIOC_REQBUFS or in compatibility mode */ | ||
222 | bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
223 | icd->current_fmt->host_fmt); | ||
224 | height = icd->user_height; | ||
225 | } | ||
206 | if (bytes_per_line < 0) | 226 | if (bytes_per_line < 0) |
207 | return bytes_per_line; | 227 | return bytes_per_line; |
208 | 228 | ||
209 | *num_planes = 1; | 229 | sizes[0] = bytes_per_line * height; |
210 | 230 | ||
211 | pcdev->sequence = 0; | ||
212 | sizes[0] = bytes_per_line * icd->user_height; | ||
213 | alloc_ctxs[0] = pcdev->alloc_ctx; | 231 | alloc_ctxs[0] = pcdev->alloc_ctx; |
214 | 232 | ||
233 | if (!vq->num_buffers) | ||
234 | pcdev->sequence = 0; | ||
235 | |||
215 | if (!*count) | 236 | if (!*count) |
216 | *count = 2; | 237 | *count = 2; |
217 | 238 | ||
218 | if (pcdev->video_limit) { | 239 | /* If *num_planes != 0, we have already verified *count. */ |
219 | if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit) | 240 | if (pcdev->video_limit && !*num_planes) { |
220 | *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]); | 241 | size_t size = PAGE_ALIGN(sizes[0]) * *count; |
242 | |||
243 | if (size + pcdev->buf_total > pcdev->video_limit) | ||
244 | *count = (pcdev->video_limit - pcdev->buf_total) / | ||
245 | PAGE_ALIGN(sizes[0]); | ||
221 | } | 246 | } |
222 | 247 | ||
248 | *num_planes = 1; | ||
249 | |||
223 | dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); | 250 | dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); |
224 | 251 | ||
225 | return 0; | 252 | return 0; |
@@ -331,23 +358,40 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
331 | 358 | ||
332 | static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) | 359 | static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) |
333 | { | 360 | { |
361 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
362 | |||
363 | /* Added list head initialization on alloc */ | ||
364 | WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | ||
370 | { | ||
334 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | 371 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); |
335 | struct sh_mobile_ceu_buffer *buf; | 372 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
373 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
374 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
375 | unsigned long size; | ||
336 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 376 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
337 | icd->current_fmt->host_fmt); | 377 | icd->current_fmt->host_fmt); |
338 | unsigned long size; | ||
339 | 378 | ||
340 | if (bytes_per_line < 0) | 379 | if (bytes_per_line < 0) |
341 | return bytes_per_line; | 380 | goto error; |
342 | 381 | ||
343 | buf = to_ceu_vb(vb); | 382 | size = icd->user_height * bytes_per_line; |
383 | |||
384 | if (vb2_plane_size(vb, 0) < size) { | ||
385 | dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n", | ||
386 | vb->v4l2_buf.index, vb2_plane_size(vb, 0), size); | ||
387 | goto error; | ||
388 | } | ||
389 | |||
390 | vb2_set_plane_payload(vb, 0, size); | ||
344 | 391 | ||
345 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | 392 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, |
346 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | 393 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); |
347 | 394 | ||
348 | /* Added list head initialization on alloc */ | ||
349 | WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); | ||
350 | |||
351 | #ifdef DEBUG | 395 | #ifdef DEBUG |
352 | /* | 396 | /* |
353 | * This can be useful if you want to see if we actually fill | 397 | * This can be useful if you want to see if we actually fill |
@@ -357,31 +401,6 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) | |||
357 | memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); | 401 | memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); |
358 | #endif | 402 | #endif |
359 | 403 | ||
360 | BUG_ON(NULL == icd->current_fmt); | ||
361 | |||
362 | size = icd->user_height * bytes_per_line; | ||
363 | |||
364 | if (vb2_plane_size(vb, 0) < size) { | ||
365 | dev_err(icd->parent, "Buffer too small (%lu < %lu)\n", | ||
366 | vb2_plane_size(vb, 0), size); | ||
367 | return -ENOBUFS; | ||
368 | } | ||
369 | |||
370 | vb2_set_plane_payload(vb, 0, size); | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | ||
376 | { | ||
377 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | ||
378 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
379 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
380 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
381 | |||
382 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
383 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
384 | |||
385 | spin_lock_irq(&pcdev->lock); | 404 | spin_lock_irq(&pcdev->lock); |
386 | list_add_tail(&buf->queue, &pcdev->capture); | 405 | list_add_tail(&buf->queue, &pcdev->capture); |
387 | 406 | ||
@@ -395,6 +414,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | |||
395 | sh_mobile_ceu_capture(pcdev); | 414 | sh_mobile_ceu_capture(pcdev); |
396 | } | 415 | } |
397 | spin_unlock_irq(&pcdev->lock); | 416 | spin_unlock_irq(&pcdev->lock); |
417 | |||
418 | return; | ||
419 | |||
420 | error: | ||
421 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
398 | } | 422 | } |
399 | 423 | ||
400 | static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) | 424 | 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) | |||
419 | if (buf->queue.next) | 443 | if (buf->queue.next) |
420 | list_del_init(&buf->queue); | 444 | list_del_init(&buf->queue); |
421 | 445 | ||
446 | pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0)); | ||
447 | dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, | ||
448 | pcdev->buf_total); | ||
449 | |||
422 | spin_unlock_irq(&pcdev->lock); | 450 | spin_unlock_irq(&pcdev->lock); |
423 | } | 451 | } |
424 | 452 | ||
425 | static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) | 453 | static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) |
426 | { | 454 | { |
455 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | ||
456 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
457 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
458 | |||
459 | pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0)); | ||
460 | dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, | ||
461 | pcdev->buf_total); | ||
462 | |||
427 | /* This is for locking debugging only */ | 463 | /* This is for locking debugging only */ |
428 | INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); | 464 | INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); |
429 | return 0; | 465 | return 0; |
@@ -525,6 +561,8 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | |||
525 | 561 | ||
526 | pm_runtime_get_sync(ici->v4l2_dev.dev); | 562 | pm_runtime_get_sync(ici->v4l2_dev.dev); |
527 | 563 | ||
564 | pcdev->buf_total = 0; | ||
565 | |||
528 | ret = sh_mobile_ceu_soft_reset(pcdev); | 566 | ret = sh_mobile_ceu_soft_reset(pcdev); |
529 | 567 | ||
530 | csi2_sd = find_csi2(pcdev); | 568 | csi2_sd = find_csi2(pcdev); |
@@ -1712,7 +1750,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
1712 | image_mode = false; | 1750 | image_mode = false; |
1713 | } | 1751 | } |
1714 | 1752 | ||
1715 | dev_info(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, | 1753 | dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, |
1716 | pix->width, pix->height); | 1754 | pix->width, pix->height); |
1717 | 1755 | ||
1718 | dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); | 1756 | dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); |