# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.575 -> 1.576 # drivers/usb/konicawc.c 1.2 -> 1.3 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/04/01 spse@secret.org.uk 1.576 # [PATCH] Update to konicawc driver # # This patch against 2.5.7 fixes an oops and a memleak in the konicawc driver # and also adds an option to set the FPS. # -------------------------------------------- # diff -Nru a/drivers/usb/konicawc.c b/drivers/usb/konicawc.c --- a/drivers/usb/konicawc.c Wed Apr 3 16:39:12 2002 +++ b/drivers/usb/konicawc.c Wed Apr 3 16:39:12 2002 @@ -1,5 +1,5 @@ /* - * $Id: konicawc.c,v 1.12 2002/02/07 23:18:53 spse Exp $ + * $Id$ * * konicawc.c - konica webcam driver * @@ -18,17 +18,18 @@ #include #include -#define DEBUG - #include "usbvideo.h" #define MAX_BRIGHTNESS 108 #define MAX_CONTRAST 108 #define MAX_SATURATION 108 #define MAX_SHARPNESS 108 -#define MAX_WHITEBAL 363 +#define MAX_WHITEBAL 372 +#define MAX_SPEED 6 +#define MAX_CAMERAS 1 -#define MAX_CAMERAS 1 +#define DRIVER_VERSION "v1.1" +#define DRIVER_DESC "Konica Webcam driver" enum ctrl_req { SetWhitebal = 0x01, @@ -40,7 +41,7 @@ enum frame_sizes { - SIZE_160X130 = 0, + SIZE_160X136 = 0, SIZE_176X144 = 1, SIZE_320X240 = 2, }; @@ -53,12 +54,30 @@ 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 speed_to_interface[] = { 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 speed_to_fps[3][7] = { { 24, 40, 48, 60, 72, 80, 100 }, + { 18, 30, 36, 45, 54, 60, 75 }, + { 6, 10, 12, 15, 18, 20, 25 } }; + + +static int camera_sizes[][2] = { { 160, 136 }, + { 176, 144 }, + { 320, 240 }, + { } /* List terminator */ +}; struct konicawc { u8 brightness; /* camera uses 0 - 9, x11 for real value */ @@ -66,12 +85,12 @@ u8 saturation; /* as above */ u8 sharpness; /* as above */ u8 white_bal; /* 0 - 33, x11 for real value */ - u8 fps; /* Stored as fps * 3 */ + u8 speed; /* Stored as 0 - 6, used as index in speed_to_* (above) */ u8 size; /* Frame Size */ int height; int width; - struct urb *sts_urb[USBVIDEO_NUMFRAMES]; - u8 sts_buf[USBVIDEO_NUMFRAMES][FRAMES_PER_DESC]; + struct urb *sts_urb[USBVIDEO_NUMSBUF]; + u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC]; struct urb *last_data_urb; int lastframe; }; @@ -97,19 +116,19 @@ konicawc_set_misc(uvd, 0x2, 0, 0x0b); dbg("setting brightness to %d (%d)", cam->brightness, - cam->brightness*11); + cam->brightness * 11); konicawc_set_value(uvd, cam->brightness, SetBrightness); dbg("setting white balance to %d (%d)", cam->white_bal, - cam->white_bal*11); + 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->brightness, SetBrightness); + cam->contrast * 11); + konicawc_set_value(uvd, cam->contrast, SetContrast); dbg("setting saturation to %d (%d)", cam->saturation, - cam->saturation*11); + cam->saturation * 11); konicawc_set_value(uvd, cam->saturation, SetSaturation); dbg("setting sharpness to %d (%d)", cam->sharpness, - cam->sharpness*11); + cam->sharpness * 11); konicawc_set_value(uvd, cam->sharpness, SetSharpness); dbg("setting size %d", cam->size); switch(cam->size) { @@ -131,6 +150,30 @@ } +static void konicawc_adjust_picture(uvd_t *uvd) +{ + struct konicawc *cam = (struct konicawc *)uvd->user_data; + + 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); + } +} + + static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *stsurb) { char *cdata; @@ -138,7 +181,7 @@ unsigned char *status = stsurb->transfer_buffer; int keep = 0, discard = 0, bad = 0; static int buttonsts = 0; - + for (i = 0; i < dataurb->number_of_packets; i++) { int button = buttonsts; unsigned char sts; @@ -228,7 +271,7 @@ 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; @@ -236,7 +279,6 @@ if (urb->actual_length > 32) { cam->last_data_urb = urb; return; - } if (!uvd->streaming) { @@ -244,7 +286,7 @@ info("Not streaming, but interrupt!"); return; } - + uvd->stats.urb_count++; if (urb->actual_length <= 0) goto urb_done_with; @@ -329,7 +371,8 @@ } } - + 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) { @@ -362,11 +405,14 @@ static void konicawc_stop_data(uvd_t *uvd) { int i, j; - struct konicawc *cam = (struct konicawc *)uvd->user_data; + 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); @@ -476,9 +522,9 @@ static int konicawc_calculate_fps(uvd_t *uvd) { struct konicawc *t = uvd->user_data; - dbg(""); + dbg("fps = %d", speed_to_fps[t->size][t->speed]/3); - return (t->fps)/3; + return speed_to_fps[t->size][t->speed]/3; } @@ -515,10 +561,10 @@ uvd->vcap.type = VID_TYPE_CAPTURE; uvd->vcap.channels = 1; uvd->vcap.audios = 0; - uvd->vcap.maxwidth = cam->width; - uvd->vcap.maxheight = cam->height; - uvd->vcap.minwidth = cam->width; - uvd->vcap.minheight = cam->height; + uvd->vcap.minwidth = camera_sizes[cam->size][0]; + uvd->vcap.minheight = camera_sizes[cam->size][1]; + uvd->vcap.maxwidth = camera_sizes[cam->size][0]; + uvd->vcap.maxheight = camera_sizes[cam->size][1]; memset(&uvd->vchan, 0, sizeof(uvd->vchan)); uvd->vchan.flags = 0 ; @@ -540,7 +586,7 @@ } -static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum ,const struct usb_device_id *devid) +static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid) { uvd_t *uvd = NULL; int i, nas; @@ -555,6 +601,7 @@ 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; @@ -600,56 +647,58 @@ return NULL; } } else { - if (actInterface < 0) { + if (i == speed_to_interface[speed]) { + /* This one is the requested one */ actInterface = i; maxPS = endpoint->wMaxPacketSize; - if (debug > 0) - info("Active setting=%d. maxPS=%d.", + if (debug > 0) { + info("Selecting requested active setting=%d. maxPS=%d.", i, maxPS); - } else { - /* Got another active alt. setting */ - if (maxPS < endpoint->wMaxPacketSize) { - /* This one is better! */ - actInterface = i; - maxPS = endpoint->wMaxPacketSize; - if (debug > 0) { - info("Even better active setting=%d. maxPS=%d.", - i, maxPS); - } } } } } + if(actInterface == -1) { + err("Cant find required endpoint"); + return NULL; + } + /* 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 *konicawc_data = (struct konicawc *)(uvd->user_data); + struct konicawc *cam = (struct konicawc *)(uvd->user_data); /* Here uvd is a fully allocated uvd_t object */ - for(i = 0; i < USBVIDEO_NUMSBUF; i++) { - konicawc_data->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); + cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); + if(cam->sts_urb[i] == NULL) { + while(i--) { + usb_free_urb(cam->sts_urb[i]); + } + err("cant allocate urbs"); + return NULL; + } } - + cam->speed = speed; switch(size) { - case SIZE_160X130: + case SIZE_160X136: default: - konicawc_data->height = 136; - konicawc_data->width = 160; - konicawc_data->size = SIZE_160X130; + cam->height = 136; + cam->width = 160; + cam->size = SIZE_160X136; break; case SIZE_176X144: - konicawc_data->height = 144; - konicawc_data->width = 176; - konicawc_data->size = SIZE_176X144; + cam->height = 144; + cam->width = 176; + cam->size = SIZE_176X144; break; case SIZE_320X240: - konicawc_data->height = 240; - konicawc_data->width = 320; - konicawc_data->size = SIZE_320X240; + cam->height = 240; + cam->width = 320; + cam->size = SIZE_320X240; break; } @@ -663,14 +712,14 @@ uvd->iso_packet_len = maxPS; uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P; uvd->defaultPalette = VIDEO_PALETTE_YUV420P; - uvd->canvas = VIDEOSIZE(konicawc_data->width, konicawc_data->height); + uvd->canvas = VIDEOSIZE(cam->width, cam->height); uvd->videosize = uvd->canvas; /* Initialize konicawc specific data */ konicawc_configure_video(uvd); i = usbvideo_RegisterVideoDevice(uvd); - uvd->max_frame_size = (konicawc_data->width * konicawc_data->height * 3)/2; + uvd->max_frame_size = (cam->width * cam->height * 3)/2; if (i != 0) { err("usbvideo_RegisterVideoDevice() failed."); uvd = NULL; @@ -681,9 +730,28 @@ } +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; @@ -691,6 +759,8 @@ cbTbl.getFPS = konicawc_calculate_fps; 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, @@ -706,19 +776,14 @@ usbvideo_Deregister(&cams); } -#if defined(usb_device_id_ver) - -static __devinitdata struct usb_device_id id_table[] = { - { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */ - { } /* Terminating entry */ -}; MODULE_DEVICE_TABLE(usb, id_table); -#endif /* defined(usb_device_id_ver) */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Simon Evans "); -MODULE_DESCRIPTION("Konica Webcam driver"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_PARM(speed, "i"); +MODULE_PARM_DESC(speed, "FPS speed: 0 (slowest) - 6 (fastest)"); MODULE_PARM(size, "i"); MODULE_PARM_DESC(size, "Frame Size 0: 160x136 1: 176x144 2: 320x240"); MODULE_PARM(brightness, "i");