diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2011-11-03 09:14:00 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-11-03 16:28:39 -0400 |
commit | 07f92448045a23d27dbc3ece3abcb6bafc618d43 (patch) | |
tree | 8cbd51322016cbd7a3dd35eae92c4c55ec44df8d /drivers/media/video/mx3_camera.c | |
parent | b5518a415158320d41bc31d6887d5c2aa1c9a164 (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.c | 161 |
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 | |||
225 | static 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); |
360 | error: | ||
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 | ||
391 | static int mx3_videobuf_init(struct vb2_buffer *vb) | 398 | static 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 | ||
433 | static struct vb2_ops mx3_videobuf_ops = { | 444 | static 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 | ||