diff -u usb-stock/Config.in usb/Config.in
--- usb-stock/Config.in	2003-06-07 21:50:52.000000000 -0400
+++ usb/Config.in	2003-06-07 21:54:34.000000000 -0400
@@ -82,6 +82,7 @@
       comment '  Video4Linux support is needed for USB Multimedia device support'
    else
       dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB IBM Ultraport II Camera support' CONFIG_USB_ULTRACAM $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
diff -u usb-stock/Makefile usb/Makefile
--- usb-stock/Makefile	2003-06-07 21:51:08.000000000 -0400
+++ usb/Makefile	2003-06-07 21:55:04.000000000 -0400
@@ -72,7 +72,8 @@
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
 obj-$(CONFIG_USB_EMI26)		+= emi26.o
 obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
-obj-$(CONFIG_USB_IBMCAM)	+= ibmcam.o usbvideo.o ultracam.o
+obj-$(CONFIG_USB_IBMCAM)	+= ibmcam.o usbvideo.o
+obj-$(CONFIG_USB_ULTRACAM)      += ultracam.o usbvideo.o
 obj-$(CONFIG_USB_PWC)		+= pwc.o
 obj-$(CONFIG_USB_DC2XX)		+= dc2xx.o
 obj-$(CONFIG_USB_MDC800)	+= mdc800.o
diff -u usb-stock/ultracam.c usb/ultracam.c
--- usb-stock/ultracam.c	2003-06-07 21:50:32.000000000 -0400
+++ usb/ultracam.c	2003-06-08 16:14:53.000000000 -0400
@@ -1,5 +1,11 @@
-/*
- * USB NB Camera driver
+/* -*- linux-c -*-
+ *
+ * USB NB (Ultraport) Camera driver
+ *
+ * Original source by Dmitri
+ * Updated by Karl Gutwin <karl@gutwin.org>
+ * Updated by Jakob Lichtenberg <jl@itu.dk>
+ * Thanks to axel grossklaus <axel@nomaden.org>
  */
 
 #include <linux/kernel.h>
@@ -16,33 +22,42 @@
 #define MAX_CAMERAS		4	/* How many devices we allow to connect */
 
 /*
- * This structure lives in uvd->user field.
+ * This structure lives in uvd_t->user field.
  */
 typedef struct {
-	int initialized;	/* Had we already sent init sequence? */
-	int camera_model;	/* What type of IBM camera we got? */
-        int has_hdr;
+  int initialized;	/* Had we already sent init sequence? */
+  int camera_model;	/* What type of IBM camera we got? */
+  int has_hdr;
+  int bytes_in;         /* bytes remaining to read before drop */
+  int invert;           /* shall we invert the picture? */
+
+  int rbar, gbar, bbar; /* mean vals for rgb, used for auto wb */
+  int projected_whitebal;
+  int frames_since_adjust;
+  int ybar;
+  
+
 } ultracam_t;
 #define	ULTRACAM_T(uvd)	((ultracam_t *)((uvd)->user_data))
 
-static struct usbvideo *cams = NULL;
+struct usbvideo *cams = NULL;
+
+static int debug = 9;
 
-static int debug = 0;
+static int ultracam_is_backward(struct uvd *uvd);
+static void ultracam_set_white_balance(struct uvd *uvd);
 
 static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
 
 static const int min_canvasWidth  = 8;
 static const int min_canvasHeight = 4;
 
-//static int lighting = 1; /* Medium */
+static int whitebal = -1; /* auto whitebal */
+static int wbmaxdelt = 1;
 
 #define SHARPNESS_MIN	0
-#define SHARPNESS_MAX	6
-//static int sharpness = 4; /* Low noise, good details */
-
-#define FRAMERATE_MIN	0
-#define FRAMERATE_MAX	6
-static int framerate = -1;
+#define SHARPNESS_MAX	4
+static int sharpness = 3; /* Low noise, good details */
 
 /*
  * Here we define several initialization variables. They may
@@ -60,9 +75,43 @@
  */
 static int init_brightness = 128;
 static int init_contrast = 192;
-static int init_color = 128;
-static int init_hue = 128;
-static int hue_correction = 128;
+static int init_sat = 10;
+static int init_hue = 180;
+
+static int brite = 0;
+MODULE_PARM(brite, "i");
+MODULE_PARM_DESC(brite, "y adjust: (-255)-(255) (default=0)");
+
+static unsigned short hs_0b = 0x002e;
+static unsigned short hs_0c = 0x00d6;
+static unsigned short hs_0d = 0x00fc;
+static unsigned short hs_0e = 0x00f1;
+static unsigned short hs_0f = 0x00da;
+static unsigned short hs_10 = 0x0036;
+
+MODULE_PARM(hs_0b, "h");
+MODULE_PARM(hs_0c, "h");
+MODULE_PARM(hs_0d, "h");
+MODULE_PARM(hs_0e, "h");
+MODULE_PARM(hs_0f, "h");
+MODULE_PARM(hs_10, "h");
+
+static unsigned short wb_51 = 0xff00;
+static unsigned short wb_52 = 0xff00;
+static unsigned short wb_53 = 0xff00;
+static unsigned short wb_11 = 0xff00;
+static unsigned short wb_12 = 0xff00;
+static unsigned short wb_13 = 0xff00;
+
+MODULE_PARM(wb_51, "h");
+MODULE_PARM(wb_52, "h");
+MODULE_PARM(wb_53, "h");
+MODULE_PARM(wb_11, "h");
+MODULE_PARM(wb_12, "h");
+MODULE_PARM(wb_13, "h");
+
+static int yuv = 0;
+MODULE_PARM(yuv, "i");
 
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
@@ -75,40 +124,347 @@
 		"4=test pattern, "
 		"5=separate frames, "
 		"6=clean frames");
-MODULE_PARM(framerate, "i");
-MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
-MODULE_PARM(lighting, "i");
-MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
+MODULE_PARM(whitebal, "i");
+MODULE_PARM_DESC(whitebal, "White balance: 0-48 (0:bluish, 48:reddish) or -1: automatic(default)");
+MODULE_PARM(wbmaxdelt, "i");
+MODULE_PARM_DESC(wbmaxdelt, "White balance maximum delta: 1-48 (1:slow, 48:fast) (default=1)");
 MODULE_PARM(sharpness, "i");
-MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
+MODULE_PARM_DESC(sharpness, "Sharpness: 0=smooth, 4=sharp (default=3)");
 
 MODULE_PARM(init_brightness, "i");
-MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
+MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128) or -1: automatic");
 MODULE_PARM(init_contrast, "i");
 MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
-MODULE_PARM(init_color, "i");
-MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
+MODULE_PARM(init_sat, "i");
+MODULE_PARM_DESC(init_sat, "Saturation preconfiguration: 0-20 (default=10)");
 MODULE_PARM(init_hue, "i");
-MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
-MODULE_PARM(hue_correction, "i");
-MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
+MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-360 (default=180)");
+
+MODULE_AUTHOR ("Karl Gutwin");
+MODULE_DESCRIPTION ("IBM Ultracam I/II driver for Linux (c) 2000");
+MODULE_LICENSE("GPL");
 
 /*
- * ultracam_ProcessIsocData()
+ * ultracam_postProcess()
  *
- * Generic routine to parse the ring queue data. It employs either
- * ultracam_find_header() or ultracam_parse_lines() to do most
- * of work.
+ * Does various things to the image once it's been
+ * read in.
  *
- * 02-Nov-2000 First (mostly dummy) version.
- * 06-Nov-2000 Rewrote to dump all data into frame.
  */
-void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
+
+static void ultracam_postProcess(struct uvd *uvd, struct usbvideo_frame *frame)
 {
-	int n;
+	ultracam_t *ucam;
+	char tmp[6];
+	int delt;
+	
+	if ((uvd == NULL) || (frame == NULL))
+		return;
+	
+	if ((VIDEOSIZE_X(frame->request) == 0) || (VIDEOSIZE_Y(frame->request) == 0))
+		return;
+	
+	ucam = ULTRACAM_T(uvd);
+	
+	ucam->rbar /= (VIDEOSIZE_X(frame->request)*VIDEOSIZE_Y(frame->request));
+	ucam->gbar /= (VIDEOSIZE_X(frame->request)*VIDEOSIZE_Y(frame->request));
+	ucam->bbar /= (VIDEOSIZE_X(frame->request)*VIDEOSIZE_Y(frame->request));
+	ucam->ybar /= (VIDEOSIZE_X(frame->request)*VIDEOSIZE_Y(frame->request));
+	
+	ucam->frames_since_adjust++;
+	
+	if (ucam->frames_since_adjust > 10) { /* module param! */
+		ucam->frames_since_adjust = 0;
+		
+		if (whitebal < 0) {
+			/* Auto white balance:
+			 * I noticed that on one end of the white balance scale, 
+			 * everything looks very blue (low, 0 end). On the other
+			 * end, everything looks very red (high, 48 end). Therefore,
+			 * this simple algorithm takes the difference between the
+			 * average red and blue values, divides that by two,
+			 * and changes the white balance by that much.
+			 *
+			 * delt is the estimated distance between where we are
+			 * and where we need to be, white-balancy speaking. Since
+			 * always jumping by size delt can cause radical color
+			 * shifts (and because I'm a patient guy) we restrict the
+			 * upper range of delt to wbmaxdelt, a module parameter.
+			 * For quicker responses, increase the value of wbmaxdelt.
+			 * 
+			 * -Karl
+			 * 
+			 * PS. I know next to nothing about color or imaging... if
+			 * someone out there knows a better solution than this, let
+			 * me know! Thanks...
+			 */
+			
+			delt = ((ucam->bbar - ucam->rbar)>>1);
+			
+			if (delt > wbmaxdelt) 
+				delt = wbmaxdelt;
+			else if ((delt < 0) && (-delt > wbmaxdelt)) 
+				delt = -wbmaxdelt;
+			
+			ucam->projected_whitebal += delt;
+			RESTRICT_TO_RANGE(ucam->projected_whitebal, 0, 48);
+			
+			if (debug > 0)
+				info("Autoadjusting whitebal to %d",ucam->projected_whitebal);
+			ultracam_set_white_balance(uvd);
+		}
+		
+	}
+	
+	/* Optionally display statistics on the screen */
+	if (uvd->flags & FLAGS_OVERLAY_STATS) {
+		usbvideo_OverlayStats(uvd, frame);
+		
+		sprintf(tmp, "wb%3d", ucam->projected_whitebal);
+		usbvideo_OverlayString(uvd, frame, (VIDEOSIZE_X(frame->request) - 30), 100, tmp);
+		
+		sprintf(tmp, "r %3d", ucam->rbar);
+		usbvideo_OverlayString(uvd, frame, (VIDEOSIZE_X(frame->request) - 30), 116, tmp);
+		sprintf(tmp, "g %3d", ucam->gbar);
+		usbvideo_OverlayString(uvd, frame, (VIDEOSIZE_X(frame->request) - 30), 124, tmp);
+		sprintf(tmp, "b %3d", ucam->bbar);
+		usbvideo_OverlayString(uvd, frame, (VIDEOSIZE_X(frame->request) - 30), 132, tmp);
+		
+		sprintf(tmp, "y %3d", ucam->ybar);
+		usbvideo_OverlayString(uvd, frame, (VIDEOSIZE_X(frame->request) - 30), 148, tmp);
+	}
+	
+	
+}
 
-	assert(uvd != NULL);
-	assert(frame != NULL);
+
+
+
+
+/*
+ * ultracam_find_header()
+ *
+ * Locate one of supported header markers in the queue.
+ * Once found, remove all preceding bytes AND the marker (8 bytes)
+ * from the data pump queue. Whatever follows must be video lines.
+ *
+ * History:
+ * 5/16/01  Created.
+ */
+static enum ParseState ultracam_find_header(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+	ultracam_t *ucam;
+
+	if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
+		err("ibmcam_find_header: Illegal frame %d.", uvd->curframe);
+		return scan_EndParse;
+	}
+
+	ucam = ULTRACAM_T(uvd);
+	assert(ucam != NULL);
+	ucam->has_hdr = 0;
+	/* and start looking for header */
+
+	while (RingQueue_GetLength(&uvd->dp) >= 8) {
+		if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+		    (RING_QUEUE_PEEK(&uvd->dp, 1) == 0x01) &&
+		    (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x19) &&
+		    (RING_QUEUE_PEEK(&uvd->dp, 3) == 0x00) &&
+		    (RING_QUEUE_PEEK(&uvd->dp, 5) == 0x00) &&
+		    (RING_QUEUE_PEEK(&uvd->dp, 6) == 0x00) &&
+		    (RING_QUEUE_PEEK(&uvd->dp, 7) == 0x40))
+		{
+#if 0				/* This code helps to detect new frame markers */
+			info("Header sig: 00 01 19 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 4));
+#endif
+			frame->header = RING_QUEUE_PEEK(&uvd->dp, 7);
+			if ((frame->header == 0x40)) {
+#if 0
+				info("Header found.");
+#endif
+				RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 8);
+				ucam->bytes_in = 7;
+				ucam->has_hdr = 1;
+				ucam->invert = ultracam_is_backward(uvd);
+				ucam->rbar = ucam->gbar = ucam->bbar = 0;
+				break;
+			}
+		}
+		/* If we are still here then this doesn't look like a header */
+		RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+	}
+
+	if (!ucam->has_hdr) {
+		if (uvd->debug > 2)
+			info("Skipping frame, no header");
+		return scan_EndParse;
+	}
+
+	/* Header found */
+	ucam->has_hdr = 1;
+	uvd->stats.header_count++;
+	frame->scanstate = ScanState_Lines;
+	frame->curline = 0;
+
+	if (flags & FLAGS_FORCE_TESTPATTERN) {
+		usbvideo_TestPattern(uvd, 1, 1);
+		return scan_NextFrame;
+	}
+	return scan_Continue;
+}
+
+/*
+ * For some unknown reason, the Ultraport camera sticks a fluke byte into
+ * the bytestream every 640 bytes. This produces dotted lines on the
+ * picture, and when left unadjusted, skewed frames.
+ * This routine simply keeps track of how much we've dequeued so far,
+ * and drops the 640th byte of the stream.
+ * -Karl
+ */
+static int ultracam_Dequeue(struct uvd *uvd, unsigned char *buf, int req)
+{
+	ultracam_t *ucam;
+	int left;
+	ucam = ULTRACAM_T(uvd);
+
+	left = (639 - ucam->bytes_in);
+	if (req > left) {
+		RingQueue_Dequeue(&uvd->dp, buf, left);
+		RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+		ucam->bytes_in = 0;
+		/* mmmm... recursion... <drool> */
+		ultracam_Dequeue(uvd, (buf + left), (req - left));
+	} else {
+		ucam->bytes_in += req;
+		RingQueue_Dequeue(&uvd->dp, buf, req);
+	} 
+
+	return req;
+}
+
+/*
+ * ultracam_parse_lines()
+ *
+ * Parse one line (interlaced) from the buffer, put
+ * decoded RGB value into the current frame buffer
+ * and add the written number of bytes (RGB) to
+ * the *pcopylen.
+ *
+ * History:
+ * 16-May-2001 Created.
+ */
+
+static enum ParseState ultracam_parse_lines(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+	/*
+	 * Okay. Data seems to look like this:
+	 *
+	 * |----luma ----|-chroma -|
+	 * |-------------+---------|
+	 * |YYYYYYYY(320)|UUUU(160)|\
+	 * |YYYYYYYY(320)|VVVV(160)| 240 lines
+	 * |....     ... |  ...    |/
+	 * |_____________|_________|
+	 *
+	 * The chroma is overlapped over four pixels to fill out
+	 * the data.
+	 */
+
+#if 1
+	unsigned char buf[(320*3) + 10];
+	unsigned char *yl[2], *ul, *vl;
+	int tX, tY;
+	int i, j;
+	unsigned char r, g, b, y, u, v;
+
+	tX = 320;
+	tY = 240;
+
+  /* We're actually going to process two lines at once.
+   * Each chroma byte has to be duplicated over four luma
+   * bytes. However, in the process of getting the entire 
+   * chroma set, we end up reading in -two- luma lines.
+   * So... we process them all - it's quicker.
+   * (on my system, this is faster than Windows! :)
+   * -Karl
+   */
+
+	if (RingQueue_GetLength(&uvd->dp) < ((tX * 3)))
+		return scan_Out;
+
+	ultracam_Dequeue(uvd, buf, (tX * 3)); 
+	/*  RingQueue_Dequeue(&uvd->dp, buf, (tX * 3)); */
+
+	if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
+		return scan_NextFrame;
+  
+	assert(frame->data != NULL);
+	yl[0] = buf;
+	vl    = (yl[0] + tX);
+	yl[1] = (vl    + (tX >> 1));
+	ul    = (yl[1] + tX);
+
+	for (j = 0; j < 2; j++) {
+		for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+			/* At some point, I would like to scale the video to fit
+			 * the requested window, rather than ignoring the size
+			 * request.
+			 */
+			if (i < tX) {
+				y = yl[j][i];
+				u = ul[(i>>1)];
+				v = vl[(i>>1)];
+
+				/* invert around 128 (signed/unsigned conflict?) */
+				y += ((y<128)?128:-128);
+				u += ((u<128)?128:-128);
+				v += ((v<128)?128:-128);
+
+				y += brite;
+			} else
+				y = u = v = 0;
+
+			if (flags & FLAGS_MONOCHROME) {
+				switch (yuv) {
+				case 2:
+					r = g = b = v;
+					break;
+				case 1:
+					r = g = b = u;
+					break;
+				case 0:
+				default:
+					r = g = b = y;
+				}
+			} else {
+				YUV_TO_RGB_BY_THE_BOOK(y, u, v, r, g, b);
+			}
+			/* this is the slow way to put pixels. if you need speed,
+			 * check out how the IBM cam driver does it.
+			 */
+			if (ULTRACAM_T(uvd)->invert) {
+				RGB24_PUTPIXEL(frame, (VIDEOSIZE_X(frame->request)-i-1), (VIDEOSIZE_Y(frame->request)-frame->curline-3), r, g, b);
+			} else {
+				RGB24_PUTPIXEL(frame, i, frame->curline, r, g, b);
+			}
+
+			ULTRACAM_T(uvd)->ybar += y;
+			ULTRACAM_T(uvd)->rbar += r;
+			ULTRACAM_T(uvd)->gbar += g;
+			ULTRACAM_T(uvd)->bbar += b;
+		}
+		frame->curline++;
+	}
+
+	if (frame->curline >= VIDEOSIZE_Y(frame->request))
+		return scan_NextFrame;
+	else
+		return scan_Continue;
+
+#else
+
+	int n;
+	unsigned char buf;
 
 	/* Try to move data from queue into frame buffer */
 	n = RingQueue_GetLength(&uvd->dp);
@@ -116,21 +472,76 @@
 		int m;
 		/* See how much spare we have left */
 		m = uvd->max_frame_size - frame->seqRead_Length;
-		if (n > m)
-			n = m;
+		if (n > (m/3))
+			n = (m/3);
 		/* Now move that much data into frame buffer */
-		RingQueue_Dequeue(
-			&uvd->dp,
-			frame->data + frame->seqRead_Length,
-			m);
-		frame->seqRead_Length += m;
+		while (n > 0) {
+			ultracam_Dequeue(uvd, &buf, 1);
+			n--;
+			frame->data[frame->seqRead_Length] = buf;
+			frame->seqRead_Length++;
+			frame->data[frame->seqRead_Length] = buf;
+			frame->seqRead_Length++;
+			frame->data[frame->seqRead_Length] = buf;
+			frame->seqRead_Length++;
+		}
 	}
 	/* See if we filled the frame */
 	if (frame->seqRead_Length >= uvd->max_frame_size) {
 		frame->frameState = FrameState_Done;
 		uvd->curframe = -1;
 		uvd->stats.frame_num++;
+		return scan_NextFrame;
 	}
+
+	return scan_Continue;
+
+#endif
+}
+
+
+
+/*
+ * ultracam_ProcessIsocData()
+ *
+ * Generic routine to parse the ring queue data. It employs either
+ * ultracam_find_header() or ultracam_parse_lines() to do most
+ * of work.
+ *
+ * 02-Nov-2000 First (mostly dummy) version.
+ * 06-Nov-2000 Rewrote to dump all data into frame.
+ * 16-May-2001 Rewrote to use find_header and parse_lines.
+ */
+void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+	/*  int n; */
+	enum ParseState pstate;
+  
+	assert(uvd != NULL);
+	assert(frame != NULL);
+  
+	while (1) {
+		pstate = scan_Out;
+		if (frame->scanstate == ScanState_Scanning) {
+			pstate = ultracam_find_header(uvd, frame);
+		} else if (frame->scanstate == ScanState_Lines) {
+			pstate = ultracam_parse_lines(uvd, frame);
+		}
+
+		if (pstate == scan_Continue)
+			continue;
+		else if ((pstate == scan_NextFrame) || (pstate == scan_Out))
+			break;
+		else
+			return;
+	}
+
+	if (pstate == scan_NextFrame) {
+		frame->frameState = FrameState_Done;
+		uvd->curframe = -1;
+		uvd->stats.frame_num++;
+	}
+  
 }
 
 /*
@@ -144,16 +555,18 @@
 	unsigned char req,
 	unsigned short value,
 	unsigned short index,
-	int is_out)
+	unsigned char *is_out)
 {
 	static const char proc[] = "ultracam_veio";
+#if 0
 	unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
+#endif
 	int i;
 
 	if (!CAMERA_IS_OPERATIONAL(uvd))
 		return 0;
 
-	if (!is_out) {
+	if (is_out) {
 		i = usb_control_msg(
 			uvd->dev,
 			usb_rcvctrlpipe(uvd->dev, 0),
@@ -161,14 +574,14 @@
 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			value,
 			index,
-			cp,
-			sizeof(cp),
+			is_out,
+			2,
 			HZ);
-#if 1
+#if 0
 		info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-		       "(req=$%02x val=$%04x ind=$%04x)",
-		       cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
-		       req, value, index);
+		     "(req=$%02x val=$%04x ind=$%04x)",
+		     cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+		     req, value, index);
 #endif
 	} else {
 		i = usb_control_msg(
@@ -190,12 +603,26 @@
 	return i;
 }
 
+static int ultracam_alternateSetting(struct uvd *uvd, int setting)
+{
+	static const char proc[] = "ultracam_alternateSetting";
+	int i;
+	i = usb_set_interface(uvd->dev, uvd->iface, setting);
+	if (i < 0) {
+		err("%s: usb_set_interface error", proc);
+		uvd->last_error = i;
+		return -EBUSY;
+	}
+	return 0;
+}
+
 /*
  * ultracam_calculate_fps()
  */
 static int ultracam_calculate_fps(struct uvd *uvd)
 {
-	return 3 + framerate*4 + framerate/2;
+	/* camera does not tell me, so I guess, no? */
+	return 30; /* YEAH RIGHT! more like 5... */
 }
 
 /*
@@ -206,21 +633,112 @@
 }
 
 /*
- * ultracam_change_lighting_conditions()
+ * ultracam_set_white_balance()
  */
-static void ultracam_change_lighting_conditions(struct uvd *uvd)
+static void ultracam_set_white_balance(struct uvd *uvd)
 {
+	int wb;
+	/* white balance codes to send to cam (sniffed from Windows) */
+	unsigned short *wbp;
+	unsigned short whitebalcodes[49 * 6] = {
+		0x0034, 0x003f, 0x00da, 0x00ff, 0x0002, 0x00f5, 
+		0x0035, 0x003f, 0x00d6, 0x00ff, 0x0002, 0x00f5, 
+		0x0036, 0x003f, 0x00d3, 0x00ff, 0x0002, 0x00f5, 
+		0x0037, 0x003f, 0x00cf, 0x00ff, 0x0002, 0x00f5, 
+		0x0038, 0x003f, 0x00cc, 0x00ff, 0x0002, 0x00f5, 
+		0x0038, 0x003f, 0x00c8, 0x00ff, 0x0002, 0x00f5, 
+		0x0039, 0x003f, 0x00c5, 0x00ff, 0x0002, 0x00f5, 
+		0x003a, 0x003f, 0x00c1, 0x00ff, 0x0002, 0x00f5, 
+		0x003b, 0x003f, 0x00be, 0x0000, 0x0002, 0x00f6, 
+		0x003c, 0x003f, 0x00ba, 0x0000, 0x0002, 0x00f6, 
+		0x003d, 0x003f, 0x00b6, 0x0000, 0x0002, 0x00f6, 
+		0x003e, 0x003f, 0x00b3, 0x0000, 0x0002, 0x00f6, 
+		0x003f, 0x003f, 0x00af, 0x0001, 0x0002, 0x00f6, 
+		0x003f, 0x003f, 0x00ac, 0x0001, 0x0002, 0x00f6, 
+		0x0040, 0x003f, 0x00a8, 0x0001, 0x0002, 0x00f6, 
+		0x0041, 0x003f, 0x00a5, 0x0001, 0x0002, 0x00f6, 
+		0x0042, 0x003f, 0x00a1, 0x0001, 0x0002, 0x00f6, 
+		0x0045, 0x003f, 0x009f, 0x0001, 0x0002, 0x00f6, 
+		0x0049, 0x003f, 0x009d, 0x0001, 0x0002, 0x00f6, 
+		0x004c, 0x003f, 0x009b, 0x0000, 0x0002, 0x00f7, 
+		0x004f, 0x003f, 0x009a, 0x0000, 0x0003, 0x00f7, 
+		0x0053, 0x003f, 0x0098, 0x00ff, 0x0003, 0x00f7, 
+		0x0056, 0x003f, 0x0096, 0x00ff, 0x0003, 0x00f7, 
+		0x0059, 0x003f, 0x0094, 0x00ff, 0x0003, 0x00f7, 
+		0x005d, 0x003f, 0x0092, 0x00ff, 0x0003, 0x00f8, 
+		0x0060, 0x003f, 0x0090, 0x00ff, 0x0003, 0x00f8, 
+		0x0063, 0x003f, 0x008e, 0x00ff, 0x0003, 0x00f8, 
+		0x0066, 0x003f, 0x008c, 0x00fe, 0x0003, 0x00f8, 
+		0x006a, 0x003f, 0x008b, 0x00fe, 0x0004, 0x00f8, 
+		0x006d, 0x003f, 0x0089, 0x00fe, 0x0004, 0x00f8, 
+		0x0070, 0x003f, 0x0087, 0x00fe, 0x0004, 0x00f9, 
+		0x0074, 0x003f, 0x0085, 0x00fd, 0x0004, 0x00f9, 
+		0x0077, 0x003f, 0x0083, 0x00fd, 0x0004, 0x00f9, 
+		0x0078, 0x003f, 0x007f, 0x00fd, 0x0004, 0x00f9, 
+		0x007a, 0x003f, 0x007b, 0x00fd, 0x0004, 0x00fa, 
+		0x007b, 0x003f, 0x0077, 0x00fc, 0x0004, 0x00fa, 
+		0x007d, 0x003f, 0x0073, 0x00fc, 0x0004, 0x00fa, 
+		0x007e, 0x003f, 0x006f, 0x00fc, 0x0003, 0x00fa, 
+		0x007f, 0x003f, 0x006b, 0x00fc, 0x0003, 0x00fb, 
+		0x0081, 0x003f, 0x0067, 0x00fb, 0x0003, 0x00fb, 
+		0x0082, 0x0040, 0x0064, 0x00fb, 0x0003, 0x00fb, 
+		0x0083, 0x0040, 0x0060, 0x00fb, 0x0003, 0x00fb, 
+		0x0085, 0x0040, 0x005c, 0x00fb, 0x0003, 0x00fc, 
+		0x0086, 0x0040, 0x0058, 0x00fa, 0x0003, 0x00fc, 
+		0x0088, 0x0040, 0x0054, 0x00fa, 0x0003, 0x00fc, 
+		0x0089, 0x0040, 0x0050, 0x00fa, 0x0002, 0x00fc, 
+		0x008a, 0x0040, 0x004c, 0x00fa, 0x0002, 0x00fd, 
+		0x008c, 0x0040, 0x0048, 0x00f9, 0x0002, 0x00fd, 
+		0x008d, 0x0040, 0x0044, 0x00f9, 0x0002, 0x00fd 
+	};
+	/* I'm trying to figure out what
+	 * these codes actually mean. Some hints may
+	 * include rgb or yuv gain within the camera
+	 * itself, but it doesn't make a whole lot of
+	 * sense, since some values change a lot, some
+	 * hardly change at all, and none is precisely
+	 * linear or even suggests a coordinating function
+	 * (Yes, I plotted the values out. They're not
+	 * linear.)
+	 *
+	 * Any ideas?
+	 * -Karl
+	 */
+
+	RESTRICT_TO_RANGE(whitebal, -1, 48);
+
+	if (whitebal >= 0) 
+		wb = whitebal;
+	else
+		wb = ULTRACAM_T(uvd)->projected_whitebal;
+
+	wbp = whitebalcodes + (wb*6);
+
+	ultracam_veio(uvd, 0x01, ((wb_51==0xff00)?*wbp:wb_51), 0x0051, NULL); wbp++;
+	ultracam_veio(uvd, 0x01, ((wb_52==0xff00)?*wbp:wb_52), 0x0052, NULL); wbp++;
+	ultracam_veio(uvd, 0x01, ((wb_53==0xff00)?*wbp:wb_53), 0x0053, NULL); wbp++;
+	ultracam_veio(uvd, 0x01, ((wb_11==0xff00)?*wbp:wb_11), 0x0011, NULL); wbp++;
+	ultracam_veio(uvd, 0x01, ((wb_12==0xff00)?*wbp:wb_12), 0x0012, NULL); wbp++;
+	ultracam_veio(uvd, 0x01, ((wb_13==0xff00)?*wbp:wb_13), 0x0013, NULL);
+
 }
 
 /*
  * ultracam_set_sharpness()
  *
- * Cameras model 1 have internal smoothing feature. It is controlled by value in
- * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
- * Recommended value is 4. Cameras model 2 do not have this feature at all.
+ * Cameras have internal smoothing feature. It is controlled by value in
+ * range [0..4], where 0 is most smooth and 4 is most sharp (raw image, I guess).
+ * Recommended value is 3. 
  */
 static void ultracam_set_sharpness(struct uvd *uvd)
 {
+	unsigned char buf[2];
+	unsigned short sharps[SHARPNESS_MAX + 1] = { 0x0004, 0x0024, 0x0064, 0x00a4, 0x00e4 };
+
+	RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
+	ultracam_veio(uvd, 0x01, 0x0000, 0x0001, buf);
+	ultracam_veio(uvd, 0x01, sharps[sharpness], 0x0001, NULL);
+
 }
 
 /*
@@ -236,6 +754,9 @@
 {
 }
 
+
+
+
 /*
  * ultracam_adjust_picture()
  *
@@ -257,6 +778,13 @@
  */
 static void ultracam_video_stop(struct uvd *uvd)
 {
+	/* I think it's this... */
+	ultracam_veio(uvd, 0x02, 0x0000, 0x0001, NULL);
+	ultracam_alternateSetting(uvd, 0x00);
+	ultracam_veio(uvd, 0x01, 0x0000, 0x0001, NULL);
+	ultracam_veio(uvd, 0x02, 0x0003, 0x0000, NULL);
+	ultracam_veio(uvd, 0x02, 0x0000, 0x0005, NULL);
+  
 }
 
 /*
@@ -272,8 +800,12 @@
 
 static void ultracam_video_start(struct uvd *uvd)
 {
-	ultracam_change_lighting_conditions(uvd);
-	ultracam_set_sharpness(uvd);
+	//	ultracam_change_lighting_conditions(uvd);
+	/* this is doing no good here... looks like 
+	 * sharpness is set on camera init.
+      	ultracam_set_sharpness(uvd);
+	 */
+
 	ultracam_reinit_iso(uvd, 0);
 }
 
@@ -283,17 +815,21 @@
 	return 0;
 }
 
-static int ultracam_alternateSetting(struct uvd *uvd, int setting)
+
+static int ultracam_is_backward(struct uvd *uvd)
 {
-	static const char proc[] = "ultracam_alternateSetting";
-	int i;
-	i = usb_set_interface(uvd->dev, uvd->iface, setting);
-	if (i < 0) {
-		err("%s: usb_set_interface error", proc);
-		uvd->last_error = i;
-		return -EBUSY;
+	unsigned char buf[2];
+
+	ultracam_veio(uvd, 0x02, 0x0000, 0x000b, buf);
+	if (buf[1] == 0x05) {
+		if (debug > 2)
+			info("Camera is facing forward  [%02x %02x]",buf[0],buf[1]);
+		return 0;
+	} else {
+		if (debug > 2)
+			info("Camera is facing backward [%02x %02x]",buf[0],buf[1]);
+		return 1;
 	}
-	return 0;
 }
 
 /*
@@ -301,188 +837,237 @@
  */
 static int ultracam_setup_on_open(struct uvd *uvd)
 {
+	unsigned char buf[2];
+  
 	int setup_ok = 0; /* Success by default */
+
+	ULTRACAM_T(uvd)->projected_whitebal = 20;
+
 	/* Send init sequence only once, it's large! */
 	if (!ULTRACAM_T(uvd)->initialized) {
 		ultracam_alternateSetting(uvd, 0x04);
 		ultracam_alternateSetting(uvd, 0x00);
-		ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1);
-		ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1);
-		ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
-		ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1);
-		ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1);
-		ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1);
-		ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1);
-		ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1);
-		ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1);
-		ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1);
-		ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1);
-		ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1);
-		ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1);
-		ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1);
-		ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1);
-		ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
-		ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
-		ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
-		ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
-		ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
-		ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
-		ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
-		ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
-		ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1);
-		ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1);
-		ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1);
-		ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1);
-		ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1);
-		ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1);
-		ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1);
-		ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1);
-		ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1);
-		ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1);
-		ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1);
-		ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1);
-		ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1);
-		ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1);
-		ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1);
-		ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1);
-		ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1);
-		ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1);
-		ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1);
-		ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1);
-		ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1);
-		ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1);
-		ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
-		ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1);
-		ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1);
-		ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-		ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-		ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0);
-		ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
-		ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
-		ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
-		ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
-		ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
-		ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
-		ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
-		ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
-		ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0);
-		ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1);
-		ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1);
-		ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1);
-		ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1);
-		ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1);
-		ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1);
-		ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1);
-		ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
-		ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1);
-		ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1);
-		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+		ultracam_veio(uvd, 0x02, 0x0004, 0x000b, NULL);
+		ultracam_veio(uvd, 0x02, 0x0001, 0x0005, NULL);
+		ultracam_veio(uvd, 0x02, 0x8000, 0x0000, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x0000, NULL);
+		ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x0002, NULL);
+		ultracam_veio(uvd, 0x00, 0x000c, 0x0003, NULL);
+		ultracam_veio(uvd, 0x00, 0x000b, 0x0004, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x0005, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x0006, NULL);
+		ultracam_veio(uvd, 0x00, 0x0079, 0x0007, NULL);
+		ultracam_veio(uvd, 0x00, 0x003b, 0x0008, NULL);
+		ultracam_veio(uvd, 0x00, 0x0002, 0x000f, NULL);
+		ultracam_veio(uvd, 0x00, 0x0001, 0x0010, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x0011, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, NULL);
+		ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, NULL);
+		ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, NULL);
+		ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, NULL);
+		ultracam_veio(uvd, 0x01, 0x0010, 0x0002, NULL);
+		ultracam_veio(uvd, 0x01, 0x0066, 0x0007, NULL);
+		ultracam_veio(uvd, 0x01, 0x000b, 0x0008, NULL);
+		ultracam_veio(uvd, 0x01, 0x0034, 0x0009, NULL);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x000a, NULL);
+		ultracam_veio(uvd, 0x01, 0x002e, 0x000b, NULL);
+		ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, NULL);
+		ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, NULL);
+		ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, NULL);
+		ultracam_veio(uvd, 0x01, 0x00da, 0x000f, NULL);
+		ultracam_veio(uvd, 0x01, 0x0036, 0x0010, NULL);
+		ultracam_veio(uvd, 0x01, 0x000b, 0x0011, NULL);
+		ultracam_veio(uvd, 0x01, 0x0001, 0x0012, NULL);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x0013, NULL);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x0014, NULL);
+		ultracam_veio(uvd, 0x01, 0x0087, 0x0051, NULL);
+		ultracam_veio(uvd, 0x01, 0x0040, 0x0052, NULL);
+		ultracam_veio(uvd, 0x01, 0x0058, 0x0053, NULL);
+		ultracam_veio(uvd, 0x01, 0x0040, 0x0054, NULL);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x0040, NULL);
+		ultracam_veio(uvd, 0x01, 0x0010, 0x0041, NULL);
+		ultracam_veio(uvd, 0x01, 0x0020, 0x0042, NULL);
+		ultracam_veio(uvd, 0x01, 0x0030, 0x0043, NULL);
+		ultracam_veio(uvd, 0x01, 0x0040, 0x0044, NULL);
+		ultracam_veio(uvd, 0x01, 0x0050, 0x0045, NULL);
+		ultracam_veio(uvd, 0x01, 0x0060, 0x0046, NULL);
+		ultracam_veio(uvd, 0x01, 0x0070, 0x0047, NULL);
+		ultracam_veio(uvd, 0x01, 0x0080, 0x0048, NULL);
+		ultracam_veio(uvd, 0x01, 0x0090, 0x0049, NULL);
+		ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, NULL);
+		ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, NULL);
+		ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, NULL);
+		ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, NULL);
+		ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, NULL);
+		ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, NULL);
+		ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, NULL);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x0056, NULL);
+		ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, NULL);
+		ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, NULL);
+		ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, NULL);
+		ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, NULL);
+		ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL);
+
+		/* command mode? */
+		ultracam_veio(uvd, 0x02, 0xc040, 0x0001, NULL);
+
+		/* read in hue/sat? */
+		ultracam_veio(uvd, 0x01, 0x0000, 0x0008, buf);
+		info("hs_read: 0x08 -- 0x%x", buf[0]);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x0009, buf);
+		info("hs_read: 0x09 -- 0x%x", buf[0]);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x000a, buf);
+		info("hs_read: 0x0a -- 0x%x", buf[0]);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x000b, buf);
+		info("hs_read: 0x0b -- 0x%x", buf[0]);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x000c, buf);
+		info("hs_read: 0x0c -- 0x%x", buf[0]);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x000d, buf);
+		info("hs_read: 0x0d -- 0x%x", buf[0]);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x000e, buf);
+		info("hs_read: 0x0e -- 0x%x", buf[0]);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x000f, buf);
+		info("hs_read: 0x0f -- 0x%x", buf[0]);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x0010, buf);
+		info("hs_read: 0x10 -- 0x%x", buf[0]);
+
+		/* hue/saturation */
+		ultracam_veio(uvd, 0x01, 0x000b, 0x0008, NULL);
+		ultracam_veio(uvd, 0x01, 0x0034, 0x0009, NULL);
+		ultracam_veio(uvd, 0x01, 0x0000, 0x000a, NULL);
+
+		ultracam_veio(uvd, 0x01, hs_0b, 0x000b, NULL);
+		ultracam_veio(uvd, 0x01, hs_0c, 0x000c, NULL);
+		ultracam_veio(uvd, 0x01, hs_0d, 0x000d, NULL);
+		ultracam_veio(uvd, 0x01, hs_0e, 0x000e, NULL);
+		ultracam_veio(uvd, 0x01, hs_0f, 0x000f, NULL);
+		ultracam_veio(uvd, 0x01, hs_10, 0x0010, NULL);
+
+		/* sharpness
+		   ultracam_veio(uvd, 0x01, 0x0000, 0x0001, buf);
+		   ultracam_veio(uvd, 0x01, 0x0064, 0x0001, NULL);
+		*/
+		ultracam_set_sharpness(uvd);
+
+		/* white balance */
+		ultracam_set_white_balance(uvd);
+		/*
+		  ultracam_veio(uvd, 0x01, wb_51, 0x0051, NULL);
+		  ultracam_veio(uvd, 0x01, wb_52, 0x0052, NULL);
+		  ultracam_veio(uvd, 0x01, wb_53, 0x0053, NULL);
+		  ultracam_veio(uvd, 0x01, wb_11, 0x0011, NULL);
+		  ultracam_veio(uvd, 0x01, wb_12, 0x0012, NULL);
+		  ultracam_veio(uvd, 0x01, wb_13, 0x0013, NULL);
+		*/
+
+
+		/* here I have >>>>>>    0x0007  (unknown setting?) */
+		ultracam_veio(uvd, 0x00, 0x0009, 0x0011, NULL);
+
+		ultracam_veio(uvd, 0x00, 0x0000, 0x0001, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x0000, NULL);
+
+		/* on my system, these look like this:
+		 *                 0x00  0x001b  0x00c1
+		 *                 0x00  0x00e0  0x00c2
+		 *                 0x00  0x0000  0x00ca
+		 * some unknown values?
+		 * -Karl
+		 */
+		ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, NULL);
+		ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, NULL);
+		ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, NULL);
+
 		ultracam_alternateSetting(uvd, 0x04);
-		ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
-		ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
-		ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1);
-		ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1);
-		ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1);
-		ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0);
+		ultracam_veio(uvd, 0x02, 0x0000, 0x0001, NULL);
+		ultracam_veio(uvd, 0x02, 0x0000, 0x0001, NULL);
+		ultracam_veio(uvd, 0x02, 0x0000, 0x0006, NULL);
+
+		/* resolution */
+		ultracam_veio(uvd, 0x02, 0x9000, 0x0007, NULL);
+
+		/* turn on camera? */
+		ultracam_veio(uvd, 0x02, 0x0042, 0x0001, NULL);
+
+		ultracam_is_backward(uvd);
 		ultracam_resetPipe(uvd);
 		ULTRACAM_T(uvd)->initialized = (setup_ok != 0);
+
 	}
 	return setup_ok;
 }
@@ -494,14 +1079,14 @@
 
 	RESTRICT_TO_RANGE(init_brightness, 0, 255);
 	RESTRICT_TO_RANGE(init_contrast, 0, 255);
-	RESTRICT_TO_RANGE(init_color, 0, 255);
-	RESTRICT_TO_RANGE(init_hue, 0, 255);
-	RESTRICT_TO_RANGE(hue_correction, 0, 255);
+	RESTRICT_TO_RANGE(init_sat, 0, 20);
+	RESTRICT_TO_RANGE(init_hue, 0, 360);
+	RESTRICT_TO_RANGE(wbmaxdelt, 1, 48);
 
 	memset(&uvd->vpic, 0, sizeof(uvd->vpic));
 	memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
 
-	uvd->vpic.colour = init_color << 8;
+	uvd->vpic.colour = init_sat << 8;
 	uvd->vpic.hue = init_hue << 8;
 	uvd->vpic.brightness = init_brightness << 8;
 	uvd->vpic.contrast = init_contrast << 8;
@@ -510,7 +1095,7 @@
 	uvd->vpic.palette = VIDEO_PALETTE_RGB24;
 
 	memset(&uvd->vcap, 0, sizeof(uvd->vcap));
-	strcpy(uvd->vcap.name, "IBM Ultra Camera");
+	strcpy(uvd->vcap.name, "IBM Ultraport Camera");
 	uvd->vcap.type = VID_TYPE_CAPTURE;
 	uvd->vcap.channels = 1;
 	uvd->vcap.audios = 0;
@@ -628,7 +1213,7 @@
 	MOD_INC_USE_COUNT;
 	uvd = usbvideo_AllocateDevice(cams);
 	if (uvd != NULL) {
-		/* Here uvd is a fully allocated uvd object */
+		/* Here uvd is a fully allocated struct uvd object */
 		uvd->flags = flags;
 		uvd->debug = debug;
 		uvd->dev = dev;
@@ -639,13 +1224,14 @@
 		uvd->iso_packet_len = maxPS;
 		uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
 		uvd->defaultPalette = VIDEO_PALETTE_RGB24;
-		uvd->canvas = VIDEOSIZE(640, 480);	/* FIXME */
+		uvd->canvas = VIDEOSIZE(320, 240);	/* FIXME */
 		uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/
 
 		/* Initialize ibmcam-specific data */
 		assert(ULTRACAM_T(uvd) != NULL);
 		ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */
 		ULTRACAM_T(uvd)->initialized = 0;
+		ULTRACAM_T(uvd)->bytes_in = 0;
 
 		ultracam_configure_video(uvd);
 
@@ -659,11 +1245,12 @@
 	return uvd;
 }
 
-
-static struct usb_device_id id_table[] = {
+static __devinitdata struct usb_device_id id_table[] = {
 	{ USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
 	{ }  /* Terminating entry */
 };
+MODULE_DEVICE_TABLE(usb, id_table);
+
 
 /*
  * ultracam_init()
@@ -679,7 +1266,7 @@
 	cbTbl.videoStart = ultracam_video_start;
 	cbTbl.videoStop = ultracam_video_stop;
 	cbTbl.processData = ultracam_ProcessIsocData;
-	cbTbl.postProcess = usbvideo_DeinterlaceFrame;
+	cbTbl.postProcess = ultracam_postProcess;
 	cbTbl.adjustPicture = ultracam_adjust_picture;
 	cbTbl.getFPS = ultracam_calculate_fps;
 	return usbvideo_register(
@@ -697,8 +1284,5 @@
 	usbvideo_Deregister(&cams);
 }
 
-MODULE_DEVICE_TABLE(usb, id_table);
-MODULE_LICENSE("GPL");
-
 module_init(ultracam_init);
 module_exit(ultracam_cleanup);
diff -u usb-stock/usbvideo.c usb/usbvideo.c
--- usb-stock/usbvideo.c	2003-06-08 16:20:19.000000000 -0400
+++ usb/usbvideo.c	2003-06-07 21:52:40.000000000 -0400
@@ -267,7 +267,7 @@
 void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame,
 			  int x, int y, int ch)
 {
-	static const unsigned short digits[16] = {
+	static const unsigned short digits[36] = {
 		0xF6DE, /* 0 */
 		0x2492, /* 1 */
 		0xE7CE, /* 2 */
@@ -283,7 +283,27 @@
 		0xF24E, /* c */
 		0xD6DC, /* d */
 		0xF34E, /* e */
-		0xF348  /* f */
+		0xF348, /* f */
+		0xf2de, /* g */
+		0xb7da, /* h */
+		0xe92e, /* i */
+		0xe92c, /* j */
+		0xb75a, /* k */
+		0x924e, /* l */
+		0xbeda, /* m */
+		0xd6da, /* n */
+		0x56d4, /* o */
+		0xf7c8, /* p */
+		0xf6fe, /* q */
+		0xf75a, /* r */
+		0x739c, /* s */
+		0xe924, /* t */
+		0xb6de, /* u */
+		0xb6d4, /* v */
+		0xb6fa, /* w */
+		0xb55a, /* x */
+		0xb524, /* y */
+		0xe54e  /* z */
 	};
 	unsigned short digit;
 	int ix, iy;
@@ -293,9 +313,9 @@
 
 	if (ch >= '0' && ch <= '9')
 		ch -= '0';
-	else if (ch >= 'A' && ch <= 'F')
+	else if (ch >= 'A' && ch <= 'Z')
 		ch = 10 + (ch - 'A');
-	else if (ch >= 'a' && ch <= 'f')
+	else if (ch >= 'a' && ch <= 'z')
 		ch = 10 + (ch - 'a');
 	else
 		return;
@@ -305,7 +325,7 @@
 		for (ix=0; ix < 3; ix++) {
 			if (digit & 0x8000) {
 				if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) {
-/* TODO */				RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
+/* TODO */				RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xff, 0xff, 0xff);
 				}
 			}
 			digit = digit << 1;
@@ -403,51 +423,53 @@
 		}
 	}
 
-	sprintf(tmp, "%8lx", uvd->stats.frame_num);
+	usbvideo_OverlayString(uvd, frame, qi_x1 + 8, qi_y1 + 2, "ring buffer fill");
+
+	sprintf(tmp, "%8lx fr", uvd->stats.frame_num);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8lx", uvd->stats.urb_count);
+	sprintf(tmp, "%8lx uc", uvd->stats.urb_count);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8lx", uvd->stats.urb_length);
+	sprintf(tmp, "%8lx ul", uvd->stats.urb_length);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8lx", uvd->stats.data_count);
+	sprintf(tmp, "%8lx dc", uvd->stats.data_count);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8lx", uvd->stats.header_count);
+	sprintf(tmp, "%8lx hc", uvd->stats.header_count);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8lx", uvd->stats.iso_skip_count);
+	sprintf(tmp, "%8lx is", uvd->stats.iso_skip_count);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8lx", uvd->stats.iso_err_count);
+	sprintf(tmp, "%8lx ie", uvd->stats.iso_err_count);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8x", uvd->vpic.colour);
+	sprintf(tmp, "%8x co", uvd->vpic.colour);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8x", uvd->vpic.hue);
+	sprintf(tmp, "%8x hu", uvd->vpic.hue);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8x", uvd->vpic.brightness >> 8);
+	sprintf(tmp, "%8x br", uvd->vpic.brightness >> 8);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8x", uvd->vpic.contrast >> 12);
+	sprintf(tmp, "%8x pi", uvd->vpic.contrast >> 12);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 
-	sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8);
+	sprintf(tmp, "%8d wh", uvd->vpic.whiteness >> 8);
 	usbvideo_OverlayString(uvd, frame, x, y, tmp);
 	y += y_diff;
 }
