summary refs log tree commit diff
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.c84
1 files changed, 44 insertions, 40 deletions
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index bdfda48e56bf..921e281876f8 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -48,6 +48,7 @@
 #endif
 
 #include "ivtv-driver.h"
+#include "ivtv-i2c.h"
 #include "ivtv-udma.h"
 #include "ivtv-mailbox.h"
 
@@ -275,7 +276,6 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
 				  int size_in_bytes)
 {
 	DEFINE_WAIT(wait);
-	int ret = 0;
 	int got_sig = 0;
 
 	mutex_lock(&itv->udma.lock);
@@ -316,7 +316,7 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
 		return -EINTR;
 	}
 
-	return ret;
+	return 0;
 }
 
 static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
@@ -368,11 +368,12 @@ static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
 }
 
 static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
-		     size_t count, loff_t *ppos)
+						size_t count, loff_t *ppos)
 {
 	unsigned long p = *ppos;
 	void *dst;
 	int err = 0;
+	int dma_err;
 	unsigned long total_size;
 	struct ivtv *itv = (struct ivtv *) info->par;
 	unsigned long dma_offset =
@@ -399,7 +400,6 @@ static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
 	if (count + p > total_size) {
 		if (!err)
 			err = -ENOSPC;
-
 		count = total_size - p;
 	}
 
@@ -408,39 +408,34 @@ static ssize_t ivtvfb_write(struct fb_info *info, const char __user *buf,
 	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 &&
-		    ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
-			/* Odd address = can't DMA. Align */
-			if ((unsigned long)dst & 3) {
-				lead = 4 - ((unsigned long)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 transfer size > threshold and both src/dst
+	addresses are aligned, use DMA */
+	if (count >= 4096 &&
+	    ((unsigned long)buf & 3) == ((unsigned long)dst & 3)) {
+		/* Odd address = can't DMA. Align */
+		if ((unsigned long)dst & 3) {
+			lead = 4 - ((unsigned long)dst & 3);
+			if (copy_from_user(dst, buf, lead))
+				return -EFAULT;
+			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;
+		dma_err = ivtvfb_prep_dec_dma_to_device(itv,
+		       p + lead + dma_offset, (void __user *)buf, dma_size);
+		if (dma_err)
+			return dma_err;
+		dst += dma_size;
+		buf += dma_size;
+		/* Copy any leftover data */
+		if (tail && copy_from_user(dst, buf, tail))
+			return -EFAULT;
+	} else if (copy_from_user(dst, buf, count)) {
+		return -EFAULT;
 	}
 
 	if  (!err)
@@ -463,9 +458,12 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
 			vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
 					FB_VBLANK_HAVE_VSYNC;
 			trace = read_reg(0x028c0) >> 16;
-			if (itv->is_50hz && trace > 312) trace -= 312;
-			else if (itv->is_60hz && trace > 262) trace -= 262;
-			if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
+			if (itv->is_50hz && trace > 312)
+				trace -= 312;
+			else if (itv->is_60hz && trace > 262)
+				trace -= 262;
+			if (trace == 1)
+				vblank.flags |= FB_VBLANK_VSYNCING;
 			vblank.count = itv->last_vsync_field;
 			vblank.vcount = trace;
 			vblank.hcount = 0;
@@ -476,7 +474,8 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
 
 		case FBIO_WAITFORVSYNC:
 			prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
-			if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
+			if (!schedule_timeout(msecs_to_jiffies(50)))
+				rc = -ETIMEDOUT;
 			finish_wait(&itv->vsync_waitq, &wait);
 			return rc;
 
@@ -896,11 +895,16 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
 	switch (blank_mode) {
 	case FB_BLANK_UNBLANK:
 		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
+		ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
 		break;
 	case FB_BLANK_NORMAL:
 	case FB_BLANK_HSYNC_SUSPEND:
 	case FB_BLANK_VSYNC_SUSPEND:
+		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
+		ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+		break;
 	case FB_BLANK_POWERDOWN:
+		ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
 		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
 		break;
 	}