--- /dev/null
+diff -urN -X /home/spse/dontdiff linux-2.4.19-pre8/Documentation/Configure.help linux-2.4.19-pre8-konicawc/Documentation/Configure.help
+--- linux-2.4.19-pre8/Documentation/Configure.help Sat May 11 01:02:03 2002
++++ linux-2.4.19-pre8-konicawc/Documentation/Configure.help Sat May 11 01:19:34 2002
+@@ -13685,6 +13685,21 @@
+ The module will be called vicam.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
++Konica based Webcam
++CONFIG_USB_KONICAWC
++ Say Y here if you want support for webcams based on a Konica
++ chipset. This is known to work with the Intel YC76 webcam.
++
++ This driver uses the Video For Linux API. You must enable
++ (Y or M in config) Video For Linux (under Character Devices)
++ to use this driver. Information on this API and pointers to
++ "v4l" programs may be found on the WWW at
++ <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
++
++ This code is also available as a module ( = code which can be
++ inserted in and removed from the running kernel whenever you want).
++ The module will be called konicawc.o. If you want to compile it as
++ a module, say M here and read <file:Documentation/modules.txt>.
+
+ Pegasus/Pegasus II based USB-Ethernet device support
+ CONFIG_USB_PEGASUS
+diff -urN -X /home/spse/dontdiff linux-2.4.19-pre8/drivers/usb/Config.in linux-2.4.19-pre8-konicawc/drivers/usb/Config.in
+--- linux-2.4.19-pre8/drivers/usb/Config.in Sat May 11 01:02:11 2002
++++ linux-2.4.19-pre8-konicawc/drivers/usb/Config.in Sat May 11 01:18:02 2002
+@@ -80,6 +80,7 @@
+ dep_tristate ' USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
+ dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
+ dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
++ dep_tristate ' USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV
+ fi
+
+ comment 'USB Network adaptors'
+diff -urN -X /home/spse/dontdiff linux-2.4.19-pre8/drivers/usb/Makefile linux-2.4.19-pre8-konicawc/drivers/usb/Makefile
+--- linux-2.4.19-pre8/drivers/usb/Makefile Sat May 11 01:02:11 2002
++++ linux-2.4.19-pre8-konicawc/drivers/usb/Makefile Sat May 11 01:36:40 2002
+@@ -10,7 +10,7 @@
+
+ # Objects that export symbols.
+
+-export-objs := hcd.o usb.o ov511.o pwc-uncompress.o
++export-objs := hcd.o usb.o ov511.o pwc-uncompress.o usbvideo.o
+
+ # Multipart objects.
+
+@@ -71,6 +71,7 @@
+ obj-$(CONFIG_USB_AUDIO) += audio.o
+ obj-$(CONFIG_USB_EMI26) += emi26.o
+ obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o
++obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o
+ obj-$(CONFIG_USB_PWC) += pwc.o
+ obj-$(CONFIG_USB_DC2XX) += dc2xx.o
+ obj-$(CONFIG_USB_MDC800) += mdc800.o
+diff -urN -X /home/spse/dontdiff linux-2.4.19-pre8/drivers/usb/ibmcam.c linux-2.4.19-pre8-konicawc/drivers/usb/ibmcam.c
+--- linux-2.4.19-pre8/drivers/usb/ibmcam.c Sat May 11 01:02:11 2002
++++ linux-2.4.19-pre8-konicawc/drivers/usb/ibmcam.c Sat May 11 01:34:30 2002
+@@ -3899,6 +3899,17 @@
+ return uvd;
+ }
+
++
++static struct usb_device_id id_table[] = {
++ { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) }, /* Model 1 */
++ { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */
++ { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) }, /* Model 3 */
++ { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */
++ { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */
++ { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */
++ { } /* Terminating entry */
++};
++
+ /*
+ * ibmcam_init()
+ *
+@@ -3926,7 +3937,8 @@
+ sizeof(ibmcam_t),
+ "ibmcam",
+ &cbTbl,
+- THIS_MODULE);
++ THIS_MODULE,
++ id_table);
+ }
+
+ static void __exit ibmcam_cleanup(void)
+@@ -3934,15 +3946,6 @@
+ usbvideo_Deregister(&cams);
+ }
+
+-static __devinitdata struct usb_device_id id_table[] = {
+- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) }, /* Model 1 */
+- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */
+- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) }, /* Model 3 */
+- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */
+- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */
+- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */
+- { } /* Terminating entry */
+-};
+ MODULE_DEVICE_TABLE(usb, id_table);
+
+ module_init(ibmcam_init);
+diff -urN -X /home/spse/dontdiff linux-2.4.19-pre8/drivers/usb/konicawc.c linux-2.4.19-pre8-konicawc/drivers/usb/konicawc.c
+--- linux-2.4.19-pre8/drivers/usb/konicawc.c Thu Jan 1 01:00:00 1970
++++ linux-2.4.19-pre8-konicawc/drivers/usb/konicawc.c Sat May 11 03:18:42 2002
+@@ -0,0 +1,936 @@
++/*
++ * konicawc.c - konica webcam driver
++ *
++ * Author: Simon Evans <spse@secret.org.uk>
++ *
++ * Copyright (C) 2002 Simon Evans
++ *
++ * Licence: GPL
++ *
++ * Driver for USB webcams based on Konica chipset. This
++ * chipset is used in Intel YC76 camera.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++
++//#define DEBUG
++
++#include "usbvideo.h"
++
++#define MAX_BRIGHTNESS 108
++#define MAX_CONTRAST 108
++#define MAX_SATURATION 108
++#define MAX_SHARPNESS 108
++#define MAX_WHITEBAL 372
++#define MAX_SPEED 6
++
++
++#define MAX_CAMERAS 1
++
++#define DRIVER_VERSION "v1.3"
++#define DRIVER_DESC "Konica Webcam driver"
++
++enum ctrl_req {
++ SetWhitebal = 0x01,
++ SetBrightness = 0x02,
++ SetSharpness = 0x03,
++ SetContrast = 0x04,
++ SetSaturation = 0x05,
++};
++
++
++enum frame_sizes {
++ SIZE_160X120 = 0,
++ SIZE_160X136 = 1,
++ SIZE_176X144 = 2,
++ SIZE_320X240 = 3,
++
++};
++
++#define MAX_FRAME_SIZE SIZE_320X240
++
++static usbvideo_t *cams;
++
++/* Some default values for inital camera settings,
++ can be set by modprobe */
++
++static int debug;
++static enum frame_sizes size;
++static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */
++static int brightness = MAX_BRIGHTNESS/2;
++static int contrast = MAX_CONTRAST/2;
++static int saturation = MAX_SATURATION/2;
++static int sharpness = MAX_SHARPNESS/2;
++static int whitebal = 3*(MAX_WHITEBAL/4);
++
++static int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
++
++/* These FPS speeds are from the windows config box. They are
++ * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
++ * real fps.
++ */
++
++static int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
++ { 24, 40, 48, 60, 72, 80, 100 },
++ { 18, 30, 36, 45, 54, 60, 75 },
++ { 6, 10, 12, 15, 18, 21, 25 } };
++
++struct cam_size {
++ u16 width;
++ u16 height;
++ u8 cmd;
++};
++
++static struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
++ { 160, 136, 0xa },
++ { 176, 144, 0x4 },
++ { 320, 240, 0x5 } };
++
++struct konicawc {
++ u8 brightness; /* camera uses 0 - 9, x11 for real value */
++ u8 contrast; /* as above */
++ u8 saturation; /* as above */
++ u8 sharpness; /* as above */
++ u8 white_bal; /* 0 - 33, x11 for real value */
++ u8 speed; /* Stored as 0 - 6, used as index in spd_to_* (above) */
++ u8 size; /* Frame Size */
++ int height;
++ int width;
++ struct urb *sts_urb[USBVIDEO_NUMSBUF];
++ u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
++ struct urb *last_data_urb;
++ int lastframe;
++ int cur_frame_size; /* number of bytes in current frame size */
++ int maxline; /* number of lines per frame */
++ int yplanesz; /* Number of bytes in the Y plane */
++ unsigned int skip_frame:2;
++ unsigned int buttonsts:1;
++};
++
++
++#define konicawc_set_misc(uvd, req, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)
++#define konicawc_get_misc(uvd, req, value, index, buf, sz) konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)
++#define konicawc_set_value(uvd, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
++
++
++static int konicawc_ctrl_msg(uvd_t *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
++{
++ int retval = usb_control_msg(uvd->dev,
++ dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
++ request, 0x40 | dir, value, index, buf, len, HZ);
++ return retval < 0 ? retval : 0;
++}
++
++
++static void konicawc_set_camera_size(uvd_t *uvd)
++{
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++
++ konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
++ cam->width = camera_sizes[cam->size].width;
++ cam->height = camera_sizes[cam->size].height;
++ cam->yplanesz = cam->height * cam->width;
++ cam->cur_frame_size = (cam->yplanesz * 3) / 2;
++ cam->maxline = cam->yplanesz / 256;
++ uvd->videosize = VIDEOSIZE(cam->width, cam->height);
++}
++
++
++static int konicawc_setup_on_open(uvd_t *uvd)
++{
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++
++ konicawc_set_misc(uvd, 0x2, 0, 0x0b);
++ dbg("setting brightness to %d (%d)", cam->brightness,
++ cam->brightness * 11);
++ konicawc_set_value(uvd, cam->brightness, SetBrightness);
++ dbg("setting white balance to %d (%d)", cam->white_bal,
++ cam->white_bal * 11);
++ konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
++ dbg("setting contrast to %d (%d)", cam->contrast,
++ cam->contrast * 11);
++ konicawc_set_value(uvd, cam->contrast, SetContrast);
++ dbg("setting saturation to %d (%d)", cam->saturation,
++ cam->saturation * 11);
++ konicawc_set_value(uvd, cam->saturation, SetSaturation);
++ dbg("setting sharpness to %d (%d)", cam->sharpness,
++ cam->sharpness * 11);
++ konicawc_set_value(uvd, cam->sharpness, SetSharpness);
++ konicawc_set_camera_size(uvd);
++ konicawc_set_misc(uvd, 0x2, 1, 0x0b);
++ cam->lastframe = -1;
++ cam->skip_frame = 2;
++ cam->buttonsts = 0;
++ return 0;
++}
++
++
++static void konicawc_adjust_picture(uvd_t *uvd)
++{
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++
++ konicawc_set_misc(uvd, 0x2, 0, 0x0b);
++ dbg("new brightness: %d", uvd->vpic.brightness);
++ uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
++ if(cam->brightness != uvd->vpic.brightness / 11) {
++ cam->brightness = uvd->vpic.brightness / 11;
++ dbg("setting brightness to %d (%d)", cam->brightness,
++ cam->brightness * 11);
++ konicawc_set_value(uvd, cam->brightness, SetBrightness);
++ }
++
++ dbg("new contrast: %d", uvd->vpic.contrast);
++ uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
++ if(cam->contrast != uvd->vpic.contrast / 11) {
++ cam->contrast = uvd->vpic.contrast / 11;
++ dbg("setting contrast to %d (%d)", cam->contrast,
++ cam->contrast * 11);
++ konicawc_set_value(uvd, cam->contrast, SetContrast);
++ }
++ konicawc_set_misc(uvd, 0x2, 1, 0x0b);
++}
++
++
++static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *stsurb)
++{
++ char *cdata;
++ int i, totlen = 0;
++ unsigned char *status = stsurb->transfer_buffer;
++ int keep = 0, discard = 0, bad = 0;
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++
++ for (i = 0; i < dataurb->number_of_packets; i++) {
++ int button = cam->buttonsts;
++ unsigned char sts;
++ int n = dataurb->iso_frame_desc[i].actual_length;
++ int st = dataurb->iso_frame_desc[i].status;
++ cdata = dataurb->transfer_buffer +
++ dataurb->iso_frame_desc[i].offset;
++
++ /* Detect and ignore errored packets */
++ if (st < 0) {
++ if (debug >= 1)
++ err("Data error: packet=%d. len=%d. status=%d.",
++ i, n, st);
++ uvd->stats.iso_err_count++;
++ continue;
++ }
++
++ /* Detect and ignore empty packets */
++ if (n <= 0) {
++ uvd->stats.iso_skip_count++;
++ continue;
++ }
++
++ /* See what the status data said about the packet */
++ sts = *(status+stsurb->iso_frame_desc[i].offset);
++
++ /* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
++ * otherwise:
++ * bit 0 0: keep packet
++ * 1: drop packet (padding data)
++ *
++ * bit 4 0 button not clicked
++ * 1 button clicked
++ * button is used to `take a picture' (in software)
++ */
++
++ if(sts < 0x80) {
++ button = sts & 0x40;
++ sts &= ~0x40;
++ }
++
++ /* work out the button status, but dont do
++ anything with it for now */
++
++ if(button != cam->buttonsts) {
++ dbg("button: %sclicked", button ? "" : "un");
++ cam->buttonsts = button;
++ }
++
++ if(sts == 0x01) { /* drop frame */
++ discard++;
++ continue;
++ }
++
++ if((sts > 0x01) && (sts < 0x80)) {
++ info("unknown status %2.2x", sts);
++ bad++;
++ continue;
++ }
++
++ keep++;
++ if(sts & 0x80) { /* frame start */
++ unsigned char marker[] = { 0, 0xff, 0, 0x00 };
++
++ if(cam->skip_frame == 2) {
++ cam->skip_frame--;
++ continue;
++ }
++
++ /* Do we have enough space for this frame? */
++#if 0
++ dbg("RingQueue: need %d have %d", cam->cur_frame_size + 4, RingQueue_GetFreeSpace(&uvd->dp));
++ if(RingQueue_GetFreeSpace(&uvd->dp) < cam->cur_frame_size + 4) {
++ info("Dropping frame");
++ cam->skip_frame = 1;
++ continue;
++ } else {
++ cam->skip_frame = 0;
++ }
++#endif
++ cam->skip_frame = 0;
++
++ if(debug > 1)
++ dbg("Adding Marker packet = %d, frame = %2.2x",
++ i, *(status+i));
++ marker[3] = sts & 0x7F;
++ if(RingQueue_GetFreeSpace(&uvd->dp) < (4+n)) {
++ err("RingQueue Full! (cant add header) - Dropping frame");
++ cam->skip_frame = 1;
++ } else {
++ RingQueue_Enqueue(&uvd->dp, marker, 4);
++ }
++
++ totlen += 4;
++ }
++ if(cam->skip_frame)
++ continue;
++
++ totlen += n; /* Little local accounting */
++ if(debug > 5)
++ dbg("Adding packet %d, bytes = %d", i, n);
++ if(RingQueue_GetFreeSpace(&uvd->dp) < n) {
++ err("RingQueue Full! (want %d got %d) - Dropping frame", n,
++ RingQueue_GetFreeSpace(&uvd->dp));
++ cam->skip_frame = 1;
++ } else {
++ RingQueue_Enqueue(&uvd->dp, cdata, n);
++ }
++ }
++ if(debug > 8) {
++ dbg("finished: keep = %d discard = %d bad = %d added %d bytes",
++ keep, discard, bad, totlen);
++ }
++ return totlen;
++}
++
++
++static void konicawc_isoc_irq(struct urb *urb)
++{
++ int i, len = 0;
++ uvd_t *uvd = urb->context;
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++
++ /* We don't want to do anything if we are about to be removed! */
++ if (!CAMERA_IS_OPERATIONAL(uvd))
++ return;
++
++ if(urb->status) {
++ if(urb->status == -EOVERFLOW) {
++ dbg("isoc_irq: got babble");
++ } else if(urb->status == -ENOENT || urb->status == -EINPROGRESS) {
++ dbg("isoc_irq: URB unlinked");
++ } else {
++ dbg("isoc_irq: status %d", urb->status);
++ }
++ return;
++ }
++
++ if (urb->actual_length > 32) {
++ cam->last_data_urb = urb;
++ return;
++ }
++
++ if (!uvd->streaming) {
++ if (debug >= 1)
++ info("Not streaming, but interrupt!");
++ return;
++ }
++
++ uvd->stats.urb_count++;
++ if (urb->actual_length <= 0)
++ goto urb_done_with;
++
++ /* Copy the data received into ring queue */
++ if(cam->last_data_urb) {
++ len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
++ for (i = 0; i < FRAMES_PER_DESC; i++) {
++ cam->last_data_urb->iso_frame_desc[i].status = 0;
++ cam->last_data_urb->iso_frame_desc[i].actual_length = 0;
++ }
++ cam->last_data_urb = NULL;
++ }
++ uvd->stats.urb_length = len;
++ uvd->stats.data_count += len;
++
++ if(RingQueue_GetLength(&uvd->dp) >= 384)
++ RingQueue_WakeUpInterruptible(&uvd->dp);
++
++urb_done_with:
++
++ for (i = 0; i < FRAMES_PER_DESC; i++) {
++ urb->iso_frame_desc[i].status = 0;
++ urb->iso_frame_desc[i].actual_length = 0;
++ }
++ return;
++}
++
++
++static int konicawc_start_data(uvd_t *uvd)
++{
++ struct usb_device *dev = uvd->dev;
++ int i, errFlag;
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++ int pktsz;
++ struct usb_interface_descriptor *interface;
++
++ interface = &dev->actconfig->interface[uvd->iface].altsetting[spd_to_iface[cam->speed]];
++ pktsz = interface->endpoint[1].wMaxPacketSize;
++ dbg("pktsz = %d", pktsz);
++ if (!CAMERA_IS_OPERATIONAL(uvd)) {
++ err("Camera is not operational");
++ return -EFAULT;
++ }
++ uvd->curframe = -1;
++
++ /* Alternate interface 1 is is the biggest frame size */
++ i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
++ if (i < 0) {
++ err("usb_set_interface error");
++ uvd->last_error = i;
++ return -EBUSY;
++ }
++
++ /* We double buffer the Iso lists */
++ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
++ int j, k;
++ struct urb *urb = uvd->sbuf[i].urb;
++ urb->dev = dev;
++ urb->context = uvd;
++ urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
++ urb->transfer_flags = USB_ISO_ASAP;
++ urb->transfer_buffer = uvd->sbuf[i].data;
++ urb->complete = konicawc_isoc_irq;
++ urb->number_of_packets = FRAMES_PER_DESC;
++ urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
++ for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
++ urb->iso_frame_desc[j].offset = k;
++ urb->iso_frame_desc[j].length = pktsz;
++ }
++
++ urb = cam->sts_urb[i];
++ urb->dev = dev;
++ urb->context = uvd;
++ urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
++ urb->transfer_flags = USB_ISO_ASAP;
++ urb->transfer_buffer = cam->sts_buf[i];
++ urb->complete = konicawc_isoc_irq;
++ urb->number_of_packets = FRAMES_PER_DESC;
++ urb->transfer_buffer_length = FRAMES_PER_DESC;
++ for (j=0; j < FRAMES_PER_DESC; j++) {
++ urb->iso_frame_desc[j].offset = j;
++ urb->iso_frame_desc[j].length = 1;
++ }
++ }
++
++ cam->last_data_urb = NULL;
++
++ /* Link URBs into a ring so that they invoke each other infinitely */
++ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
++ if ((i+1) < USBVIDEO_NUMSBUF) {
++ cam->sts_urb[i]->next = uvd->sbuf[i].urb;
++ uvd->sbuf[i].urb->next = cam->sts_urb[i+1];
++ } else {
++ cam->sts_urb[i]->next = uvd->sbuf[i].urb;
++ uvd->sbuf[i].urb->next = cam->sts_urb[0];
++ }
++ }
++
++ /* Submit all URBs */
++ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
++ errFlag = usb_submit_urb(uvd->sbuf[i].urb);
++ if (errFlag)
++ err ("usb_submit_isoc(%d) ret %d", i, errFlag);
++
++ errFlag = usb_submit_urb(cam->sts_urb[i]);
++ if (errFlag)
++ err("usb_submit_isoc(%d) ret %d", i, errFlag);
++ }
++
++ uvd->streaming = 1;
++ if (debug > 1)
++ dbg("streaming=1 video_endp=$%02x", uvd->video_endp);
++ return 0;
++}
++
++
++static void konicawc_stop_data(uvd_t *uvd)
++{
++ int i, j;
++ struct konicawc *cam;
++
++ if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
++ return;
++
++ cam = (struct konicawc *)uvd->user_data;
++ cam->last_data_urb = NULL;
++
++ /* Unschedule all of the iso td's */
++ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
++ j = usb_unlink_urb(uvd->sbuf[i].urb);
++ if (j < 0)
++ err("usb_unlink_urb() error %d.", j);
++
++ j = usb_unlink_urb(cam->sts_urb[i]);
++ if (j < 0)
++ err("usb_unlink_urb() error %d.", j);
++ }
++
++ uvd->streaming = 0;
++
++ if (!uvd->remove_pending) {
++ /* Set packet size to 0 */
++ j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
++ if (j < 0) {
++ err("usb_set_interface() error %d.", j);
++ uvd->last_error = j;
++ }
++ }
++}
++
++
++static void konicawc_process_isoc(uvd_t *uvd, usbvideo_frame_t *frame)
++{
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++ int maxline = cam->maxline;
++ int yplanesz = cam->yplanesz;
++
++ assert(frame != NULL);
++
++ if(debug > 5)
++ dbg("maxline = %d yplanesz = %d", maxline, yplanesz);
++
++ if(debug > 3)
++ dbg("Frame state = %d", frame->scanstate);
++
++ if(frame->scanstate == ScanState_Scanning) {
++ int drop = 0;
++ int curframe;
++ int fdrops = 0;
++ if(debug > 3)
++ dbg("Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
++ while(RingQueue_GetLength(&uvd->dp) >= 4) {
++ if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
++ (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
++ (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
++ (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
++ curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
++ if(cam->lastframe != -1) {
++ fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
++ fdrops--;
++ if(fdrops) {
++ info("Dropped %d frames (%d -> %d)", fdrops,
++ cam->lastframe, curframe);
++ }
++ }
++ cam->lastframe = curframe;
++ frame->curline = 0;
++ frame->scanstate = ScanState_Lines;
++ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
++ break;
++ }
++ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
++ drop++;
++ }
++ if(drop)
++ dbg("dropped %d bytes looking for new frame", drop);
++ }
++
++ if(frame->scanstate == ScanState_Scanning)
++ return;
++
++ /* Try to move data from queue into frame buffer
++ * We get data in blocks of 384 bytes made up of:
++ * 256 Y, 64 U, 64 V.
++ * This needs to be written out as a Y plane, a U plane and a V plane.
++ */
++
++ while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
++ /* Y */
++ RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
++ /* U */
++ RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64);
++ /* V */
++ RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64);
++ frame->seqRead_Length += 384;
++ frame->curline++;
++ }
++ /* See if we filled the frame */
++ if (frame->curline == maxline) {
++ if(debug > 5)
++ dbg("got whole frame");
++
++ frame->frameState = FrameState_Done_Hold;
++ frame->curline = 0;
++ uvd->curframe = -1;
++ uvd->stats.frame_num++;
++ }
++}
++
++
++static int konicawc_find_fps(int size, int fps)
++{
++ int i;
++
++ fps *= 3;
++ dbg("konica_find_fps: size = %d fps = %d", size, fps);
++ if(fps <= spd_to_fps[size][0])
++ return 0;
++
++ if(fps >= spd_to_fps[size][MAX_SPEED])
++ return MAX_SPEED;
++
++ for(i = 0; i < MAX_SPEED; i++) {
++ if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
++ dbg("fps %d between %d and %d", fps, i, i+1);
++ if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
++ return i;
++ else
++ return i+1;
++ }
++ }
++ return MAX_SPEED+1;
++}
++
++
++static int konicawc_set_video_mode(uvd_t *uvd, int x, int y, int fps)
++{
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++ int newspeed = cam->speed;
++ int newsize;
++
++ if(x > 0 && y > 0) {
++ if(debug >= 2)
++ dbg("trying to find size %d,%d", x, y);
++ for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
++ if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
++ break;
++ }
++ } else {
++ newsize = cam->size;
++ }
++
++ if(newsize > MAX_FRAME_SIZE) {
++ dbg("couldnt find size %d,%d", x, y);
++ return -EINVAL;
++ }
++
++ if(fps > 0) {
++ dbg("trying to set fps to %d", fps);
++ newspeed = konicawc_find_fps(newsize, fps);
++ dbg("find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
++ }
++
++ if(newspeed > MAX_SPEED)
++ return -EINVAL;
++
++ dbg("setting size to %d speed to %d", newsize, newspeed);
++ if((newsize == cam->size) && (newspeed == cam->speed)) {
++ dbg("Nothing to do");
++ return 0;
++ }
++ info("setting to %dx%d @ %d fps", camera_sizes[newsize].width,
++ camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
++
++ konicawc_stop_data(uvd);
++ konicawc_set_misc(uvd, 0x2, 0, 0x0b);
++ uvd->ifaceAltActive = spd_to_iface[newspeed];
++ dbg("new interface = %d", uvd->ifaceAltActive);
++ cam->speed = newspeed;
++
++ if(cam->size != newsize) {
++ cam->size = newsize;
++ konicawc_set_camera_size(uvd);
++ }
++
++ /* Flush the input queue and clear any current frame in progress */
++
++ RingQueue_Flush(&uvd->dp);
++ cam->skip_frame = 2;
++ cam->lastframe = -1;
++ if(uvd->curframe != -1) {
++ uvd->frame[uvd->curframe].curline = 0;
++ uvd->frame[uvd->curframe].seqRead_Length = 0;
++ uvd->frame[uvd->curframe].seqRead_Index = 0;
++ }
++
++ konicawc_set_misc(uvd, 0x2, 1, 0x0b);
++ konicawc_start_data(uvd);
++ return 0;
++}
++
++
++static int konicawc_calculate_fps(uvd_t *uvd)
++{
++ struct konicawc *cam = uvd->user_data;
++ return spd_to_fps[cam->size][cam->speed]/3;
++}
++
++
++static void konicawc_configure_video(uvd_t *uvd)
++{
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++ u8 buf[2];
++
++ memset(&uvd->vpic, 0, sizeof(uvd->vpic));
++ memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
++
++ RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS);
++ RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST);
++ RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION);
++ RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS);
++ RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL);
++
++ cam->brightness = brightness / 11;
++ cam->contrast = contrast / 11;
++ cam->saturation = saturation / 11;
++ cam->sharpness = sharpness / 11;
++ cam->white_bal = whitebal / 11;
++
++ uvd->vpic.colour = 108;
++ uvd->vpic.hue = 108;
++ uvd->vpic.brightness = brightness;
++ uvd->vpic.contrast = contrast;
++ uvd->vpic.whiteness = whitebal;
++ uvd->vpic.depth = 6;
++ uvd->vpic.palette = VIDEO_PALETTE_YUV420P;
++
++ memset(&uvd->vcap, 0, sizeof(uvd->vcap));
++ strcpy(uvd->vcap.name, "Konica Webcam");
++ uvd->vcap.type = VID_TYPE_CAPTURE;
++ uvd->vcap.channels = 1;
++ uvd->vcap.audios = 0;
++ uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
++ uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
++ uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
++ uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
++
++ memset(&uvd->vchan, 0, sizeof(uvd->vchan));
++ uvd->vchan.flags = 0 ;
++ uvd->vchan.tuners = 0;
++ uvd->vchan.channel = 0;
++ uvd->vchan.type = VIDEO_TYPE_CAMERA;
++ strcpy(uvd->vchan.name, "Camera");
++
++ /* Talk to device */
++ dbg("device init");
++ if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
++ dbg("3,10 -> %2.2x %2.2x", buf[0], buf[1]);
++ if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
++ dbg("3,10 -> %2.2x %2.2x", buf[0], buf[1]);
++ if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
++ dbg("2,0,d failed");
++ dbg("setting initial values");
++}
++
++
++static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
++{
++ uvd_t *uvd = NULL;
++ int i, nas;
++ int actInterface=-1, inactInterface=-1, maxPS=0;
++ unsigned char video_ep = 0;
++
++ if (debug >= 1)
++ dbg("konicawc_probe(%p,%u.)", dev, ifnum);
++
++ /* We don't handle multi-config cameras */
++ if (dev->descriptor.bNumConfigurations != 1)
++ return NULL;
++
++ info("Konica Webcam (rev. 0x%04x)", dev->descriptor.bcdDevice);
++ RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
++
++ /* Validate found interface: must have one ISO endpoint */
++ nas = dev->actconfig->interface[ifnum].num_altsetting;
++ if (nas != 8) {
++ err("Incorrect number of alternate settings (%d) for this camera!", nas);
++ return NULL;
++ }
++ /* Validate all alternate settings */
++ for (i=0; i < nas; i++) {
++ const struct usb_interface_descriptor *interface;
++ const struct usb_endpoint_descriptor *endpoint;
++
++ interface = &dev->actconfig->interface[ifnum].altsetting[i];
++ if (interface->bNumEndpoints != 2) {
++ err("Interface %d. has %u. endpoints!",
++ ifnum, (unsigned)(interface->bNumEndpoints));
++ return NULL;
++ }
++ endpoint = &interface->endpoint[1];
++ dbg("found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
++ endpoint->bEndpointAddress, endpoint->wMaxPacketSize);
++ if (video_ep == 0)
++ video_ep = endpoint->bEndpointAddress;
++ else if (video_ep != endpoint->bEndpointAddress) {
++ err("Alternate settings have different endpoint addresses!");
++ return NULL;
++ }
++ if ((endpoint->bmAttributes & 0x03) != 0x01) {
++ err("Interface %d. has non-ISO endpoint!", ifnum);
++ return NULL;
++ }
++ if ((endpoint->bEndpointAddress & 0x80) == 0) {
++ err("Interface %d. has ISO OUT endpoint!", ifnum);
++ return NULL;
++ }
++ if (endpoint->wMaxPacketSize == 0) {
++ if (inactInterface < 0)
++ inactInterface = i;
++ else {
++ err("More than one inactive alt. setting!");
++ return NULL;
++ }
++ } else {
++ if (i == spd_to_iface[speed]) {
++ /* This one is the requested one */
++ actInterface = i;
++ }
++ }
++ if(endpoint->wMaxPacketSize > maxPS)
++ maxPS = endpoint->wMaxPacketSize;
++ }
++ if(actInterface == -1) {
++ err("Cant find required endpoint");
++ return NULL;
++ }
++
++ dbg("Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
++
++ /* Code below may sleep, need to lock module while we are here */
++ MOD_INC_USE_COUNT;
++ uvd = usbvideo_AllocateDevice(cams);
++ if (uvd != NULL) {
++ struct konicawc *cam = (struct konicawc *)(uvd->user_data);
++ /* Here uvd is a fully allocated uvd_t object */
++ for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
++ cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC);
++ if(cam->sts_urb[i] == NULL) {
++ while(i--) {
++ usb_free_urb(cam->sts_urb[i]);
++ }
++ err("cant allocate urbs");
++ return NULL;
++ }
++ }
++ cam->speed = speed;
++ RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
++ cam->width = camera_sizes[size].width;
++ cam->height = camera_sizes[size].height;
++ cam->size = size;
++
++ uvd->flags = 0;
++ uvd->debug = debug;
++ uvd->dev = dev;
++ uvd->iface = ifnum;
++ uvd->ifaceAltInactive = inactInterface;
++ uvd->ifaceAltActive = actInterface;
++ uvd->video_endp = video_ep;
++ uvd->iso_packet_len = maxPS;
++ uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
++ uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
++ uvd->canvas = VIDEOSIZE(320, 240);
++ uvd->videosize = VIDEOSIZE(cam->width, cam->height);
++
++ /* Initialize konicawc specific data */
++ konicawc_configure_video(uvd);
++
++ i = usbvideo_RegisterVideoDevice(uvd);
++ uvd->max_frame_size = (320 * 240 * 3)/2;
++ if (i != 0) {
++ err("usbvideo_RegisterVideoDevice() failed.");
++ uvd = NULL;
++ }
++ }
++ MOD_DEC_USE_COUNT;
++ return uvd;
++}
++
++
++static void konicawc_free_uvd(uvd_t *uvd)
++{
++ int i;
++ struct konicawc *cam = (struct konicawc *)uvd->user_data;
++
++ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
++ usb_free_urb(cam->sts_urb[i]);
++ cam->sts_urb[i] = NULL;
++ }
++}
++
++
++static struct usb_device_id id_table[] = {
++ { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
++ { } /* Terminating entry */
++};
++
++
++static int __init konicawc_init(void)
++{
++ usbvideo_cb_t cbTbl;
++ info(DRIVER_DESC " " DRIVER_VERSION);
++ memset(&cbTbl, 0, sizeof(cbTbl));
++ cbTbl.probe = konicawc_probe;
++ cbTbl.setupOnOpen = konicawc_setup_on_open;
++ cbTbl.processData = konicawc_process_isoc;
++ cbTbl.getFPS = konicawc_calculate_fps;
++ cbTbl.setVideoMode = konicawc_set_video_mode;
++ cbTbl.startDataPump = konicawc_start_data;
++ cbTbl.stopDataPump = konicawc_stop_data;
++ cbTbl.adjustPicture = konicawc_adjust_picture;
++ cbTbl.userFree = konicawc_free_uvd;
++ return usbvideo_register(
++ &cams,
++ MAX_CAMERAS,
++ sizeof(struct konicawc),
++ "konicawc",
++ &cbTbl,
++ THIS_MODULE,
++ id_table);
++}
++
++
++static void __exit konicawc_cleanup(void)
++{
++ usbvideo_Deregister(&cams);
++}
++
++
++MODULE_DEVICE_TABLE(usb, id_table);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_PARM(speed, "i");
++MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
++MODULE_PARM(size, "i");
++MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
++MODULE_PARM(brightness, "i");
++MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
++MODULE_PARM(contrast, "i");
++MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
++MODULE_PARM(saturation, "i");
++MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
++MODULE_PARM(sharpness, "i");
++MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108");
++MODULE_PARM(whitebal, "i");
++MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
++MODULE_PARM(debug, "i");
++MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
++module_init(konicawc_init);
++module_exit(konicawc_cleanup);
+diff -urN -X /home/spse/dontdiff linux-2.4.19-pre8/drivers/usb/ultracam.c linux-2.4.19-pre8-konicawc/drivers/usb/ultracam.c
+--- linux-2.4.19-pre8/drivers/usb/ultracam.c Wed Oct 17 22:34:06 2001
++++ linux-2.4.19-pre8-konicawc/drivers/usb/ultracam.c Sat May 11 01:34:30 2002
+@@ -659,6 +659,12 @@
+ return uvd;
+ }
+
++
++static struct usb_device_id id_table[] = {
++ { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
++ { } /* Terminating entry */
++};
++
+ /*
+ * ultracam_init()
+ *
+@@ -682,7 +688,8 @@
+ sizeof(ultracam_t),
+ "ultracam",
+ &cbTbl,
+- THIS_MODULE);
++ THIS_MODULE,
++ id_table);
+ }
+
+ static void __exit ultracam_cleanup(void)
+@@ -690,16 +697,7 @@
+ usbvideo_Deregister(&cams);
+ }
+
+-#if defined(usb_device_id_ver)
+-
+-static __devinitdata struct usb_device_id id_table[] = {
+- { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
+- { } /* Terminating entry */
+-};
+ MODULE_DEVICE_TABLE(usb, id_table);
+-
+-
+-#endif /* defined(usb_device_id_ver) */
+ MODULE_LICENSE("GPL");
+
+ module_init(ultracam_init);
+diff -urN -X /home/spse/dontdiff linux-2.4.19-pre8/drivers/usb/usbvideo.c linux-2.4.19-pre8-konicawc/drivers/usb/usbvideo.c
+--- linux-2.4.19-pre8/drivers/usb/usbvideo.c Thu Oct 11 07:42:46 2001
++++ linux-2.4.19-pre8-konicawc/drivers/usb/usbvideo.c Sat May 11 03:11:30 2002
+@@ -159,9 +159,21 @@
+
+ void RingQueue_Allocate(RingQueue_t *rq, int rqLen)
+ {
++ /* Make sure the requested size is a power of 2 and
++ round up if necessary. This allows index wrapping
++ using masks rather than modulo */
++
++ int i = 1;
+ assert(rq != NULL);
+ assert(rqLen > 0);
++
++ while(rqLen >> i)
++ i++;
++ if(rqLen != 1 << (i-1))
++ rqLen = 1 << i;
++
+ rq->length = rqLen;
++ rq->ri = rq->wi = 0;
+ rq->queue = usbvideo_rvmalloc(rq->length);
+ assert(rq->queue != NULL);
+ }
+@@ -185,12 +197,33 @@
+
+ int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len)
+ {
+- int i;
++ int rql, toread;
++
+ assert(rq != NULL);
+ assert(dst != NULL);
+- for (i=0; i < len; i++) {
+- dst[i] = rq->queue[rq->ri];
+- RING_QUEUE_DEQUEUE_BYTES(rq,1);
++
++
++ rql = RingQueue_GetLength(rq);
++ if(!rql)
++ return 0;
++
++ /* Clip requested length to available data */
++ if(len > rql)
++ len = rql;
++
++ toread = len;
++ if(rq->ri > rq->wi) {
++ /* Read data from tail */
++ int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
++ memcpy(dst, rq->queue + rq->ri, read);
++ toread -= read;
++ dst += read;
++ rq->ri = (rq->ri + read) & (rq->length-1);
++ }
++ if(toread) {
++ /* Read data from head */
++ memcpy(dst, rq->queue + rq->ri, toread);
++ rq->ri = (rq->ri + toread) & (rq->length-1);
+ }
+ return len;
+ }
+@@ -216,7 +249,7 @@
+ if (m > q_avail)
+ m = q_avail;
+
+- memmove(rq->queue + rq->wi, cdata, m);
++ memcpy(rq->queue + rq->wi, cdata, m);
+ RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
+ cdata += m;
+ enqueued += m;
+@@ -225,22 +258,6 @@
+ return enqueued;
+ }
+
+-int RingQueue_GetLength(const RingQueue_t *rq)
+-{
+- int ri, wi;
+-
+- assert(rq != NULL);
+-
+- ri = rq->ri;
+- wi = rq->wi;
+- if (ri == wi)
+- return 0;
+- else if (ri < wi)
+- return wi - ri;
+- else
+- return wi + (rq->length - ri);
+-}
+-
+ void RingQueue_InterruptibleSleepOn(RingQueue_t *rq)
+ {
+ assert(rq != NULL);
+@@ -254,6 +271,14 @@
+ wake_up_interruptible(&rq->wqh);
+ }
+
++void RingQueue_Flush(RingQueue_t *rq)
++{
++ assert(rq != NULL);
++ rq->ri = 0;
++ rq->wi = 0;
++}
++
++
+ /*
+ * usbvideo_VideosizeToString()
+ *
+@@ -390,7 +415,7 @@
+ q_used = RingQueue_GetLength(&uvd->dp);
+ if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
+ u_hi = uvd->dp.length;
+- u_lo = (q_used + uvd->dp.ri) % uvd->dp.length;
++ u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
+ } else {
+ u_hi = (q_used + uvd->dp.ri);
+ u_lo = -1;
+@@ -757,7 +782,8 @@
+ const int num_extra,
+ const char *driverName,
+ const usbvideo_cb_t *cbTbl,
+- struct module *md )
++ struct module *md,
++ const struct usb_device_id *id_table)
+ {
+ static const char proc[] = "usbvideo_register";
+ usbvideo_t *cams;
+@@ -791,6 +817,10 @@
+ cams->cb.getFrame = usbvideo_GetFrame;
+ if (cams->cb.disconnect == NULL)
+ cams->cb.disconnect = usbvideo_Disconnect;
++ if (cams->cb.startDataPump == NULL)
++ cams->cb.startDataPump = usbvideo_StartDataPump;
++ if (cams->cb.stopDataPump == NULL)
++ cams->cb.stopDataPump = usbvideo_StopDataPump;
+ #if USES_PROC_FS
+ /*
+ * If both /proc fs callbacks are NULL then we assume that the driver
+@@ -843,6 +873,7 @@
+ cams->usbdrv.name = cams->drvName;
+ cams->usbdrv.probe = cams->cb.probe;
+ cams->usbdrv.disconnect = cams->cb.disconnect;
++ cams->usbdrv.id_table = id_table;
+
+ #if USES_PROC_FS
+ if (cams->uses_procfs) {
+@@ -963,7 +994,7 @@
+ uvd->remove_pending = 1; /* Now all ISO data will be ignored */
+
+ /* At this time we ask to cancel outstanding URBs */
+- usbvideo_StopDataPump(uvd);
++ GET_CALLBACK(uvd, stopDataPump)(uvd);
+
+ for (i=0; i < USBVIDEO_NUMSBUF; i++)
+ usb_free_urb(uvd->sbuf[i].urb);
+@@ -1192,8 +1223,7 @@
+
+ if (!CAMERA_IS_OPERATIONAL(uvd))
+ return -EFAULT;
+-
+- if (size > (((2 * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
++ if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+ return -EINVAL;
+
+ pos = (unsigned long) uvd->fbuf;
+@@ -1254,7 +1284,7 @@
+ /* Allocate memory for the frame buffers */
+ uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
+ uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
+- RingQueue_Allocate(&uvd->dp, 128*1024); /* FIXME #define */
++ RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
+ if ((uvd->fbuf == NULL) ||
+ (!RingQueue_IsAllocated(&uvd->dp))) {
+ err("%s: Failed to allocate fbuf or dp", proc);
+@@ -1299,7 +1329,7 @@
+ if (errCode == 0) {
+ /* Start data pump if we have valid endpoint */
+ if (uvd->video_endp != 0)
+- errCode = usbvideo_StartDataPump(uvd);
++ errCode = GET_CALLBACK(uvd, startDataPump)(uvd);
+ if (errCode == 0) {
+ if (VALID_CALLBACK(uvd, setupOnOpen)) {
+ if (uvd->debug > 1)
+@@ -1350,7 +1380,7 @@
+ info("%s($%p)", proc, dev);
+
+ down(&uvd->lock);
+- usbvideo_StopDataPump(uvd);
++ GET_CALLBACK(uvd, stopDataPump)(uvd);
+ usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
+ uvd->fbuf = NULL;
+ RingQueue_Free(&uvd->dp);
+@@ -1458,8 +1488,8 @@
+
+ vw.x = 0;
+ vw.y = 0;
+- vw.width = VIDEOSIZE_X(uvd->canvas);
+- vw.height = VIDEOSIZE_Y(uvd->canvas);
++ vw.width = VIDEOSIZE_X(uvd->videosize);
++ vw.height = VIDEOSIZE_Y(uvd->videosize);
+ vw.chromakey = 0;
+ if (VALID_CALLBACK(uvd, getFPS))
+ vw.flags = GET_CALLBACK(uvd, getFPS)(uvd);
+@@ -1529,8 +1559,8 @@
+ }
+ return -EINVAL;
+ }
+- if ((vm.frame != 0) && (vm.frame != 1)) {
+- err("VIDIOCMCAPTURE: vm.frame=%d. !E [0,1]", vm.frame);
++ if ((vm.frame < 0) && (vm.frame >= USBVIDEO_NUMFRAMES)) {
++ err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm.frame, USBVIDEO_NUMFRAMES-1);
+ return -EINVAL;
+ }
+ if (uvd->frame[vm.frame].frameState == FrameState_Grabbing) {
+@@ -1629,7 +1659,7 @@
+ {
+ static const char proc[] = "usbvideo_v4l_read";
+ uvd_t *uvd = (uvd_t *) dev;
+- int frmx = -1;
++ int frmx = -1, i;
+ usbvideo_frame_t *frame;
+
+ if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))
+@@ -1641,14 +1671,13 @@
+ down(&uvd->lock);
+
+ /* See if a frame is completed, then use it. */
+- if ((uvd->frame[0].frameState == FrameState_Done) ||
+- (uvd->frame[0].frameState == FrameState_Done_Hold) ||
+- (uvd->frame[0].frameState == FrameState_Error)) {
+- frmx = 0;
+- } else if ((uvd->frame[1].frameState >= FrameState_Done) ||
+- (uvd->frame[1].frameState == FrameState_Done_Hold) ||
+- (uvd->frame[1].frameState >= FrameState_Done)) {
+- frmx = 1;
++ for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
++ if ((uvd->frame[i].frameState == FrameState_Done) ||
++ (uvd->frame[i].frameState == FrameState_Done_Hold) ||
++ (uvd->frame[i].frameState == FrameState_Error)) {
++ frmx = i;
++ break;
++ }
+ }
+
+ /* FIXME: If we don't start a frame here then who ever does? */
+@@ -1663,10 +1692,12 @@
+ * We will need to wait until it becomes cooked, of course.
+ */
+ if (frmx == -1) {
+- if (uvd->frame[0].frameState == FrameState_Grabbing)
+- frmx = 0;
+- else if (uvd->frame[1].frameState == FrameState_Grabbing)
+- frmx = 1;
++ for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
++ if (uvd->frame[i].frameState == FrameState_Grabbing) {
++ frmx = i;
++ break;
++ }
++ }
+ }
+
+ /*
+@@ -1764,7 +1795,7 @@
+
+ /* Mark it as available to be used again. */
+ uvd->frame[frmx].frameState = FrameState_Unused;
+- if (usbvideo_NewFrame(uvd, frmx ? 0 : 1)) {
++ if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
+ err("%s: usbvideo_NewFrame failed.", proc);
+ }
+ }
+@@ -2001,7 +2032,7 @@
+ uvd->settingsAdjusted = 1;
+ }
+
+- n = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
++ n = (framenum + 1) % USBVIDEO_NUMFRAMES;
+ if (uvd->frame[n].frameState == FrameState_Ready)
+ framenum = n;
+
+@@ -2033,7 +2064,8 @@
+ */
+ if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) {
+ /* This copies previous frame into this one to mask losses */
+- memmove(frame->data, uvd->frame[1-framenum].data, uvd->max_frame_size);
++ int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
++ memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size);
+ } else {
+ if (uvd->flags & FLAGS_CLEAN_FRAMES) {
+ /* This provides a "clean" frame but slows things down */
+diff -urN -X /home/spse/dontdiff linux-2.4.19-pre8/drivers/usb/usbvideo.h linux-2.4.19-pre8-konicawc/drivers/usb/usbvideo.h
+--- linux-2.4.19-pre8/drivers/usb/usbvideo.h Thu Oct 11 07:42:46 2001
++++ linux-2.4.19-pre8-konicawc/drivers/usb/usbvideo.h Sat May 11 01:58:58 2002
+@@ -113,9 +113,10 @@
+ mr = LIMIT_RGB(mm_r); \
+ }
+
+-#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) % (rq)->length
++#define RING_QUEUE_SIZE (128*1024) /* Must be a power of 2 */
++#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
+ #define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
+-#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) % (rq)->length])
++#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
+
+ typedef struct {
+ unsigned char *queue; /* Data from the Isoc data pump */
+@@ -269,6 +270,9 @@
+ int (*getFrame)(uvd_t *, int);
+ int (*procfs_read)(char *page,char **start,off_t off,int count,int *eof,void *data);
+ int (*procfs_write)(struct file *file,const char *buffer,unsigned long count,void *data);
++ int (*startDataPump)(uvd_t *uvd);
++ void (*stopDataPump)(uvd_t *uvd);
++ int (*setVideoMode)(uvd_t *, int, int, int);
+ } usbvideo_cb_t;
+
+ struct s_usbvideo_t {
+@@ -302,15 +306,20 @@
+ #define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \
+ ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL)
+
+-void RingQueue_Initialize(RingQueue_t *rq);
+-void RingQueue_Allocate(RingQueue_t *rq, int rqLen);
+-int RingQueue_IsAllocated(const RingQueue_t *rq);
+-void RingQueue_Free(RingQueue_t *rq);
+ int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len);
+ int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n);
+-int RingQueue_GetLength(const RingQueue_t *rq);
+-void RingQueue_InterruptibleSleepOn(RingQueue_t *rq);
+ void RingQueue_WakeUpInterruptible(RingQueue_t *rq);
++void RingQueue_Flush(RingQueue_t *rq);
++
++static inline int RingQueue_GetLength(const RingQueue_t *rq)
++{
++ return (rq->wi - rq->ri + rq->length) & (rq->length-1);
++}
++
++static inline int RingQueue_GetFreeSpace(const RingQueue_t *rq)
++{
++ return rq->length - RingQueue_GetLength(rq);
++}
+
+ void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame);
+ void usbvideo_DrawLine(
+@@ -339,7 +348,8 @@
+ const int num_extra,
+ const char *driverName,
+ const usbvideo_cb_t *cbTable,
+- struct module *md);
++ struct module *md,
++ const struct usb_device_id *id_table);
+ uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams);
+ int usbvideo_RegisterVideoDevice(uvd_t *uvd);
+ void usbvideo_Deregister(usbvideo_t **uvt);