aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv/ivtvfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/ivtv/ivtvfb.c')
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c78
1 files changed, 38 insertions, 40 deletions
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index bdfda48e56bf..8a4a150b12fb 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -275,7 +275,6 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
275 int size_in_bytes) 275 int size_in_bytes)
276{ 276{
277 DEFINE_WAIT(wait); 277 DEFINE_WAIT(wait);
278 int ret = 0;
279 int got_sig = 0; 278 int got_sig = 0;
280 279
281 mutex_lock(&itv->udma.lock); 280 mutex_lock(&itv->udma.lock);
@@ -316,7 +315,7 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
316 return -EINTR; 315 return -EINTR;
317 } 316 }
318 317
319 return ret; 318 return 0;
320} 319}
321 320
322static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, 321static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
@@ -368,11 +367,12 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
368} 367}
369 368
370static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf, 369static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
371 size_t count, loff_t *ppos) 370 size_t count, loff_t *ppos)
372{ 371{
373 unsigned long p = *ppos; 372 unsigned long p = *ppos;
374 void *dst; 373 void *dst;
375 int err = 0; 374 int err = 0;
375 int dma_err;
376 unsigned long total_size; 376 unsigned long total_size;
377 struct ivtv *itv = (struct ivtv *) info->par; 377 struct ivtv *itv = (struct ivtv *) info->par;
378 unsigned long dma_offset = 378 unsigned long dma_offset =
@@ -399,7 +399,6 @@ static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
399 if (count + p > total_size) { 399 if (count + p > total_size) {
400 if (!err) 400 if (!err)
401 err = -ENOSPC; 401 err = -ENOSPC;
402
403 count = total_size - p; 402 count = total_size - p;
404 } 403 }
405 404
@@ -408,39 +407,34 @@ static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
408 if (info->fbops->fb_sync) 407 if (info->fbops->fb_sync)
409 info->fbops->fb_sync(info); 408 info->fbops->fb_sync(info);
410 409
411 if (!access_ok(VERIFY_READ, buf, count)) { 410 /* If transfer size > threshold and both src/dst
412 IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n", 411 addresses are aligned, use DMA */
413 (unsigned long)buf); 412 if (count >= 4096 &&
414 err = -EFAULT; 413 ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
415 } 414 /* Odd address = can't DMA. Align */
416 415 if ((unsigned long)dst & 3) {
417 if (!err) { 416 lead = 4 - ((unsigned long)dst & 3);
418 /* If transfer size > threshold and both src/dst 417 if (copy_from_user(dst, buf, lead))
419 addresses are aligned, use DMA */ 418 return -EFAULT;
420 if (count >= 4096 && 419 buf += lead;
421 ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) { 420 dst += lead;
422 /* Odd address = can't DMA. Align */
423 if ((unsigned long)dst & 3) {
424 lead = 4 - ((unsigned long)dst & 3);
425 memcpy(dst, buf, lead);
426 buf += lead;
427 dst += lead;
428 }
429 /* DMA resolution is 32 bits */
430 if ((count - lead) & 3)
431 tail = (count - lead) & 3;
432 /* DMA the data */
433 dma_size = count - lead - tail;
434 err = ivtvfb_prep_dec_dma_to_device(itv,
435 p + lead + dma_offset, (void *)buf, dma_size);
436 dst += dma_size;
437 buf += dma_size;
438 /* Copy any leftover data */
439 if (tail)
440 memcpy(dst, buf, tail);
441 } else {
442 memcpy(dst, buf, count);
443 } 421 }
422 /* DMA resolution is 32 bits */
423 if ((count - lead) & 3)
424 tail = (count - lead) & 3;
425 /* DMA the data */
426 dma_size = count - lead - tail;
427 dma_err = ivtvfb_prep_dec_dma_to_device(itv,
428 p + lead + dma_offset, (void __user *)buf, dma_size);
429 if (dma_err)
430 return dma_err;
431 dst += dma_size;
432 buf += dma_size;
433 /* Copy any leftover data */
434 if (tail && copy_from_user(dst, buf, tail))
435 return -EFAULT;
436 } else if (copy_from_user(dst, buf, count)) {
437 return -EFAULT;
444 } 438 }
445 439
446 if (!err) 440 if (!err)
@@ -463,9 +457,12 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
463 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT | 457 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
464 FB_VBLANK_HAVE_VSYNC; 458 FB_VBLANK_HAVE_VSYNC;
465 trace = read_reg(0x028c0) >> 16; 459 trace = read_reg(0x028c0) >> 16;
466 if (itv->is_50hz && trace > 312) trace -= 312; 460 if (itv->is_50hz && trace > 312)
467 else if (itv->is_60hz && trace > 262) trace -= 262; 461 trace -= 312;
468 if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING; 462 else if (itv->is_60hz && trace > 262)
463 trace -= 262;
464 if (trace == 1)
465 vblank.flags |= FB_VBLANK_VSYNCING;
469 vblank.count = itv->last_vsync_field; 466 vblank.count = itv->last_vsync_field;
470 vblank.vcount = trace; 467 vblank.vcount = trace;
471 vblank.hcount = 0; 468 vblank.hcount = 0;
@@ -476,7 +473,8 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
476 473
477 case FBIO_WAITFORVSYNC: 474 case FBIO_WAITFORVSYNC:
478 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE); 475 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
479 if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT; 476 if (!schedule_timeout(msecs_to_jiffies(50)))
477 rc = -ETIMEDOUT;
480 finish_wait(&itv->vsync_waitq, &wait); 478 finish_wait(&itv->vsync_waitq, &wait);
481 return rc; 479 return rc;
482 480