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 + -
显示快捷键?