konicawc.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 803 行 · 第 1/2 页
C
803 行
/* * $Id$ * * 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>#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.1"#define DRIVER_DESC "Konica Webcam driver"enum ctrl_req { SetWhitebal = 0x01, SetBrightness = 0x02, SetSharpness = 0x03, SetContrast = 0x04, SetSaturation = 0x05,};enum frame_sizes { SIZE_160X136 = 0, SIZE_176X144 = 1, SIZE_320X240 = 2,};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 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 */ 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 speed_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;};#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 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); dbg("setting size %d", cam->size); switch(cam->size) { case 0: konicawc_set_misc(uvd, 0x2, 0xa, 0x08); break; case 1: konicawc_set_misc(uvd, 0x2, 4, 0x08); break; case 2: konicawc_set_misc(uvd, 0x2, 5, 0x08); break; } konicawc_set_misc(uvd, 0x2, 1, 0x0b); cam->lastframe = -1; return 0;}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; int i, totlen = 0; 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; 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:drop packet (padding data) * 1 keep packet * * 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 != buttonsts) { dbg("button: %sclicked", button ? "" : "un"); buttonsts = button; } if(sts == 0x01) { /* drop frame */ discard++; continue; } if((sts > 0x01) && (sts < 0x80)) { info("unknown status %2.2x", sts); bad++; continue; } keep++; if(*(status+i) & 0x80) { /* frame start */ unsigned char marker[] = { 0, 0xff, 0, 0x00 }; if(debug > 1) dbg("Adding Marker packet = %d, frame = %2.2x", i, *(status+i)); marker[3] = *(status+i) - 0x80; RingQueue_Enqueue(&uvd->dp, marker, 4); totlen += 4; } totlen += n; /* Little local accounting */ if(debug > 5) dbg("Adding packet %d, bytes = %d", i, n); 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->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; if (len <= 0) { goto urb_done_with; } /* Here we got some data */ uvd->stats.data_count += len; 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; 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 = uvd->iso_packet_len * FRAMES_PER_DESC; for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) { urb->iso_frame_desc[j].offset = k; urb->iso_frame_desc[j].length = uvd->iso_packet_len; } 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, GFP_KERNEL); if (errFlag) err ("usb_submit_isoc(%d) ret %d", i, errFlag); errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL); 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;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?