--- video_device.c.orig	2008-09-20 03:19:37.000000000 +0200
+++ video_device.c	2008-09-20 09:10:27.000000000 +0200
@@ -20,15 +20,59 @@
 #include <media/v4l2-common.h>
 #include <linux/time.h>
 
-/*#define DEBUG*/
+#define DEBUG
 
 #define KERNEL_PREFIX "AVLD device: " /* Prefix of each kernel message */
 #define VID_DUMMY_DEVICE 0 /* The type of device we create */
 
 /* The device can't be used by more than 2 applications ( typically : a read and a write application )
 Decrease this number if you want it to be accessible for more applications.*/
+
 static int usage = -1;
 
+/* v4l palettes */
+static int _palette[]={
+	VIDEO_PALETTE_RGB24,	/*0*/
+	VIDEO_PALETTE_GREY,	/*1*/
+	VIDEO_PALETTE_HI240,	/*2*/
+	VIDEO_PALETTE_RGB565,	/*3*/
+	VIDEO_PALETTE_RGB24,	/*4*/
+	VIDEO_PALETTE_RGB32,	/*5*/
+	VIDEO_PALETTE_RGB555,	/*6*/
+	VIDEO_PALETTE_YUV422,	/*7*/
+	VIDEO_PALETTE_YUYV,	/*8*/
+	VIDEO_PALETTE_UYVY,	/*9*/
+	VIDEO_PALETTE_YUV420,	/*10*/
+	VIDEO_PALETTE_YUV411,	/*11*/
+	VIDEO_PALETTE_RAW,	/*12*/
+	VIDEO_PALETTE_YUV422P,	/*13*/
+	VIDEO_PALETTE_YUV411P,	/*14*/
+	VIDEO_PALETTE_YUV420P,	/*15*/
+	VIDEO_PALETTE_YUV410P	/*16*/
+};
+
+/* v4l palette names */
+static char *palette_name[]={
+	"RGB24",
+	"GREY",
+	"HI240",
+	"RGB565",
+	"RGB24",
+	"RGB32",
+	"RGB555",
+	"YUV422",
+	"YUYV",
+	"UYVY",
+	"YUV420",
+	"YUV411",
+	"RAW",
+	"YUV422P",
+	"YUV411P",
+	"YUV420P",
+	"YUV410P",
+	0
+};
+
 /* Variable used to let reader control framerate */
 struct mutex lock;
 
@@ -53,7 +97,16 @@
 static wait_queue_head_t wait;/* variable used to simulate the FPS  */
 struct timeval timer;/* used to have a better framerate accuracy */
 
-
+static int atoi(char *s) {
+	int i;
+	int ret=0;
+	for (i=0;i<strlen(s);++i) {
+		if (s[i]>'9' || s[i]<'0')
+			break;
+		ret=ret*10+s[i]-'0';
+	}
+	return ret;
+}
 
 /************************************************
 **************** V4L FUNCTIONS  ***************
@@ -68,68 +121,59 @@
 		/* Get capabilities */
 		case VIDIOCGCAP:
 		{
-			struct video_capability v;
+			struct video_capability *v=arg;
 			
 			#ifdef DEBUG
 				printk (KERNEL_PREFIX "VIDIOCGCAP\n");
 			#endif
 			
-			v.type = VID_TYPE_CAPTURE;
-			v.channels = 1;
-			v.audios = 0;
-			v.maxwidth = width;
-			v.maxheight = height;
-			v.minwidth = width;
-			v.minheight = height;
-			strcpy(v.name, "Dummy video device");
+			v->type = VID_TYPE_CAPTURE;
+			v->channels = 1;
+			v->audios = 0;
+			v->maxwidth = width;
+			v->maxheight = height;
+			v->minwidth = width;
+			v->minheight = height;
+			strcpy(v->name, "Dummy video device");
 			
-			if(copy_to_user((void*)arg, &v, sizeof(v)))
-				return -EFAULT;
-			else
-				return 0;
+			return 0;
 		} 
 		
 		/* Get channel info (sources) */
 		case VIDIOCGCHAN:
 		{
-			struct video_channel v;
+			struct video_channel *v=arg;
 			#ifdef DEBUG
 				printk (KERNEL_PREFIX "VIDIOCGCHAN\n");
 			#endif
+		
+			if (v->channel!=0)
+				return -EINVAL;
+
+			v->flags = 0;
+			v->tuners = 0;
+			v->type = VIDEO_TYPE_CAMERA;
+			v->norm = VIDEO_MODE_AUTO;
+			v->channel = 0;
+			strcpy(v->name, "Dummy video device");
 			
-			if(copy_from_user(&v, (void*)arg, sizeof(v)))
-				return -EFAULT;
-			
-			v.flags = 0;
-			v.tuners = 0;
-			v.type = VIDEO_TYPE_CAMERA;
-			v.norm = VIDEO_MODE_AUTO;
-			v.channel = 0;
-			strcpy(v.name, "Dummy video device");
-			
-			if(copy_to_user((void*)arg, &v, sizeof(v)))
-				return -EFAULT;
-			else
-				return 0;
+			return 0;
 		}
 		
 		/* Set channel  */
 		case VIDIOCSCHAN:
 		{
-			struct video_channel v;
+			struct video_channel *v=arg;
 			
 			#ifdef DEBUG
 				printk (KERNEL_PREFIX "VIDIOCSCHAN\n");
 			#endif
 			
-			if(copy_from_user(&v, (void*)arg, sizeof(v)))
-				return -EFAULT;
-			
 			#ifdef DEBUG
-				printk("Channel=%d Norm=%d\n", v.channel, v.norm);
+				printk("Channel=%d Norm=%d\n", v->channel, v->norm);
 			#endif
 			
-			if(v.channel != 0)
+			if(v->channel != 0)
 				return -EINVAL;
 			
 			return 0;
@@ -138,43 +182,37 @@
 		/* Get picture properties */
 		case VIDIOCGPICT:
 		{
-			struct video_picture v;
+			struct video_picture *v=arg;
 			#ifdef DEBUG
 				printk (KERNEL_PREFIX "VIDIOCGPICT\n");
 			#endif
-			
-			v.brightness = brightness; 
-			v.hue = hue; 
-			v.colour = colour; 
-			v.contrast = contrast; 
-			v.whiteness = whiteness;
-			v.depth = depth;
-			v.palette = palette ? VIDEO_PALETTE_UYVY : VIDEO_PALETTE_RGB24;
-			if(copy_to_user((void*)arg, &v, sizeof(v))) 
-				return -EFAULT;
-			else
-				return 0;
+
+			v->brightness = brightness; 
+			v->hue = hue; 
+			v->colour = colour; 
+			v->contrast = contrast; 
+			v->whiteness = whiteness;
+			v->depth = depth;
+			v->palette = _palette[palette];
+			return 0;
 		}
 		
 		/* Set picture properties */
 		case VIDIOCSPICT:
 		{
-			struct video_picture v;
+			struct video_picture *v=arg;
 			#ifdef DEBUG
 				printk (KERNEL_PREFIX "VIDIOCSPICT\n");
 			#endif
 			
-			if(copy_from_user(&v, (void*)arg, sizeof(v)))
-				return -EFAULT;
+			brightness = v->brightness;
+			hue = v->hue;
+			colour = v->colour;
+			contrast = v->contrast;
 			
-			brightness = v.brightness;
-			hue = v.hue;
-			colour = v.colour;
-			contrast = v.contrast;
-			
-			if(v.depth != depth || v.palette != (palette ? VIDEO_PALETTE_UYVY : VIDEO_PALETTE_RGB24) ) {
+			if(v->depth != depth || v->palette != _palette[palette]) {
 				#ifdef DEBUG
-					printk (KERNEL_PREFIX "Properties have changed..\n");
+					printk (KERNEL_PREFIX "Attempt to change picture properties.. palette wanted=%s, depth wanted=%d\n",palette_name[v->palette],v->depth);
 				#endif
 				return -EINVAL;
 			}
@@ -199,10 +237,10 @@
 			#ifdef DEBUG
 				printk (KERNEL_PREFIX "VIDIOCGMBUF\n");
 			#endif
-			buf->frames = 1;
-			buf->offsets[0] = 0;
-			buf->size = BUFFER_SIZE;
-			
+	
+			buf->frames=1;
+			buf->offsets[0]=0;
+			buf->size=BUFFER_SIZE;
 			return 0;
 		}
 		
@@ -212,7 +250,12 @@
 			#ifdef DEBUG
 				printk (KERNEL_PREFIX "VIDIOCGWIN\n");
 			#endif
-			
+
+			memset(&capture_win, 0, sizeof(capture_win));
+			capture_win.width=width;	
+			capture_win.height=height;
+
+
 			if(copy_to_user((void*)arg, &capture_win, sizeof(capture_win)))
 				return -EFAULT;
 			return 0;
@@ -221,17 +264,22 @@
 		/* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
 		case VIDIOCSWIN:
 		{
-			struct video_window v;
+			struct video_window *v=arg;
 			
 			#ifdef DEBUG
 				printk (KERNEL_PREFIX "VIDIOCSWIN\n");
 			#endif
 			
-			if(copy_from_user(&v, (void*)arg, sizeof(v))) return -EFAULT;
-				if(v.width != width || v.height != height) 
-					return -EINVAL;
+			if ((v->width != width) || (v->height != height))
+				return -EINVAL;
+
+			if ((v->clipcount) || (v->clips)) 
+				return -EINVAL;
 			
-			memcpy(&capture_win, &v, sizeof(v));
+			if (v->flags) 
+				return -EINVAL;
+
+			memcpy(&capture_win, v, sizeof(*v));
 			return 0;
 		}
 		
@@ -259,15 +307,10 @@
 		/* Set frame buffer - root only */
 		case  VIDIOCSFBUF: {
 			
-			struct video_buffer v;
-			
-			if (copy_from_user(&v, (void*)arg, sizeof(v))) {
-				printk (KERNEL_PREFIX "ERROR with VIDIOCSFBUF\n");
-				return -EFAULT;
-			}
+			struct video_buffer *v=arg;
 			
 			#ifdef DEBUG
-				printk(KERNEL_PREFIX "Display at %p is %d by %d, bytedepth %d, bpl %d at %d depth\n", v.base, v.width, v.height,	((v.depth + 7) & 0x38) / 8, v.bytesperline,v.depth);
+				printk(KERNEL_PREFIX "Display at %p is %d by %d, bytedepth %d, bpl %d at %d depth\n", v->base, v->width, v->height,((v->depth + 7) & 0x38) >> 3 , v->bytesperline,v->depth);
 			#endif
 			
 			return 0;
@@ -277,20 +320,18 @@
 		/* Get frame buffer */
 		case  VIDIOCGFBUF:	{
 			
-			struct video_buffer v;
+			struct video_buffer *v=arg;
 			
-			v.base = 0;
-			v.height = height;
-			v.width = width;
-			v.depth = depth;
-			v.bytesperline = ((v.depth + 7) & 0x38) / 8;
+			v->base = 0;
+			v->height = height;
+			v->width = width;
+			v->depth = depth;
+			v->bytesperline=width*((depth+7)>>3);
 			
 			#ifdef DEBUG
-				printk(KERNEL_PREFIX "VIDIOCGFBUF : %d\n",v.bytesperline);
+				printk(KERNEL_PREFIX "VIDIOCGFBUF : %d\n",v->bytesperline);
 			#endif
 			
-			if (copy_to_user((void*)arg, &v, sizeof(v)))
-				return -EFAULT;
 			return 0;
 		}
 		
@@ -399,7 +440,7 @@
 	
 	
 	// if input size superior to the buffered image size
-	if (count >BUFFER_SIZE) {
+	if (count > BUFFER_SIZE) {
 		printk(KERNEL_PREFIX "ERROR : you are attempting to read too much data\n");
 		return -EINVAL;
 	}
@@ -415,50 +456,91 @@
 static int v4l_write(struct file *file, const char *buf, size_t count, loff_t *ppos) {
 	
 	#ifdef DEBUG
-		printk(KERNEL_PREFIX "v4l_write() : %d\n",count);
+		printk(KERNEL_PREFIX "v4l_write() : %d/%lu\n",count,BUFFER_SIZE);
 	#endif
 	
 	int waiting_time;
 	struct timeval current_time;
-	
+
 	// in case user wants to change the video parameters, we check if "buf" contains the necessary string
-	int l__width=0,l__height=0,l__fps=0;
-	int l__ret = sscanf(buf,"width=%d height=%d fps=%d",&l__width,&l__height,&l__fps);
-	if ( l__ret == 3 ) {
+	int l__width=0,l__height=0,l__fps=0,l__depth=0,l__palette=0;
+	// the image that should not be read now anyway
+	char *s__palette=image;
+
+	if (buf[0]=='w' && buf[1]=='i' && buf[2]=='d') {
+		int l__ret = sscanf(buf,"width=%d height=%d fps=%d palette=%s depth=%d",&l__width,&l__height,&l__fps,s__palette,&l__depth);
+
+		if ( l__ret == 5 ) {
+
+			int p=0;
+			while (palette_name[p]) {
+				if (!strcmp(palette_name[p],s__palette)) {
+					break;
+				}
+				++p;
+			}
 
-		if ( l__width <= 0 || l__height <= 0 ) {
-			printk (KERN_INFO "ERROR : Incorrect width and/or height values\n");
-			return -EINVAL;
-		} else if ( l__fps < 0 ) {
-			printk (KERN_INFO "WARNING : Framerate is synchronized on reader !!\n");;
-			l__fps=-1;
-			mutex_init(&lock);
-		}
+			if (palette_name[p]) {
+				l__palette=p;
+			} else { 
+				l__palette=atoi(s__palette);
+				if (l__palette<0 || l__palette>16) {
+					printk (KERN_INFO "ERROR : Incorrect palette number\n");
+					return -EINVAL;
+				}
+
+			}
 
-		width=l__width;
-		height=l__height;
-		fps=l__fps;
-		printk(KERNEL_PREFIX "New video parameters : width=%d - height=%d - fps=%d\n",width,height,fps);
+			if (l__depth<1 || l__depth>32 ) {
+				printk (KERN_INFO "ERROR : Incorrect depth\n");
+				return -EINVAL;
+			}
+
+			if ( l__width <= 0 || l__height <= 0 ) {
+				printk (KERN_INFO "ERROR : Incorrect width and/or height values\n");
+				return -EINVAL;
+			}
 			
-		// we unallocate the old image
-		if ( image != NULL ) {
-			vfree(image);
-		}
-	
-		// we recalculate the new size
-		BUFFER_SIZE=((width*height*3/PAGE_SIZE)+1)*PAGE_SIZE;
+			if ( l__fps < 0 ) {
+				printk (KERN_INFO "WARNING : Framerate is synchronized on reader !!\n");;
+				l__fps=-1;
+				mutex_init(&lock);
+			}
 
-		// and finally, we allocate memory for this new image
-		image = vmalloc (BUFFER_SIZE);
-		if (!image) {
-			printk (KERN_INFO "failed vmalloc\n");
-			return -EINVAL;
-		}
+			// if the current buffer is too small
+			if (BUFFER_SIZE<(l__width*l__height*((l__depth+7)>>3)/PAGE_SIZE+1)*PAGE_SIZE) {
+
+				// we unallocate the old image
+				if (image) {
+					vfree(image);
+					image=0;
+				}
+
+				// we recalculate the new size
+				BUFFER_SIZE=(l__width*l__height*((l__depth+7)>>3)/PAGE_SIZE+1)*PAGE_SIZE;
+
+				// and finally, we allocate memory for this new image
+				image = vmalloc (BUFFER_SIZE);
+				if (!image) {
+					BUFFER_SIZE=0;
+					printk (KERN_INFO "Failed vmalloc. Try to set or change parameters again.\n");
+					return -EINVAL;
+				}
+			}
+				
+			width=l__width;
+			height=l__height;
+			fps=l__fps;
+			palette=l__palette;
+			depth=l__depth;
+			printk(KERNEL_PREFIX "New video parameters : width=%d - height=%d - fps=%d - palette=%s - depth=%d\n",width,height,fps,palette_name[palette],depth);
+		
 
+		}
 	}
 	
 	// if input size superior to the buffered image size
-	if (count >BUFFER_SIZE) {
+	if (count>BUFFER_SIZE) {
 		printk(KERNEL_PREFIX "ERROR : you are attempting to write too much data\n");
 		return -EINVAL;
 	}
@@ -530,6 +612,7 @@
 	mmap: 		v4l_mmap,
 	write:		v4l_write,
 	ioctl:		v4l_ioctl,
+	compat_ioctl: 	v4l_compat_ioctl32,
 	llseek:     no_llseek,
 };
 static struct video_device my_device = {
@@ -566,7 +649,7 @@
 	}
 
 	// image buffer size is computed
-	BUFFER_SIZE=((width*height*3/PAGE_SIZE)+1)*PAGE_SIZE;
+	BUFFER_SIZE=(((width*height*(depth+7)>>3)/PAGE_SIZE)+1)*PAGE_SIZE;
 	
 	// allocation of the memory used to save the image
 	image = vmalloc (BUFFER_SIZE);
@@ -575,8 +658,7 @@
 		return -EINVAL;
 	}
 	
-	printk(KERNEL_PREFIX "module installed (%s)\n", palette ? "UYVY" : "RGB24");
-	
+	printk(KERNEL_PREFIX "module installed: fps=%d palette=%s (memory allocated to fit up to: width=%d - height=%d - depth=%d)\n",fps,palette_name[palette],width,height,depth);
 	return 0;
 }
 void cleanup_module() {
@@ -613,7 +695,10 @@
 MODULE_PARM_DESC(fps,"framerate of the video in FPS (frame per second)");
 
 module_param(palette,int,0);
-MODULE_PARM_DESC(palette,"palette used, 0:RGB24, 1:UYVY");
+MODULE_PARM_DESC(palette,"v4l palette used, see linux/videodev.h");
+
+module_param(depth,int,0);
+MODULE_PARM_DESC(depth,"bitdepth");
 
 /*
 	VIDIOCGCAP		_IOR('v',1,struct video_capability)     		// Get capabilities
