Skip to content

Commit

Permalink
V4L/DVB (7886): ivtvfb: Use DMA for write()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ian Armstrong authored and Mauro Carvalho Chehab committed Jul 20, 2008
1 parent 5a4f5da commit 4cbeb37
Showing 1 changed file with 82 additions and 0 deletions.
82 changes: 82 additions & 0 deletions drivers/media/video/ivtv/ivtvfb.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,87 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
}

static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
void *dst;
int err = 0;
unsigned long total_size;
struct ivtv *itv = (struct ivtv *) info->par;
unsigned long dma_offset =
IVTV_DECODER_OFFSET + itv->osd_info->video_rbase;
unsigned long dma_size;
u16 lead = 0, tail = 0;

if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;

total_size = info->screen_size;

if (total_size == 0)
total_size = info->fix.smem_len;

if (p > total_size)
return -EFBIG;

if (count > total_size) {
err = -EFBIG;
count = total_size;
}

if (count + p > total_size) {
if (!err)
err = -ENOSPC;

count = total_size - p;
}

dst = (void __force *) (info->screen_base + p);

if (info->fbops->fb_sync)
info->fbops->fb_sync(info);

if (!access_ok(VERIFY_READ, buf, count)) {
IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
(unsigned long)buf);
err = -EFAULT;
}

if (!err) {
/* If transfer size > threshold and both src/dst
addresses are aligned, use DMA */
if (count >= 4096 && ((u32)buf & 3) == ((u32)dst & 3)) {
/* Odd address = can't DMA. Align */
if ((u32)dst & 3) {
lead = 4 - ((u32)dst & 3);
memcpy(dst, buf, lead);
buf += lead;
dst += lead;
}
/* DMA resolution is 32 bits */
if ((count - lead) & 3)
tail = (count - lead) & 3;
/* DMA the data */
dma_size = count - lead - tail;
err = ivtvfb_prep_dec_dma_to_device(itv,
p + lead + dma_offset, (void *)buf, dma_size);
dst += dma_size;
buf += dma_size;
/* Copy any leftover data */
if (tail)
memcpy(dst, buf, tail);
} else {
memcpy(dst, buf, count);
}
}

if (!err)
*ppos += count;

return (err) ? err : count;
}

static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
DEFINE_WAIT(wait);
Expand Down Expand Up @@ -824,6 +905,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)

static struct fb_ops ivtvfb_ops = {
.owner = THIS_MODULE,
.fb_write = ivtvfb_write,
.fb_check_var = ivtvfb_check_var,
.fb_set_par = ivtvfb_set_par,
.fb_setcolreg = ivtvfb_setcolreg,
Expand Down

0 comments on commit 4cbeb37

Please sign in to comment.