⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qc-driver.c

📁 在Linux下用于webeye的摄像头的驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
{	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_exit()");	if (!qc_proc_entry) return;	remove_proc_entry(qc_proc_name, NULL);	POISON(qc_proc_entry);}/* }}} */#elsestatic inline int qc_proc_create(struct quickcam *qc) { return 0; }static inline void qc_proc_destroy(struct quickcam *qc) { }static inline int qc_proc_init(void) { return 0; }static inline void qc_proc_exit(void) { }#endif /* HAVE_PROCFS *//* }}} *//* {{{ [fold] **** qc_adapt:  Automatic exposure control ************************ */#define MEASURE_ADAPT_DELAY 0		/* Measure adaptation delay, only for test purposes *//* {{{ [fold] qc_adapt_init(struct quickcam *qc) *//* Initialize automatic exposure control structure. */static int qc_adapt_init(struct quickcam *qc){	struct qc_adapt_data *ctrl = &qc->adapt_data;	ctrl->gain         = 32768;	ctrl->olddelta     = 4*256;			/* best guess */	ctrl->exposure     = 32768;	ctrl->oldexposure  = ctrl->exposure + 1;	/* Slightly different for _issettled() */	ctrl->midvaluesum  = ctrl->oldmidvalue = 0;	ctrl->framecounter = 0;	ctrl->controlalg   = EXPCONTROL_SATURATED;	IDEBUG_INIT(*ctrl);	return 0;}/* }}} *//* {{{ [fold] qc_adapt_exit(struct quickcam *qc) */static inline void qc_adapt_exit(struct quickcam *qc){#ifdef DEBUG	struct qc_adapt_data *ctrl = &qc->adapt_data;	if (qcdebug&QC_DEBUGINIT) PDEBUG("qc_adapt_exit(ctrl=%p)",ctrl);	IDEBUG_EXIT(*ctrl);#endif}/* }}} *//* {{{ [fold] qc_adapt_reset(struct quickcam *qc) *//* Must be called each time just before starting video adaptation */static inline void qc_adapt_reset(struct quickcam *qc){	IDEBUG_TEST(qc->adapt_data);	if (!qc->settings.keepsettings) {		IDEBUG_EXIT(qc->adapt_data);		qc_adapt_init(qc);	}}/* }}} *//* {{{ [fold] qc_adapt_hassettled(struct quickcam *qc) *//* Return TRUE if the image brightness has settled */static inline Bool qc_adapt_hassettled(struct quickcam *qc){	struct qc_adapt_data *ctrl = &qc->adapt_data;	IDEBUG_TEST(*ctrl);	if (ctrl->framecounter != 0) return FALSE;//PDEBUG("control=%i  oldexp=%i  exp=%i",ctrl->controlalg,ctrl->oldexposure,ctrl->exposure);	return ctrl->controlalg==EXPCONTROL_FLOAT || ctrl->oldexposure==ctrl->exposure;}/* }}} *//* {{{ [fold] qc_adapt(struct quickcam *qc, int midvalue, int target, int *ret_exposure, int *ret_gain) *//* Set image exposure and gain so that computed midvalue approaches the target value. * midvalue = average pixel intensity on image 0..255 * target   = user settable preferable intensity 0..255 * *ret_exposure = the exposure value to use for the camera, 0..65535 * *ret_gain     = the gain to use for the camera, 0..65535. */static void qc_adapt(struct quickcam *qc, int midvalue, int target, int *ret_exposure, int *ret_gain){#if !MEASURE_ADAPT_DELAY	struct qc_adapt_data *ctrl = &qc->adapt_data;	/* Here are some constant for controlling the adaptation algorithm. You may play with them. */	static const int saturation_min = 32;			/* (0-127) If midvalue is out of this range, image is */	static const int saturation_max = 256 - 8;		/* (128-255) considered saturated and no Newton is used */	static const int adaptation_min = 5;			/* (0-128) For small variations, do not change exposure */	static const int delta_min      = 256/2;		/* (2-16*256) Minimum and maximum value for delta */	static const int delta_max      = 256*256;		/* (4*256-1024*256) */		static const int dmidvalue_min  = 400;			/* (1-128) Minimum differences, under which delta estimation (FIXME:disabled by changing values very big) */	static const int dexposure_min  = 400;			/* (1-32000) will not be done due to inaccuracies */		static const int delta_speed    = 256;			/* (0-256) How fast or slowly delta can change */	static const int small_adapt    = 4;			/* (0-1024) When very near optimal, exposure change size */	static const int underestimate  = 16;			/* (0-250) Underestimation, may prevent oscillation */	static const int bestguess      = 256/2;		/* (2-1024*256) If delta can not be computed, guess this */	static const int midvalueaccum  = 2;			/* (1-100) How many frames to use for midvalue averaging */	static const int framedelay     = 5;			/* (0-8) How many frames there are before a new exposure setting in effect */								/* With QuickCam Web: if set at frame #0, it will be in effect at frame #4; skip 3 frames #1,#2,#3 */								/* -> should be 3 with QuickCam Web, but it oscillates, FIXME:why? Setting to 4 fixes this */	static const int gainstep       = 256;			/* (0-32768) Amount to change gain at one step */	static const int gainneeded     = 10;			/* (0-255) How eagerly to change brightness with gain */	/* End of tunable constants */	int newexposure, delta=0;	int dexposure=0, dmidvalue=0;	int deviation=0;			/* Deviation of actual brightness from target brightness */	int smoothdelta=0;			/* Final, smoothed, value of delta */	TEST_BUG(ctrl==NULL || ret_gain==NULL || ret_exposure==NULL);	IDEBUG_TEST(*ctrl);	if (ctrl->framecounter >= framedelay)		ctrl->midvaluesum += midvalue;	ctrl->framecounter++;	if (ctrl->framecounter < framedelay+midvalueaccum) {		*ret_exposure = ctrl->exposure;		*ret_gain     = ctrl->gain;		return;	}	midvalue = ctrl->midvaluesum / midvalueaccum;	ctrl->framecounter = 0;	ctrl->midvaluesum  = 0;	if (ctrl->exposure >= qc->sensor_data.sensor->adapt_gainhigh && 	    ctrl->oldexposure >= qc->sensor_data.sensor->adapt_gainhigh &&	    target - ctrl->oldmidvalue > gainneeded &&	    target - midvalue > gainneeded)	{		/* Exposure is at maximum, but image is still too dark. Increase gain.*/		ctrl->gain = ctrl->gain + ctrl->gain/2 + gainstep;		if (ctrl->gain > 65535) ctrl->gain = 65535;		if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("increasing gain to %i", ctrl->gain);	} else 	if (ctrl->exposure <= qc->sensor_data.sensor->adapt_gainlow &&	    ctrl->oldexposure <= qc->sensor_data.sensor->adapt_gainlow &&	    target - ctrl->oldmidvalue <= gainneeded &&	    target - midvalue <= gainneeded)	{		/* Decrease gain if unnecessarily high */		ctrl->gain = ctrl->gain - ctrl->gain/2 - gainstep;		if (ctrl->gain < 0) ctrl->gain = 0;		if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("decreasing gain to %i", ctrl->gain);	}		if (ctrl->oldmidvalue<saturation_min || midvalue<saturation_min) {		/* Image was undersaturated, Newton method would give inaccurate results */		if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Increasing exposure");		ctrl->controlalg = EXPCONTROL_SATURATED;		newexposure = ctrl->exposure * 2;	} else	if (ctrl->oldmidvalue>=saturation_max || midvalue>=saturation_max) {		/* Image is oversaturated, Newton method would give inaccurate results */		if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Decreasing exposure");		ctrl->controlalg = EXPCONTROL_SATURATED;		newexposure = ctrl->exposure / 2;	} else {		deviation = target - midvalue;		if (ABS(deviation) < adaptation_min) {			/* For small variations, adapt linearly */			if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Small deviation %i",deviation);			ctrl->controlalg = EXPCONTROL_FLOAT;			newexposure = small_adapt * SGN(deviation) + ctrl->exposure;		} else {			/* Try using Newton method for estimating correct exposure value */			ctrl->controlalg = EXPCONTROL_NEWTON;			dmidvalue = midvalue       - ctrl->oldmidvalue;			dexposure = ctrl->exposure - ctrl->oldexposure;			if (ABS(dmidvalue) <  dmidvalue_min || 			    ABS(dexposure) <  dexposure_min ||			    SGN(dmidvalue) != SGN(dexposure))			{				/* Can not estimate delta with Newton method, just guess */				if (ctrl->olddelta < 2) {					if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Best guessing");					smoothdelta = bestguess;				} else {					Bool cross = SGN(midvalue-target) != SGN(ctrl->oldmidvalue-target);					smoothdelta = cross ? (ctrl->olddelta / 2) : (ctrl->olddelta * 3 / 2);					if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Change more exposure, smoothdelta=%i",smoothdelta);				}			} else {				/* Everything is well, use here actual Newton method */				delta       = (256 - underestimate) * dexposure / dmidvalue;				smoothdelta = (delta_speed*delta + (256-delta_speed)*ctrl->olddelta) / 256;				if (qcdebug&QC_DEBUGADAPTATION) PDEBUG("Using Newton, delta=%i",delta);			}		}		/* Compute new exposure based on guessed/computed delta */		smoothdelta = CLIP(smoothdelta, delta_min,delta_max);		dexposure = deviation * smoothdelta / 256;		/* Newton works linearly, but exposure/brightness are not linearly related */		/* The following test fixes the worst deficiencies due to that (I hope) */		if (-dexposure > ctrl->exposure/2)			dexposure = -ctrl->exposure/2;		newexposure = dexposure + ctrl->exposure;		ctrl->olddelta = smoothdelta;	}	newexposure       = CLIP(newexposure, 2,65535);	if (qcdebug&QC_DEBUGADAPTATION) 		PDEBUG("midval=%i dev=%i dmidv=%i dexp=%i smdelta=%i olddelta=%i newexp=%i gain=%i",		midvalue,deviation,dmidvalue,dexposure,smoothdelta,ctrl->olddelta,newexposure,ctrl->gain);	ctrl->oldexposure = ctrl->exposure;	ctrl->exposure    = newexposure;	ctrl->oldmidvalue = midvalue;	*ret_exposure     = newexposure;	*ret_gain         = ctrl->gain;#else	/* This code is for measuring the delay between an exposure settings and until	 * it becomes in effect. Only useful for developing the adaptation algorithm. */	/* Some delays: when a setting is changed at frame number #0,	 * it becomes in effect in frame xx for	exposure	gain	 * QuickCam Web/0850/normal mode	4		4	 * QuickCam Web/0850/compressed mode	5		5	 * QuickCam Express/840			2		1-5	 *	 */	static int exp = 0;	static int gain = 0;	static const int changedel = 20;	static int state = 0;	static int framenum = 0;	PRINTK(KERN_CRIT,"Measuring: framenum=%i, midvalue=%i",framenum,midvalue);	if ((framenum%changedel)==0) {		switch (state) {		default:		case 0:			PRINTK(KERN_CRIT,"Measuring: set to black");			exp = 0;			gain = 0;			break;		case 1:			PRINTK(KERN_CRIT,"Measuring: changing exposure");			exp = 65535;			break;		case 2:			PRINTK(KERN_CRIT,"Measuring: changing gain");			gain = 32535;			break;		}		state = ((state+1) % 3);	}	*ret_exposure = exp;	*ret_gain = gain;	framenum++;#endif}/* }}} *//* }}} *//* {{{ [fold] **** qc_frame:  Frame capturing functions ************************* *//* From /usr/src/linux/Documentation/smp.tex: * + Kernel mode process (e.g. system calls): *   - No other kernel mode processes may run simultaneously/pre-empt *     (kernel mode processes are atomic with respect to each other) *     (Does not hold for 2.6.x) *   - Exception is voluntary sleeping, in which case re-entry is allowed *     (Does not hold for 2.6.x) *   - Interrupts may pre-empt (but return to same process) *     (interrupts can be disabled if necessary) * + Interrupt mode execution *   - Kernel mode process may not pre-empt/execute simultaneously *   - Other interrupts may pre-empt, however same interrupt is not nested *//* We have here a quite typical producer-consumer scheme: * Interrupt routine produces more frame data, while * kernel mode processes consume it * Read: Linux Device Drivers, Alessandro Rubini et al, 2nd edition, pg. 279 * "Using Circular Buffers" *//* Initialization and cleanup routines, called from kernel mode processes *//* {{{ [fold] qc_frame_init(struct quickcam *qc) */static int qc_frame_init(struct quickcam *qc){	struct qc_frame_data *fd = &qc->frame_data;	int n;	if (qcdebug&QC_DEBUGFRAME || qcdebug&QC_DEBUGINIT) PDEBUG("qc_frame_init(qc=%p)",qc);	TEST_BUGR(qc==NULL || fd==NULL);	TEST_BUGR(in_interrupt());	fd->rawdatabuf = vmalloc(FRAME_DATASIZE * FRAME_BUFFERS);	if (!fd->rawdatabuf) return -ENOMEM;	memset(fd->rawdatabuf, 0, FRAME_DATASIZE * FRAME_BUFFERS);	/* Never let user access random kernel data */	fd->head       = 0;		/* First buffer to fill */	fd->tail       = 0;		/* First buffer to get */	spin_lock_init(&fd->tail_lock);	fd->tail_in_use= FALSE;	init_waitqueue_head(&fd->wq);	fd->waiting    = 0;	fd->exiting    = FALSE;	for (n=0; n<FRAME_BUFFERS; n++) fd->buffers[n].rawdatalen = 0;	fd->lost_frames = 0;	IDEBUG_INIT(*fd);	return 0;}/* }}} *//* {{{ [fold] qc_frame_exit(struct quickcam *qc) *//* This function must be called with qc->lock acquired  * (it may release it temporarily and sleep) */static void qc_frame_exit(struct quickcam *qc){	struct qc_frame_data *fd = &qc->frame_data;#if PARANOID	unsigned long startjiffy = jiffies;#endif	if (qcdebug&QC_DEBUGFRAME || qcdebug&QC_DEBUGINIT) PDEBUG("qc_frame_exit(qc=%p,tail=%i,head=%i)",qc,fd->tail,fd->head);	TEST_BUG(in_interrupt());	TEST_BUG(qc==NULL || fd==NULL);	fd->exiting = TRUE;	fd->maxrawdatalen = 0;		/* Hopefully stops all ongoing captures, might need locking though */	wake_up(&fd->wq);	if (qcdebug&QC_DEBUGFRAME) PDEBUG("waiting=%i",fd->waiting);	if (qcdebug&QC_DEBUGMUTEX) PDEBUG("up(%p) in qc_frame_exit() : %i", qc, sem_getcount(&qc->lock));	up(&qc->lock);			/* The lock was down when entering this function */	while (fd->waiting > 0) {		schedule();#if PARANOID		if (jiffies-startjiffy > 60*HZ) {			PRINTK(KERN_CRIT,"Wait queue never completing!! (waiting=%i)",fd->waiting);			break;		}#endif	}	if (qcdebug&QC_DEBUGMUTEX) PDEBUG("down(%p) in qc_frame_exit() : %i", qc, sem_getcount(&qc->lock));	down(&qc->lock);	vfree(fd->rawdatabuf);	POISON(fd->rawdatabuf);	IDEBUG_EXIT(*fd);}/* }}} *//* Consumer routines, called from kernel mode processes *//* {{{ [fold] qc_frame_get(struct quickcam *qc, unsigned char **buf) *//* Wait until next frame is ready and return the frame length

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -