diff options
author | Ian Armstrong <ian@iarmst.co.uk> | 2008-05-12 10:53:10 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:05:57 -0400 |
commit | 4cbeb3711481a7e563fe4c61888986c4aa1cb22e (patch) | |
tree | b672ed149fb8fe2544867f7d8b883df67814e7ac | |
parent | 5a4f5da6552e6c55eff6fbddfee3eab908325c63 (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.c | 82 |
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 | ||
370 | static 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 | |||
370 | static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | 451 | static 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 | ||
825 | static struct fb_ops ivtvfb_ops = { | 906 | static 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, |