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

📄 qc-driver.c

📁 Webcam Linux driver for Quickcam
💻 C
📖 第 1 页 / 共 5 页
字号:
	up(&quickcam_list_lock);	len = out - page;	len -= off;	if (len < count) {		*eof = 1;		if (len <= 0) return 0;	} else		len = count;	*start = page + off;	return len;}/* }}} *//* {{{ [fold] qc_proc_write(struct file *file, const char *buffer, unsigned long count, void *data) */static int qc_proc_write(struct file *file, const char *buffer, unsigned long count, void *data){	/* we don't support this....yet? Might replace qcset some day */	return -EINVAL;}/* }}} *//* {{{ [fold] qc_proc_create(struct quickcam *qc) *//* Called for each camera plugged in, create file containing information of the camera */static int qc_proc_create(struct quickcam *qc){	char name[9];	struct proc_dir_entry *entry;	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_create(quickcam=%p)",qc);	TEST_BUGR(!qc);	qc->proc_entry = NULL;	if (qc_proc_quickcam_entry==NULL) return -ENOTDIR;	sprintf(name, "video%d", qc->vdev.minor);	entry = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, qc_proc_quickcam_entry);	if (!entry) {		PRINTK(KERN_WARNING,"Could not register procfs file entry");		return -ENXIO;	}	entry->owner = THIS_MODULE;	entry->data = qc;	entry->read_proc = qc_proc_read;	entry->write_proc = qc_proc_write;	qc->proc_entry = entry;	sprintf(name, "button%d", qc->vdev.minor);	entry = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, qc_proc_quickcam_entry);	if (!entry) {		PRINTK(KERN_WARNING,"Could not register procfs file entry");		return -ENXIO;	}	entry->owner = THIS_MODULE;	entry->data = qc;	entry->read_proc = qc_proc_button_read;	entry->write_proc = qc_proc_write;	qc->proc_entry_button = entry;	return 0;}/* }}} *//* {{{ [fold] qc_proc_destroy(struct quickcam *qc) *//* qc_proc_destroy may be called after qc_proc_create for given quickcam even if it failed */static void qc_proc_destroy(struct quickcam *qc){	char name[9];	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_destroy(quickcam=%p)",qc);	TEST_BUG(!qc);	if (qc->proc_entry) {	  TEST_BUG(!qc_proc_quickcam_entry);	  sprintf(name, "video%d", qc->vdev.minor);	  remove_proc_entry(name, qc_proc_quickcam_entry);	  POISON(qc->proc_entry);	}	if (qc->proc_entry_button) {	  TEST_BUG(!qc_proc_quickcam_entry);	  sprintf(name, "button%d", qc->vdev.minor);	  remove_proc_entry(name, qc_proc_quickcam_entry);	  POISON(qc->proc_entry_button);	}	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_proc_destroy() done");}/* }}} *//* {{{ [fold] qc_proc_init(void) *//* Called when the driver is initially loaded, creates "/proc/video/qcquickcam" subdirectory */static int qc_proc_init(void){	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_init()");	/* Might fail, if the directory already exists, but we don't care */	qc_proc_video_entry = proc_mkdir(qc_proc_video_name, NULL);	if(!qc_proc_video_entry) {		PRINTK(KERN_WARNING,"Could not register procfs dir entry");		return -ENXIO;	}	qc_proc_video_entry->owner = THIS_MODULE;	qc_proc_quickcam_entry = create_proc_entry(qc_proc_quickcam_name, S_IFDIR, qc_proc_video_entry);	if (!qc_proc_quickcam_entry) {		PRINTK(KERN_WARNING,"Could not register procfs dir entry");		return -ENXIO;	}	qc_proc_quickcam_entry->owner = THIS_MODULE;	return 0;}/* }}} *//* {{{ [fold] qc_proc_exit(void) *//* Can be called after qc_proc_init() even if it has failed, in which case this does nothing */static void qc_proc_exit(void){	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_exit()");	if (qc_proc_quickcam_entry) {	  remove_proc_entry(qc_proc_quickcam_name, qc_proc_video_entry);	  POISON(qc_proc_quickcam_entry);	}	if (qc_proc_video_entry) {	  remove_proc_entry(qc_proc_video_name, NULL);	  POISON(qc_proc_video_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->olddelta     = 4*256;			/* best guess */	ctrl->gain         = 32768;	//ctrl->gain         = 5000;#if 0	ctrl->exposure     = 32768;#else	ctrl->exposure     = 20000;  // avoid overexposed at start.#endif	ctrl->oldexposure  = ctrl->exposure + 1;	/* Slightly different for _issettled() */	ctrl->midvaluesum  = ctrl->oldmidvalue = 0;	ctrl->framecounter = 0;	ctrl->controlalg   = EXPCONTROL_SATURATED;	ctrl->shutter      = 32768;	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;}/* }}} */#if 1// This really need some tuning... 300 seem to work good outdoor.//#define MIN_SHUTTER 5000#define MIN_SHUTTER 300#define MAX_SHUTTER 0xC000#define EXTREME_MAX_SHUTTER 0xFFFF#else#define MIN_SHUTTER 2500#define MAX_SHUTTER 15000#define EXTREME_MAX_SHUTTER 50000#endifint max_shutter = MAX_SHUTTER;/* {{{ [fold] qc_adapt_shutter(struct quickcam *qc) */static void qc_adapt_shutter(struct quickcam *qc){  struct qc_adapt_data *ctrl = &qc->adapt_data;  int r;  int newshutter = 0;#if 1  int diff = ctrl->oldmidvalue - 120;#if 1#define INC_VAL 10#define DIFF_VAL_SMALL 10#define DIFF_VAL_BIG 50#else#define INC_VAL 5#define DIFF_VAL_SMALL 5#define DIFF_VAL_BIG 25#endif#else  int diff = -((qc->adapt_data.exposure>>8) - ctrl->oldmidvalue);#define INC_VAL 10#define DIFF_VAL_SMALL 10#define DIFF_VAL_BIG 30#endif  /*    Just a test of adjusting the shutter value. Try to keep picture    intensity (ctrl->oldmidvalue) constant 120.  */#if 1  if(qc->adapt_data.exposure==0xffff &&     qc->adapt_data.gain==0xffff) {    max_shutter *= 2;    if(max_shutter > EXTREME_MAX_SHUTTER) max_shutter = EXTREME_MAX_SHUTTER;  } else {    if(max_shutter > MAX_SHUTTER) {      diff = 0;      max_shutter = MAX_SHUTTER;      newshutter = max_shutter;    }  }#endif#if 0  if(ctrl->shutter == max_shutter && (qc->adapt_data.exposure>>12)<10) {    newshutter = ctrl->shutter / 2;    if(newshutter < MIN_SHUTTER) newshutter = MIN_SHUTTER;  } else#endif  if(diff > DIFF_VAL_BIG) {    newshutter = ctrl->shutter - 2*INC_VAL*diff;    if(newshutter < MIN_SHUTTER) newshutter = MIN_SHUTTER;  } else if(diff > DIFF_VAL_SMALL) {    newshutter = ctrl->shutter - INC_VAL*diff;    if(newshutter < MIN_SHUTTER) newshutter = MIN_SHUTTER;  } else if(diff < -DIFF_VAL_BIG) {    newshutter = ctrl->shutter - 2*INC_VAL*diff;    if(newshutter > max_shutter) newshutter = max_shutter;  } else if(diff < -DIFF_VAL_SMALL) {    newshutter = ctrl->shutter - INC_VAL*diff;    if(newshutter > max_shutter) newshutter = max_shutter;  }  if(newshutter) {    ctrl->shutter = newshutter;    if (qc->sensor_data.sensor->set_shutter!=NULL) {      if ((r = qc->sensor_data.sensor->set_shutter(qc, newshutter))<0) goto fail;    }  } fail:  return;}/* }}} *//* {{{ [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 = 32;			/* (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;	}	// Wim van Eenennaam, do nothing before framedelay	if (ctrl->framecounter <= framedelay) 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.*/#define GAINSTEP 2		ctrl->gain = ctrl->gain + ctrl->gain/GAINSTEP + 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/GAINSTEP - 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 */

⌨️ 快捷键说明

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