[PATCH] x86_64: Implement compat code for raw1394 read/write

Not for the ioctls so far because I was too lazy.

Cc: bcollins@debian.org
Cc: dan@dennedy.org
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index b052356..19f26c5 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -42,6 +42,7 @@
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/compat.h>
 
 #include "csr1212.h"
 #include "ieee1394.h"
@@ -406,6 +407,65 @@
 	    queue_complete_req(req);
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_raw1394_req {
+        __u32 type;
+        __s32 error;
+        __u32 misc;
+
+        __u32 generation;
+        __u32 length;
+
+        __u64 address;
+
+        __u64 tag;
+
+        __u64 sendb;
+        __u64 recvb;
+}  __attribute__((packed));
+
+static const char __user *raw1394_compat_write(const char __user *buf)
+{
+	struct compat_raw1394_req __user *cr = (typeof(cr)) buf; 
+	struct raw1394_request __user *r;
+	r = compat_alloc_user_space(sizeof(struct raw1394_request));
+
+#define C(x) __copy_in_user(&r->x, &cr->x, sizeof(r->x))
+
+	if (copy_in_user(r, cr, sizeof(struct compat_raw1394_req)) ||
+		C(address) ||
+		C(tag) ||
+		C(sendb) ||
+		C(recvb))
+		return ERR_PTR(-EFAULT);
+	return (const char __user *)r;
+}
+#undef C
+
+#define P(x) __put_user(r->x, &cr->x)
+
+static int 
+raw1394_compat_read(const char __user *buf, struct raw1394_request *r)
+{
+	struct compat_raw1394_req __user *cr = (typeof(cr)) r; 
+	if (!access_ok(VERIFY_WRITE,cr,sizeof(struct compat_raw1394_req)) ||
+	    P(type) ||
+	    P(error) ||
+	    P(misc) ||
+	    P(generation) ||
+	    P(length) ||
+	    P(address) ||
+	    P(tag) ||
+	    P(sendb) ||
+	    P(recvb))
+		return -EFAULT;
+	return sizeof(struct compat_raw1394_req);
+}
+#undef P
+
+#endif
+
+
 static ssize_t raw1394_read(struct file *file, char __user * buffer,
 			    size_t count, loff_t * offset_is_ignored)
 {
@@ -415,6 +475,11 @@
 	struct pending_request *req;
 	ssize_t ret;
 
+#ifdef CONFIG_COMPAT
+	if (count == sizeof(struct compat_raw1394_req)) {
+		/* ok */
+	} else
+#endif
 	if (count != sizeof(struct raw1394_request)) {
 		return -EINVAL;
 	}
@@ -446,12 +511,22 @@
 			req->req.error = RAW1394_ERROR_MEMFAULT;
 		}
 	}
-	if (copy_to_user(buffer, &req->req, sizeof(req->req))) {
-		ret = -EFAULT;
-		goto out;
-	}
 
-	ret = (ssize_t) sizeof(struct raw1394_request);
+#ifdef CONFIG_COMPAT
+	if (count == sizeof(struct compat_raw1394_req) && 
+   		sizeof(struct compat_raw1394_req) != 
+			sizeof(struct raw1394_request)) { 
+		ret = raw1394_compat_read(buffer, &req->req);
+
+	} else	
+#endif
+	{
+		if (copy_to_user(buffer, &req->req, sizeof(req->req))) {
+			ret = -EFAULT;
+			goto out;
+		}		
+		ret = (ssize_t) sizeof(struct raw1394_request);
+	}
       out:
 	free_pending_request(req);
 	return ret;
@@ -2274,6 +2349,7 @@
 	return handle_async_request(fi, req, node);
 }
 
+
 static ssize_t raw1394_write(struct file *file, const char __user * buffer,
 			     size_t count, loff_t * offset_is_ignored)
 {
@@ -2281,6 +2357,15 @@
 	struct pending_request *req;
 	ssize_t retval = 0;
 
+#ifdef CONFIG_COMPAT
+	if (count == sizeof(struct compat_raw1394_req) && 
+   		sizeof(struct compat_raw1394_req) != 
+			sizeof(struct raw1394_request)) { 
+		buffer = raw1394_compat_write(buffer);
+		if (IS_ERR(buffer))
+			return PTR_ERR(buffer);
+	} else
+#endif
 	if (count != sizeof(struct raw1394_request)) {
 		return -EINVAL;
 	}
@@ -2893,6 +2978,7 @@
 	.write = raw1394_write,
 	.mmap = raw1394_mmap,
 	.ioctl = raw1394_ioctl,
+	// .compat_ioctl = ... someone needs to do this
 	.poll = raw1394_poll,
 	.open = raw1394_open,
 	.release = raw1394_release,