diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2008-04-22 09:40:23 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:09:45 -0400 |
commit | 5aa2110f3f33feb4a0c67a4996dc400dc594bc1d (patch) | |
tree | 7c7806b8edec85e7afdaea696b7106fa0d683c6f /drivers/media/video/pxa_camera.c | |
parent | e7c506881973d0c762d660005be54c4095219c59 (diff) |
V4L/DVB (7671): pxa-camera: fix DMA sg-list coalescing for more than 2 buffers
Currently the pxa-camera driver has a bug, visible when the user requests
more than 2 video buffers. When the third buffer is queued, it is not
appended to the DMA-descriptor list of the second buffer, but is again
appended to the first buffer. Fix it.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/pxa_camera.c')
-rw-r--r-- | drivers/media/video/pxa_camera.c | 35 |
1 files changed, 15 insertions, 20 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 1dcfd9109c57..7cc8e9b19fb7 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -102,11 +102,6 @@ struct pxa_buffer { | |||
102 | enum pxa_camera_active_dma active_dma; | 102 | enum pxa_camera_active_dma active_dma; |
103 | }; | 103 | }; |
104 | 104 | ||
105 | struct pxa_framebuffer_queue { | ||
106 | dma_addr_t sg_last_dma; | ||
107 | struct pxa_dma_desc *sg_last_cpu; | ||
108 | }; | ||
109 | |||
110 | struct pxa_camera_dev { | 105 | struct pxa_camera_dev { |
111 | struct device *dev; | 106 | struct device *dev; |
112 | /* PXA27x is only supposed to handle one camera on its Quick Capture | 107 | /* PXA27x is only supposed to handle one camera on its Quick Capture |
@@ -131,6 +126,7 @@ struct pxa_camera_dev { | |||
131 | spinlock_t lock; | 126 | spinlock_t lock; |
132 | 127 | ||
133 | struct pxa_buffer *active; | 128 | struct pxa_buffer *active; |
129 | struct pxa_dma_desc *sg_tail[3]; | ||
134 | }; | 130 | }; |
135 | 131 | ||
136 | static const char *pxa_cam_driver_description = "PXA_Camera"; | 132 | static const char *pxa_cam_driver_description = "PXA_Camera"; |
@@ -144,11 +140,14 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | |||
144 | unsigned int *size) | 140 | unsigned int *size) |
145 | { | 141 | { |
146 | struct soc_camera_device *icd = vq->priv_data; | 142 | struct soc_camera_device *icd = vq->priv_data; |
143 | struct soc_camera_host *ici = | ||
144 | to_soc_camera_host(icd->dev.parent); | ||
145 | struct pxa_camera_dev *pcdev = ici->priv; | ||
147 | 146 | ||
148 | dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); | 147 | dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size); |
149 | 148 | ||
150 | /* planar capture requires Y, U and V buffers to be page aligned */ | 149 | /* planar capture requires Y, U and V buffers to be page aligned */ |
151 | if (icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P) { | 150 | if (pcdev->channels == 3) { |
152 | *size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */ | 151 | *size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */ |
153 | *size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */ | 152 | *size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */ |
154 | *size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */ | 153 | *size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */ |
@@ -296,7 +295,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
296 | if (ret) | 295 | if (ret) |
297 | goto fail; | 296 | goto fail; |
298 | 297 | ||
299 | if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) { | 298 | if (pcdev->channels == 3) { |
300 | /* FIXME the calculations should be more precise */ | 299 | /* FIXME the calculations should be more precise */ |
301 | sglen_y = dma->sglen / 2; | 300 | sglen_y = dma->sglen / 2; |
302 | sglen_u = sglen_v = dma->sglen / 4 + 1; | 301 | sglen_u = sglen_v = dma->sglen / 4 + 1; |
@@ -318,7 +317,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
318 | goto fail; | 317 | goto fail; |
319 | } | 318 | } |
320 | 319 | ||
321 | if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) { | 320 | if (pcdev->channels == 3) { |
322 | /* init DMA for U channel */ | 321 | /* init DMA for U channel */ |
323 | ret = pxa_init_dma_channel(pcdev, buf, dma, 1, sglen_u, | 322 | ret = pxa_init_dma_channel(pcdev, buf, dma, 1, sglen_u, |
324 | sglen_y, 0x30, size_u); | 323 | sglen_y, 0x30, size_u); |
@@ -343,7 +342,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, | |||
343 | 342 | ||
344 | buf->inwork = 0; | 343 | buf->inwork = 0; |
345 | buf->active_dma = DMA_Y; | 344 | buf->active_dma = DMA_Y; |
346 | if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) | 345 | if (pcdev->channels == 3) |
347 | buf->active_dma |= DMA_U | DMA_V; | 346 | buf->active_dma |= DMA_U | DMA_V; |
348 | 347 | ||
349 | return 0; | 348 | return 0; |
@@ -371,6 +370,7 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, | |||
371 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); | 370 | struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); |
372 | struct pxa_buffer *active; | 371 | struct pxa_buffer *active; |
373 | unsigned long flags; | 372 | unsigned long flags; |
373 | int i; | ||
374 | 374 | ||
375 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, | 375 | dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, |
376 | vb, vb->baddr, vb->bsize); | 376 | vb, vb->baddr, vb->bsize); |
@@ -383,15 +383,11 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, | |||
383 | 383 | ||
384 | if (!active) { | 384 | if (!active) { |
385 | CIFR |= CIFR_RESET_F; | 385 | CIFR |= CIFR_RESET_F; |
386 | DDADR(pcdev->dma_chans[0]) = buf->dmas[0].sg_dma; | ||
387 | DCSR(pcdev->dma_chans[0]) = DCSR_RUN; | ||
388 | |||
389 | if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) { | ||
390 | DDADR(pcdev->dma_chans[1]) = buf->dmas[1].sg_dma; | ||
391 | DCSR(pcdev->dma_chans[1]) = DCSR_RUN; | ||
392 | 386 | ||
393 | DDADR(pcdev->dma_chans[2]) = buf->dmas[2].sg_dma; | 387 | for (i = 0; i < pcdev->channels; i++) { |
394 | DCSR(pcdev->dma_chans[2]) = DCSR_RUN; | 388 | DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma; |
389 | DCSR(pcdev->dma_chans[i]) = DCSR_RUN; | ||
390 | pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen - 1; | ||
395 | } | 391 | } |
396 | 392 | ||
397 | pcdev->active = buf; | 393 | pcdev->active = buf; |
@@ -400,7 +396,6 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, | |||
400 | struct pxa_cam_dma *buf_dma; | 396 | struct pxa_cam_dma *buf_dma; |
401 | struct pxa_cam_dma *act_dma; | 397 | struct pxa_cam_dma *act_dma; |
402 | int nents; | 398 | int nents; |
403 | int i; | ||
404 | 399 | ||
405 | for (i = 0; i < pcdev->channels; i++) { | 400 | for (i = 0; i < pcdev->channels; i++) { |
406 | buf_dma = &buf->dmas[i]; | 401 | buf_dma = &buf->dmas[i]; |
@@ -412,8 +407,8 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, | |||
412 | 407 | ||
413 | /* Add the descriptors we just initialized to | 408 | /* Add the descriptors we just initialized to |
414 | the currently running chain */ | 409 | the currently running chain */ |
415 | act_dma->sg_cpu[act_dma->sglen - 1].ddadr = | 410 | pcdev->sg_tail[i]->ddadr = buf_dma->sg_dma; |
416 | buf_dma->sg_dma; | 411 | pcdev->sg_tail[i] = buf_dma->sg_cpu + buf_dma->sglen - 1; |
417 | 412 | ||
418 | /* Setup a dummy descriptor with the DMA engines current | 413 | /* Setup a dummy descriptor with the DMA engines current |
419 | * state | 414 | * state |