--- linux-2.4.5-dist/drivers/usb/pwc-ctrl.c	Sat Jun  2 03:53:46 2001
+++ linux-2.4.5/drivers/usb/pwc-ctrl.c	Wed Jun 20 00:47:44 2001
@@ -236,9 +236,7 @@
 	if (ret < 0)
 		return ret;
 	if (pEntry->compressed)
-		ret = pdev->decompressor->init(pdev->release, buf, &pdev->decompress_data);
-	if (ret < 0)
-		return ret;
+		pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
 		
 	/* Set various parameters */
 	pdev->vframes = frames;
@@ -303,9 +301,7 @@
 		return ret;
 
 	if (pChoose->bandlength > 0)
-		ret = pdev->decompressor->init(pdev->release, buf, &pdev->decompress_data);
-	if (ret < 0)
-		return ret;
+		pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
 	
 	/* Set various parameters */
 	pdev->vframes = frames;
@@ -366,9 +362,7 @@
 		return ret;
 
 	if (pChoose->bandlength > 0)
-		ret = pdev->decompressor->init(pdev->release, buf, &pdev->decompress_data);
-	if (ret < 0)
-		return ret;
+		pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
 		
 	/* All set and go */
 	pdev->vframes = frames;
@@ -429,14 +423,11 @@
 			return ret;
 		}
 	}
-	/* If the video mode was not supported, we still adjust the view size,
-	   since xawtv (Again! Stupid program...) doesn't care zit about 
-	   return values.
-	 */
 	pdev->view.x = width;
 	pdev->view.y = height;
 	pwc_set_image_buffer_size(pdev);
-	Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d. Palette = %d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y, pdev->vpalette);
+	Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d, palette = %d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y, pdev->vpalette);
+Debug("bandlength = %d\n", pdev->vbandlength);	
 	return 0;
 }
 
@@ -482,22 +473,15 @@
 	pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
 	pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
 
-	pdev->offset.x = (pdev->view.x - pdev->image.x) / 2;
-	pdev->offset.y = (pdev->view.y - pdev->image.y) / 2;
-	if (pdev->vpalette == VIDEO_PALETTE_YUV420 || pdev->vpalette == VIDEO_PALETTE_YUV420P) {
-		/* Align offset, or you'll get some very weird results in
-		   YUV mode... x must be multiple of 4 (to get the Y's in 
-		   place), and y even (or you'll mixup U & V).
-		 */
-		pdev->offset.x &= 0xFFFC;
-		pdev->offset.y &= 0xFFFE;	
-		/* This is the offset in the Y area, hence no factor */
-		pdev->offset.size = (pdev->offset.y * pdev->view.x + pdev->offset.x);
-	}
-	else
-		pdev->offset.size = (pdev->offset.y * pdev->view.x + pdev->offset.x) * factor / 4;
+	/* Align offset, or you'll get some very weird results in
+	   YUV420 mode... x must be multiple of 4 (to get the Y's in 
+	   place), and y even (or you'll mixup U & V). This is less of a
+	   problem for YUV420P.
+	 */
+	pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
+	pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
 	
-	/* Set buffers to gray */
+	/* Fill buffers with gray or black */
 	for (i = 0; i < MAX_IMAGES; i++) {
 		if (pdev->image_ptr[i] != NULL)
 			memset(pdev->image_ptr[i], filler, pdev->view.size);
diff -u linux-2.4.5-dist/drivers/usb/pwc-if.c linux-2.4.5/drivers/usb/pwc-if.c
--- linux-2.4.5-dist/drivers/usb/pwc-if.c	Sat Jun  2 03:53:46 2001
+++ linux-2.4.5/drivers/usb/pwc-if.c	Wed Jun 20 01:13:57 2001
@@ -84,10 +84,10 @@
 
 static int default_size = PSZ_QCIF;
 static int default_fps = 10;
-static int default_palette = VIDEO_PALETTE_RGB24; /* This is normal for webcams */
+static int default_palette = VIDEO_PALETTE_YUV420P; /* This format is understood by most tools */
 static int default_fbufs = 3;   /* Default number of frame buffers */
 static int default_mbufs = 2;	/* Default number of mmap() buffers */
-       int pwc_trace = TRACE_MODULE | TRACE_FLOW;
+       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
 static int power_save = 0;
 int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
 
@@ -110,7 +110,7 @@
 	owner:		THIS_MODULE,
 	name:		"Philips Webcam",	/* Filled in later */
 	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_PWC,	/* Let's pretend for now */
+	hardware:	VID_HARDWARE_PWC,
 	open:		pwc_video_open,
 	close:		pwc_video_close,
 	read:		pwc_video_read,
@@ -321,14 +321,16 @@
 		}
 	}
 	
-	/* Allocate decompressor buffer space */
-	kbuf = vmalloc(FRAME_SIZE);
-	if (kbuf == NULL) {
-		Err("Failed to allocate compressed image buffer.\n");
-		return -ENOMEM;
+	/* Allocate decompressor table space */
+	kbuf = NULL;
+	if (pdev->decompressor != NULL) {
+		kbuf = kmalloc(pdev->decompressor->table_size, GFP_KERNEL);
+		if (kbuf == NULL) {
+			Err("Failed to allocate decompress table.\n");
+			return -ENOMEM;
+		}
 	}
-	memset(kbuf, 0, FRAME_SIZE);
-	pdev->decompress_buffer = kbuf;
+	pdev->decompress_data = kbuf;
 	
 	/* Allocate image buffer; double buffer for mmap() */
 	kbuf = rvmalloc(default_mbufs * pdev->view_max.size * 4);
@@ -361,6 +363,7 @@
 		return;
 	}
 #endif	
+
 	/* Release Iso-pipe buffers */
 	Trace(TRACE_MEMORY, "Freeing ISO buffers.\n");
 	for (i = 0; i < MAX_ISO_BUFS; i++)
@@ -368,6 +371,7 @@
 			kfree(pdev->sbuf[i].data);
 			pdev->sbuf[i].data = NULL;
 		}
+
 	/* The same for frame buffers */
 	Trace(TRACE_MEMORY, "Freeing frame buffers.\n");
 	if (pdev->fbuf != NULL) {
@@ -380,11 +384,14 @@
 		kfree(pdev->fbuf);
 		pdev->fbuf = NULL;
 	}
-	/* Intermediate decompression buffer */
+
+	/* Intermediate decompression buffer & tables */
 	Trace(TRACE_MEMORY, "Freeing decompression buffer\n");
-	if (pdev->decompress_buffer != NULL)
-		vfree(pdev->decompress_buffer);
-	pdev->decompress_buffer = NULL;
+	if (pdev->decompress_data != NULL) {
+		kfree(pdev->decompress_data);
+		pdev->decompress_data = NULL;
+	}
+	pdev->decompressor = NULL;
 
 	/* Release image buffers */
 	Trace(TRACE_MEMORY, "Freeing image buffers\n");
@@ -401,7 +408,7 @@
    the user program. The first scheme involves the ISO buffers (called thus
    since they transport ISO data from the USB controller), and not really
    interesting. Suffices to say the data from this buffer is quickly 
-   gathered in an interrupt handler (pwc_isoc_hanlder) and placed into the 
+   gathered in an interrupt handler (pwc_isoc_handler) and placed into the 
    frame buffer.
    
    The frame buffer is the second scheme, and is the central element here.
@@ -412,8 +419,8 @@
    either read() or mmap().
    
    The image buffer is the third scheme, in which frames are decompressed
-   and converted into any of the desired image formats (rgb, bgr, yuv, etc).
-   For mmap() there is more than one image buffer available.
+   and possibly converted into planar format. For mmap() there is more than
+   one image buffer available.
 
    The frame buffers provide the image buffering, in case the user process
    is a bit slow. This introduces lag and some undesired side-effects.
@@ -500,7 +507,7 @@
 /**
   \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. 
   
-  If the image_used[] buffer is cleared too mmap()/VIDIOCSYNC will run into trouble.
+  If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
  */
 static void pwc_reset_buffers(struct pwc_device *pdev)
 {
@@ -589,10 +596,11 @@
 	pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
 }
 
+/* XXX: 2001-06-17: The YUV420 palette will be phased out soon */
 static int pwc_set_palette(struct pwc_device *pdev, int pal)
 {
-	if (
-            pal == VIDEO_PALETTE_YUV420
+	if (   pal == VIDEO_PALETTE_YUV420
+            || pal == VIDEO_PALETTE_YUV420P
 #if PWC_DEBUG
             || pal == VIDEO_PALETTE_RAW
 #endif
@@ -640,10 +648,7 @@
 	fbuf = pdev->fill_frame;
 	if (fbuf == NULL) {
 		Err("pwc_isoc_handler without valid fill frame.\n");
-		if (waitqueue_active(&pdev->frameq))
-			wake_up_interruptible(&pdev->frameq);
-		if (waitqueue_active(&pdev->pollq))
-			wake_up_interruptible(&pdev->pollq);
+		wake_up_interruptible(&pdev->frameq);
 		return;
 	}
 	fillptr = fbuf->data + fbuf->filled;
@@ -750,12 +755,8 @@
 			pdev->vlast_packet_size = flen;
 		} /* ..status == 0 */
 	}
-	if (awake) {
-		if (waitqueue_active(&pdev->frameq))
-			wake_up_interruptible(&pdev->frameq);
-		if (waitqueue_active(&pdev->pollq))
-			wake_up_interruptible(&pdev->pollq);
-	}
+	if (awake)
+		wake_up_interruptible(&pdev->frameq);
 }
 
 
@@ -811,6 +812,7 @@
 		while (i >= 0) {
 			if (pdev->sbuf[i].urb != NULL)
 				usb_free_urb(pdev->sbuf[i].urb);
+			pdev->sbuf[i].urb = NULL;
 			i--;
 		}
 		return ret;
@@ -842,6 +844,8 @@
 		ret = usb_submit_urb(pdev->sbuf[i].urb);
 		if (ret)
 			Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+		else
+			Trace(TRACE_OPEN, "pwc_isoc_init(): URB submitted.\n");
 	}
 
 	/* data should stream in now */
@@ -945,10 +949,16 @@
 		}
 	}
 
+	/* Find our decompressor, if any */
+	pdev->decompressor = pwc_find_decompressor(pdev->type);
+#if PWC_DEBUG	
+	Debug("Found decompressor for %d at 0x%p\n", pdev->type, pdev->decompressor);
+#endif
+
 	/* So far, so good. Allocate memory. */
 	i = pwc_allocate_buffers(pdev);
 	if (i < 0) {
-		Trace(TRACE_OPEN, "Failed to allocate memory.\n");
+		Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
 		up(&pdev->modlock);
 		return i;
 	}
@@ -965,12 +975,6 @@
 	pdev->sequence = 0;
 #endif
 
-	/* Find our decompressor, if any */
-	pdev->decompressor = pwc_find_decompressor(pdev->type);
-#if PWC_DEBUG	
-	Debug("Found decompressor for %d at 0x%p\n", pdev->type, pdev->decompressor);
-#endif
-
 	/* Set some defaults */
 	pdev->vsnapshot = 0;
 	if (pdev->type == 730 || pdev->type == 740)
@@ -1064,12 +1068,11 @@
 	}
 
 	pdev->vopen = 0;
-	pwc_free_buffers(pdev);
 	if (pdev->decompressor != NULL) {
-		pdev->decompressor->exit(&pdev->decompress_data);
+		pdev->decompressor->exit();
 		pdev->decompressor->unlock();
 	}
-	pdev->decompressor = NULL;
+	pwc_free_buffers(pdev);
 
 	/* wake up _disconnect() routine */
 	if (pdev->unplugged)
@@ -1078,11 +1081,20 @@
 
 /*
  *	FIXME: what about two parallel reads ????
+ *      ANSWER: Not supported. You can't open the device more than once,
+                despite what the V4L1 interface says. First, I don't see 
+                the need, second there's no mechanism of alerting the 
+                2nd/3rd/... process of events like changing image size.
+                And I don't see the point of blocking that for the 
+                2nd/3rd/... process.
+                In multi-threaded environments reading parallel from any
+                device is tricky anyhow.
  */
  
 static long pwc_video_read(struct video_device *vdev, char *buf, unsigned long count, int noblock)
 {
 	struct pwc_device *pdev;
+	DECLARE_WAITQUEUE(wait, current);
 
 	Trace(TRACE_READ, "video_read(0x%p, %p, %ld, %d) called.\n", vdev, buf, count, noblock);
 	if (vdev == NULL)
@@ -1097,20 +1109,26 @@
 
 	/* In case we're doing partial reads, we don't have to wait for a frame */
 	if (pdev->image_read_pos == 0) {
-		/* See if a frame is completed, process that */
-		if (noblock && pdev->full_frames == NULL)
-			return -EAGAIN;
+		/* Do wait queueing according to the (doc)book */
+		add_wait_queue(&pdev->frameq, &wait);
 		while (pdev->full_frames == NULL) {
-			interruptible_sleep_on(&pdev->frameq);
-			if (pdev->unplugged) {
-				Debug("pwc_video_read: Device got unplugged (2).\n");
-				return -EPIPE;
-			}
-			if (signal_pending(current))
-				return -EINTR;
-		}
- 
-		/* Decompress & convert now */
+	                if (noblock) {
+	                	remove_wait_queue(&pdev->frameq, &wait);
+	                	current->state = TASK_RUNNING;
+	                	return -EWOULDBLOCK;
+	                }
+	                if (signal_pending(current)) {
+	                	remove_wait_queue(&pdev->frameq, &wait);
+	                	current->state = TASK_RUNNING;
+	                	return -ERESTARTSYS;
+	                }
+	                schedule();
+	                current->state = TASK_INTERRUPTIBLE;
+		}
+		remove_wait_queue(&pdev->frameq, &wait);
+		current->state = TASK_RUNNING;
+	                                                                                                                                                                                
+		/* Decompress [, convert] and release frame */
 		if (pwc_handle_frame(pdev))
 			return -EFAULT;
 	}
@@ -1145,7 +1163,7 @@
 	if (pdev == NULL)
 		return -EFAULT;
 	
-	poll_wait(file, &pdev->pollq, wait);
+	poll_wait(file, &pdev->frameq, wait);
 	if (pdev->unplugged) {
 		Debug("pwc_video_poll: Device got unplugged.\n");
 		return POLLERR;
@@ -1159,6 +1177,7 @@
 static int pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 {
 	struct pwc_device *pdev;
+	DECLARE_WAITQUEUE(wait, current);
 	
 	if (vdev == NULL)
 		return -EFAULT;
@@ -1271,6 +1290,11 @@
 
 			/*
 			 *	FIXME:	Suppose we are mid read
+			        ANSWER: No problem: the firmware of the camera
+			                can handle brightness/contrast/etc
+			                changes at _any_ time, and the palette
+			                is used exactly once in the uncompress
+			                routine.
 			 */
 			pwc_set_brightness(pdev, p.brightness);
 			pwc_set_contrast(pdev, p.contrast);
@@ -1309,11 +1333,6 @@
 			if (copy_from_user(&vw, arg, sizeof(vw)))
 				return -EFAULT;
 
-/*
-			size = pwc_decode_size(pdev, vw.width, vw.height);
-			if (size < 0)
-				return -EINVAL;
-*/				
 			fps = (vw.flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
 			snapshot = vw.flags & PWC_FPS_SNAPSHOT;
 			if (fps == 0)
@@ -1385,11 +1404,6 @@
 				int ret;
 				
 				Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
-/*
-				size = pwc_decode_size(pdev, vm.width, vm.height);
-				if (size < 0)
-					return -EINVAL;
-*/					
 				ret = pwc_try_video_mode(pdev, vm.width, vm.height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
 				if (ret)
 					return ret;
@@ -1435,28 +1449,32 @@
 
 			Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", mbuf);
 
+			/* bounds check */
 			if (mbuf < 0 || mbuf >= default_mbufs)
 				return -EINVAL;
 			/* check if this buffer was requested anyway */
 			if (pdev->image_used[mbuf] == 0)
 				return -EINVAL;
 
-			/* We (re)use the frame-waitqueue here. That may
-			   conflict with read(), but any programmer that uses
-			   read() and mmap() simultaneously should be given 
-			   a job at Micro$oft. As janitor.
+			/* Add ourselves to the frame wait-queue.
 			   
 			   FIXME: needs auditing for safety.
+			   QUSTION: In what respect? I think that using the
+			            frameq is safe now.
 			 */
+			add_wait_queue(&pdev->frameq, &wait);
 			while (pdev->full_frames == NULL) {
-				interruptible_sleep_on(&pdev->frameq);
-				if (pdev->unplugged) {
-					Debug("VIDIOCSYNC: Device got unplugged.\n");
-					return -EPIPE;
-				}
-				if (signal_pending(current))
-					return -EINTR;
+	                	if (signal_pending(current)) {
+	                		remove_wait_queue(&pdev->frameq, &wait);
+		                	current->state = TASK_RUNNING;
+		                	return -ERESTARTSYS;
+	        	        }
+	                	schedule();
+		                current->state = TASK_INTERRUPTIBLE;
 			}
+			remove_wait_queue(&pdev->frameq, &wait);
+			current->state = TASK_RUNNING;
+				
 			/* The frame is ready. Expand in the image buffer 
 			   requested by the user. I don't care if you 
 			   mmap() 5 buffers and request data in this order: 
@@ -1537,7 +1555,6 @@
 
 	vendor_id = udev->descriptor.idVendor;
 	product_id = udev->descriptor.idProduct;
-	
 
 	if (vendor_id == 0x0471) {
 		switch (product_id) {
@@ -1612,7 +1629,6 @@
 
 	pdev->udev = udev;
 	init_waitqueue_head(&pdev->frameq);
-	init_waitqueue_head(&pdev->pollq);
 	init_waitqueue_head(&pdev->remove_ok);
 	pdev->vcompression = pwc_preferred_compression;
 
@@ -1691,7 +1707,6 @@
 			   a frame, let them return an error condition
 			 */
 			wake_up(&pdev->frameq);
-			wake_up(&pdev->pollq);
 			
 			/* Wait until we get a 'go' from _close(). This
 			   had a gigantic race condition, since we kfree()
@@ -1736,7 +1751,7 @@
 MODULE_PARM(fps, "i");
 MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
 MODULE_PARM(palette, "s");
-MODULE_PARM_DESC(palette, "Initial colour format of images. One of rgb24, bgr24, rgb32, bgr32, yuyv, yuv420, yuv420p");
+MODULE_PARM_DESC(palette, "Initial colour format of images. One of yuv420, yuv420p");
 MODULE_PARM(fbufs, "i");
 MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
 MODULE_PARM(mbufs, "i");
@@ -1786,8 +1801,10 @@
 		/* Determine default palette */
 		if (!strcmp(palette, "yuv420"))
 			default_palette = VIDEO_PALETTE_YUV420;
+		if (!strcmp(palette, "yuv420p"))
+			default_palette = VIDEO_PALETTE_YUV420P;
 		else {
-			Err("Palette not recognized: try palette=yuv420.\n");
+			Err("Palette not recognized: try palette=yuv420 or yuv420p.\n");
 			return -EINVAL;
 		}
 		Info("Default palette set to %d.\n", default_palette);
diff -u linux-2.4.5-dist/drivers/usb/pwc-uncompress.c linux-2.4.5/drivers/usb/pwc-uncompress.c
--- linux-2.4.5-dist/drivers/usb/pwc-uncompress.c	Sat Jun  2 03:53:46 2001
+++ linux-2.4.5/drivers/usb/pwc-uncompress.c	Wed Jun 20 02:05:17 2001
@@ -21,6 +21,8 @@
    themselves. It also has a decompressor wrapper function.
 */
 
+#include <asm/types.h>
+
 #include "pwc.h"
 #include "pwc-uncompress.h"
 
@@ -38,7 +40,7 @@
 void pwc_register_decompressor(struct pwc_decompressor *pwcd)
 {
 	if (pwc_find_decompressor(pwcd->type) == NULL) {
-		Debug("Adding decompressor for model %d.\n", pwcd->type);
+		Trace(TRACE_PWCX, "Adding decompressor for model %d.\n", pwcd->type);
 		list_add_tail(&pwcd->pwcd_list, &pwc_decompressor_list);
 	}
 }
@@ -50,7 +52,7 @@
 	
 	find = pwc_find_decompressor(type);
 	if (find != NULL) {
-		Debug("Removing decompressor for model %d.\n", type);
+		Trace(TRACE_PWCX, "Removing decompressor for model %d.\n", type);
 		list_del(&find->pwcd_list);
 	}
 }
@@ -74,8 +76,11 @@
 int pwc_decompress(struct pwc_device *pdev)
 {
 	struct pwc_frame_buf *fbuf;
-	int n, l, c, w;
+	int n, line, col, stride;
 	void *yuv, *image, *dst;
+	u16 *src;
+	u16 *dsty, *dstu, *dstv;
+
 	
 	if (pdev == NULL)
 		return -EFAULT;
@@ -92,7 +97,7 @@
 	image = pdev->image_ptr[pdev->fill_image];
 	if (!image)
 		return -EFAULT;
-
+	
 #if PWC_DEBUG
 	/* This is a quickie */
 	if (pdev->vpalette == VIDEO_PALETTE_RAW) {
@@ -101,49 +106,78 @@
 	}
 #endif
 
-	/* Compressed formats are decompressed in decompress_buffer, then 
-	 * transformed into the desired format 
-	 */
-	yuv = pdev->decompress_buffer;
-	n = 0;
-	if (pdev->vbandlength == 0) { /* uncompressed */
-		yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
-	}
-	else {
-		if (pdev->decompressor)
-			n = pdev->decompressor->decompress(pdev->decompress_data, pdev->image.x, pdev->image.y, pdev->vbandlength, yuv, fbuf->data + pdev->frame_header_size, 0);
-		else
-			n = -ENXIO; /* No such device or address: missing decompressor */
-	}
-	if (n < 0) {
-		Err("Error in decompression engine: %d\n", n);
-		return n;
-	}
-
-	/* At this point 'yuv' always points to the uncompressed, non-scaled YUV420I data */
-	if (pdev->image.x == pdev->view.x && pdev->image.y == pdev->view.y) {
-		/* Sizes matches; make it quick */
-		switch(pdev->vpalette) {
+	yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
+	if (pdev->vbandlength == 0) { 
+		/* Uncompressed mode. We copy the data into the output buffer,
+		   using the viewport size (which may be larger than the image
+		   size). Unfortunately we have to do a bit of byte stuffing
+		   to get the desired output format/size.
+		 */
+		switch (pdev->vpalette) {
 		case VIDEO_PALETTE_YUV420:
-			memcpy(image, yuv, pdev->image.size);
+			/* Calculate byte offsets per line in image & view */
+			n   = (pdev->image.x * 3) / 2;
+			col = (pdev->view.x  * 3) / 2;
+			/* Offset into image */
+			dst = image + (pdev->view.x * pdev->offset.y + pdev->offset.x) * 3 / 2;
+			for (line = 0; line < pdev->image.y; line++) {
+				memcpy(dst, yuv, n);
+				yuv += n;
+				dst += col;
+			}
 			break;
-		}
-	}
-	else {
- 		/* Size mismatch; use viewport conversion routines */
-	 	switch(pdev->vpalette) {
-		case VIDEO_PALETTE_YUV420:
-			dst = image + pdev->offset.size;
-			w = pdev->view.x * 6;
-			c = pdev->image.x * 6;
-			for (l = 0; l < pdev->image.y; l++) {
-				memcpy(dst, yuv, c);
-				dst += w;
-				yuv += c;
+
+		case VIDEO_PALETTE_YUV420P:
+			/* 
+			 * We do some byte shuffling here to go from the 
+			 * native format to YUV420P.
+			 */
+			src = (u16 *)yuv;
+			n = pdev->view.x * pdev->view.y;
+
+			/* offset in Y plane */
+			stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
+			dsty = (u16 *)(image + stride);
+
+			/* offsets in U/V planes */
+			stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
+			dstu = (u16 *)(image + n +         stride);
+			dstv = (u16 *)(image + n + n / 4 + stride);
+
+			/* increment after each line */
+			stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
+
+			for (line = 0; line < pdev->image.y; line++) {
+				for (col = 0; col < pdev->image.x; col += 4) {
+					*dsty++ = *src++;
+					*dsty++ = *src++;
+					if (line & 1)
+						*dstv++ = *src++;
+					else
+						*dstu++ = *src++;
+				}
+				dsty += stride;
+				if (line & 1)
+					dstv += (stride >> 1);
+				else
+					dstu += (stride >> 1);
 			}
 			break;
- 		}
- 	}
+		}
+	}
+	else { 
+		/* Compressed; the decompressor routines will write the data 
+		   in interlaced or planar format immediately.
+		 */
+		if (pdev->decompressor)
+			pdev->decompressor->decompress(
+				&pdev->image, &pdev->view, &pdev->offset,
+				yuv, image, 
+				pdev->vpalette == VIDEO_PALETTE_YUV420P ? 1 : 0,
+				pdev->decompress_data, pdev->vbandlength);
+		else
+			return -ENXIO; /* No such device or address: missing decompressor */
+	}
 	return 0;
 }
 
@@ -154,4 +188,3 @@
 EXPORT_SYMBOL_NOVERS(pwc_decompressor_version);
 EXPORT_SYMBOL(pwc_register_decompressor);
 EXPORT_SYMBOL(pwc_unregister_decompressor);
-EXPORT_SYMBOL(pwc_find_decompressor);
diff -u linux-2.4.5-dist/drivers/usb/pwc-uncompress.h linux-2.4.5/drivers/usb/pwc-uncompress.h
--- linux-2.4.5-dist/drivers/usb/pwc-uncompress.h	Sat Jun  2 03:53:46 2001
+++ linux-2.4.5/drivers/usb/pwc-uncompress.h	Wed Jun 20 01:44:46 2001
@@ -15,13 +15,19 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
+/* This file is the bridge between the kernel module and the plugin; it
+   describes the structures and datatypes used in both modules. Any
+   significant change should be reflected by increasing the 
+   pwc_decompressor_version major number.
+ */
 #ifndef PWC_DEC_H
 #define PWC_DEC_H
 
 #include <linux/config.h>
-
 #include <linux/list.h>
 
+#include "pwc.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -33,12 +39,16 @@
  */
 struct pwc_decompressor
 {
-	int  type;	/* type of camera (645, 646, etc) */
-	int  (* init)(int release, void *buffer, void **data);	/* Initialization routine; should be called after each set_video_mode */
-	void (* exit)(void **data);	/* Cleanup routine */
-	int  (* decompress)(void *data, int width, int height, int bandlength, void *dst, void *src, int planar); /* The decompression routine itself */
-	void (* lock)(void); /* make sure module cannot be unloaded */
-	void (* unlock)(void); /* release lock on module */
+	int  type;		/* type of camera (645, 680, etc) */
+	int  table_size;	/* memory needed */
+
+	void (* init)(int release, void *buffer, void *table);	/* Initialization routine; should be called after each set_video_mode */
+	void (* exit)(void);	/* Cleanup routine */
+	void (* decompress)(struct pwc_coord *image, struct pwc_coord *view, struct pwc_coord *offset,
+                            void *src, void *dst, int planar,
+	                    void *table, int bandlength);
+	void (* lock)(void);	/* make sure module cannot be unloaded */
+	void (* unlock)(void);	/* release lock on module */
 
 	struct list_head pwcd_list;
 };
Only in linux-2.4.5/drivers/usb: pwc-uncompress.o
diff -u linux-2.4.5-dist/drivers/usb/pwc.h linux-2.4.5/drivers/usb/pwc.h
--- linux-2.4.5-dist/drivers/usb/pwc.h	Sat Jun  2 03:53:46 2001
+++ linux-2.4.5/drivers/usb/pwc.h	Wed Jun 20 01:42:37 2001
@@ -43,6 +43,7 @@
 #define TRACE_MEMORY	0x0010
 #define TRACE_FLOW	0x0020
 #define TRACE_SIZE	0x0040
+#define TRACE_PWCX	0x0080
 #define TRACE_SEQUENCE	0x1000
 
 #define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
@@ -56,28 +57,10 @@
 #define TOUCAM_TRAILER_SIZE		4
 
 /* Version block */
-#define PWC_MAJOR	7
-#define PWC_MINOR	1
-#define PWC_RELEASE 	"7.1"
-
-#if defined(CONFIG_ARM)
-  #define PWC_PROCESSOR "ARM"
-#endif
-#if defined(CONFIG_M686)
-  #define PWC_PROCESSOR "PPro"
-#endif
-#if !defined(PWC_PROCESSOR)
-  #define PWC_PROCESSOR "P5"
-#endif  
-
-#if defined(__SMP__) || defined(CONFIG_SMP)
-#define PWC_SMP "(SMP)"
-#else
-#define PWC_SMP "(UP)"
-#endif
-
-#define PWC_VERSION PWC_RELEASE " " PWC_PROCESSOR " " PWC_SMP
-#define PWC_NAME "pwc"
+#define PWC_MAJOR	8
+#define PWC_MINOR	0
+#define PWC_VERSION 	"8.0"
+#define PWC_NAME 	"pwc"
 
 /* Turn certain features on/off */
 #define PWC_INT_PIPE 0
@@ -156,12 +139,12 @@
    char vsnapshot;		/* snapshot mode */
    char vsync;			/* used by isoc handler */
 
-   /* The image acquisition requires 3 to 5 steps:
+   /* The image acquisition requires 3 to 4 steps:
       1. data is gathered in short packets from the USB controller
       2. data is synchronized and packed into a frame buffer
-      3. in case data is compressed, decompress it into a separate buffer
-      4. data is optionally converted to RGB/YUV 
-      5. data is transfered to the user process
+      3a. in case data is compressed, decompress it directly into image buffer
+      3b. in case data is uncompressed, copy into image buffer with viewport
+      4. data is transfered to the user process
 
       Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... 
       We have in effect a back-to-back-double-buffer system.
@@ -171,11 +154,11 @@
    char iso_init;
    
    /* 2: frame */
-   struct pwc_frame_buf *fbuf;
-   struct pwc_frame_buf *empty_frames, *empty_frames_tail;
-   struct pwc_frame_buf *full_frames, *full_frames_tail;
-   struct pwc_frame_buf *read_frame;
-   struct pwc_frame_buf *fill_frame;
+   struct pwc_frame_buf *fbuf;	/* all frames */
+   struct pwc_frame_buf *empty_frames, *empty_frames_tail;	/* all empty frames */
+   struct pwc_frame_buf *full_frames, *full_frames_tail;	/* all filled frames */
+   struct pwc_frame_buf *fill_frame;	/* frame currently filled */
+   struct pwc_frame_buf *read_frame;	/* frame currently read by user process */
    int frame_size;
    int frame_header_size, frame_trailer_size;
    int drop_frames;
@@ -186,7 +169,6 @@
    /* 3: decompression */
    struct pwc_decompressor *decompressor;	/* function block with decompression routines */
    void *decompress_data;		/* private data for decompression engine */
-   void *decompress_buffer;		/* decompressed data */
 
    /* 4: image */
    /* We have an 'image' and a 'view', where 'image' is the fixed-size image
@@ -205,20 +187,11 @@
    int image_read_pos;			/* In case we read data in pieces, keep track of were we are in the imagebuffer */
    int image_used[MAX_IMAGES];		/* For MCAPTURE and SYNC */
 
-   /* Kernel specific structures. These were once moved to the end 
-      of the structure and padded with bytes after I found out
-      some of these have different sizes in different kernel versions.
-      But since this is now a source release, I don't have this problem
-      anymore.
-
-      Fortunately none of these structures are needed in the pwcx module.
-    */
    struct semaphore modlock;		/* to prevent races in video_open(), etc */
    spinlock_t ptrlock;			/* for manipulating the buffer pointers */
 
    /*** Misc. data ***/
    wait_queue_head_t frameq;		/* When waiting for a frame to finish... */
-   wait_queue_head_t pollq;		/* poll() has it's own waitqueue */
    wait_queue_head_t remove_ok;		/* When we got hot unplugged, we have to avoid a few race conditions */
 #if PWC_INT_PIPE
    void *usb_int_handler;		/* for the interrupt endpoint */
