aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Armstrong <ian@iarmst.co.uk>2008-05-12 10:53:10 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-07-20 06:05:57 -0400
commit4cbeb3711481a7e563fe4c61888986c4aa1cb22e (patch)
treeb672ed149fb8fe2544867f7d8b883df67814e7ac
parent5a4f5da6552e6c55eff6fbddfee3eab908325c63 (diff)
V4L/DVB (7886): ivtvfb: Use DMA for write()
write() operations to the ivtv framebuffer will now attempt to use DMA if the amount of data to copy is >= 4096 bytes. This change effectively depreciates the need for the proprietary IVTVFB_IOC_DMA_FRAME ioctl since a write() of sufficient size will do the same thing. Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk> Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 73be154f7f05..e8dbee443946 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -367,6 +367,87 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
367 return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count); 367 return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
368} 368}
369 369
370static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
371 size_t count, loff_t *ppos)
372{
373 unsigned long p = *ppos;
374 void *dst;
375 int err = 0;
376 unsigned long total_size;
377 struct ivtv *itv = (struct ivtv *) info->par;
378 unsigned long dma_offset =
379 IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
380 unsigned long dma_size;
381 u16 lead = 0, tail = 0;
382
383 if (info->state != FBINFO_STATE_RUNNING)
384 return -EPERM;
385
386 total_size = info->screen_size;
387
388 if (total_size == 0)
389 total_size = info->fix.smem_len;
390
391 if (p > total_size)
392 return -EFBIG;
393
394 if (count > total_size) {
395 err = -EFBIG;
396 count = total_size;
397 }
398
399 if (count + p > total_size) {
400 if (!err)
401 err = -ENOSPC;
402
403 count = total_size - p;
404 }
405
406 dst = (void __force *) (info->screen_base + p);
407
408 if (info->fbops->fb_sync)
409 info->fbops->fb_sync(info);
410
411 if (!access_ok(VERIFY_READ, buf, count)) {
412 IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
413 (unsigned long)buf);
414 err = -EFAULT;
415 }
416
417 if (!err) {
418 /* If transfer size > threshold and both src/dst
419 addresses are aligned, use DMA */
420 if (count >= 4096 && ((u32)buf & 3) == ((u32)dst & 3)) {
421 /* Odd address = can't DMA. Align */
422 if ((u32)dst & 3) {
423 lead = 4 - ((u32)dst & 3);
424 memcpy(dst, buf, lead);
425 buf += lead;
426 dst += lead;
427 }
428 /* DMA resolution is 32 bits */
429 if ((count - lead) & 3)
430 tail = (count - lead) & 3;
431 /* DMA the data */
432 dma_size = count - lead - tail;
433 err = ivtvfb_prep_dec_dma_to_device(itv,
434 p + lead + dma_offset, (void *)buf, dma_size);
435 dst += dma_size;
436 buf += dma_size;
437 /* Copy any leftover data */
438 if (tail)
439 memcpy(dst, buf, tail);
440 } else {
441 memcpy(dst, buf, count);
442 }
443 }
444
445 if (!err)
446 *ppos += count;
447
448 return (err) ? err : count;
449}
450
370static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) 451static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
371{ 452{
372 DEFINE_WAIT(wait); 453 DEFINE_WAIT(wait);
@@ -824,6 +905,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
824 905
825static struct fb_ops ivtvfb_ops = { 906static struct fb_ops ivtvfb_ops = {
826 .owner = THIS_MODULE, 907 .owner = THIS_MODULE,
908 .fb_write = ivtvfb_write,
827 .fb_check_var = ivtvfb_check_var, 909 .fb_check_var = ivtvfb_check_var,
828 .fb_set_par = ivtvfb_set_par, 910 .fb_set_par = ivtvfb_set_par,
829 .fb_setcolreg = ivtvfb_setcolreg, 911 .fb_setcolreg = ivtvfb_setcolreg,