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

📄 qc-driver.c

📁 在Linux下用于webeye的摄像头的驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Wait until all previosly set registers are set or abort all transmissions * and return error code. * After this function returns, there will not be uncompleted I2C URBs. */int qc_i2c_wait(struct quickcam *qc){	struct qc_i2c_data *id = &qc->i2c_data;	int r;	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_wait(quickcam=%p)",qc);	TEST_BUGR(in_interrupt());	TEST_BUGR(qc==NULL);	IDEBUG_TEST(*id);	if (!qc->connected) goto cancel;	r = qc_i2c_flush(qc);	if (r>=0) r = wait_event_interruptible(id->wq, id->packets==0);	if (r<0) goto cancel;	return 0;cancel:	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("Canceling pending URB %p, packets=%i", id->urb, id->packets);	PDEBUG("i2c_cancel: qc=%p, id=%p",qc,id);	PDEBUG("i2c_cancel: id->urb=%p", id->urb);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)	if (qc->connected) {		PDEBUG("i2c_cancel: id->urb->dev=%p", id->urb->dev);		if (id->urb->dev!=NULL) {			PDEBUG("i2c_cancel: id->urb->dev->bus=%p", id->urb->dev->bus);			if (id->urb->dev->bus!=NULL) {				PDEBUG("i2c_cancel: id->urb->dev->bus->op=%p", id->urb->dev->bus->op);				//PDEBUG("id->urb->dev->bus->op->unlink=%p", id->urb->dev->bus->op->unlink);			}		}	}#endif	/* Cancel URB if it is in progress or in completion handler */	if (id->packets > 0) usb_kill_urb(id->urb);	TEST_BUGR_MSG(id->packets!=0, "i2c_wait: packets=%i", id->packets);	return 0;}/* }}} *//* {{{ [fold] (private) qc_i2c_set0(struct quickcam *qc, unsigned char regnum, unsigned char loval, unsigned char hival, int flags) *//* Called from qc_i2c_set and qc_i2c_setw, should not be called elsewhere */static int qc_i2c_set0(struct quickcam *qc, unsigned char regnum, unsigned char loval, unsigned char hival, int flags){	struct qc_i2c_data *id = &qc->i2c_data;	unsigned int newhead;	signed int r;	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_set0(quickcam=%p,reg=%02X,val=%02X%02X)",qc,regnum,hival,loval);	TEST_BUGR(qc==NULL);	IDEBUG_TEST(*id);	newhead = id->newhead;	id->commands[newhead].loval  = loval;	id->commands[newhead].hival  = hival;	id->commands[newhead].regnum = regnum;	id->commands[newhead].flags  = flags;	newhead = (newhead + 1) % I2C_MAXCOMMANDS;	if (newhead == id->tail) {		/* If buffer is full, wait until it's empty */		if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("i2c buffer is full, waiting");		r = qc_i2c_wait(qc);		if (r<0) return r;	}	TEST_BUGR(newhead==id->tail);	/* no i2c buffer space but nothing to send!!! */	id->newhead = newhead;	return 0;}/* }}} *//* {{{ [fold] qc_i2c_set(struct quickcam *qc, unsigned char reg, unsigned char val) *//* Set an I2C register to desired value *//* (queue setting to be sent later when qc_i2c_flush() is called) */inline int qc_i2c_set(struct quickcam *qc, unsigned char reg, unsigned char val){	return qc_i2c_set0(qc, reg, val, 0, 0);}/* }}} *//* {{{ [fold] qc_i2c_setw(struct quickcam *qc, unsigned char reg, unsigned short val) *//* Set a two-byte (word length) I2C register to desired value (queue setting to be sent later) *//* (queue setting to be sent later when qc_i2c_flush() is called) */inline int qc_i2c_setw(struct quickcam *qc, unsigned char reg, unsigned short val){	return qc_i2c_set0(qc, reg, val & 0xFF, (val >> 8) & 0xFF, I2C_FLAG_WORD);}/* }}} *//* {{{ [fold] qc_i2c_break(struct quickcam *qc)  *//* The next register written will be sent in another packet */int qc_i2c_break(struct quickcam *qc){	struct qc_i2c_data *id = &qc->i2c_data;	unsigned int prevhead;	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_break(quickcam=%p)",qc);	TEST_BUGR(qc==NULL);	IDEBUG_TEST(*id);	/* We access an entry that may be already submitted and even finished */	/* But it should not harm */	prevhead = (id->newhead + I2C_MAXCOMMANDS - 1) % I2C_MAXCOMMANDS;	id->commands[prevhead].flags |= I2C_FLAG_BREAK;	barrier();	return qc_i2c_flush(qc);}/* }}} *//* {{{ [fold] qc_i2c_init(struct quickcam *qc) *//* Initialize structures and hardware for I2C communication */static int qc_i2c_init(struct quickcam *qc){	struct qc_i2c_data *id = &qc->i2c_data;	struct urb *urb;	struct usb_ctrlrequest *cr;	int r = -ENOMEM;	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_i2c_init(quickcam=%p)",qc);	TEST_BUGR(qc==NULL);	id->tail = id->head = id->newhead = 0;	/* Next position to be filled and sent is 0 */	id->packets = 0;	init_waitqueue_head(&id->wq);	/* Allocate an URB and associated buffers and fill them */	urb = id->urb = usb_alloc_urb(0,GFP_KERNEL);	if (!urb) goto fail1;	cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);	urb->setup_packet = (unsigned char *)cr;	if (!cr) goto fail2;	urb->transfer_buffer = kmalloc(qc_i2c_maxbufsize*sizeof(u8), GFP_KERNEL);	/* Allocate maximum ever needed */	if (!urb->transfer_buffer) goto fail3;	spin_lock_init(&urb->lock);	urb->complete = qc_i2c_handler;	urb->context  = qc;#if (LINUX_VERSION_CODE<KERNEL_VERSION(2,6,9) && !defined(CONFIG_SUSE_KERNEL)) || LINUX_VERSION_CODE<KERNEL_VERSION(2,6,8)	urb->timeout  = 3*HZ;			/* 1 s */#endif	cr->bRequestType = 0x40;	cr->bRequest     = 0x04;	cr->wIndex       = 0;	IDEBUG_INIT(*id);	return 0;fail3:	kfree(cr);fail2:	usb_free_urb(urb);	POISON(id->urb);fail1:	return r;}/* }}} *//* {{{ [fold] qc_i2c_exit(struct quickcam *qc) *//* Close messaging, free up memory, stop messaging */static void qc_i2c_exit(struct quickcam *qc){	struct qc_i2c_data *id = &qc->i2c_data;	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_i2c_exit(qc=%p)",qc);	TEST_BUG(qc==NULL);	qc_i2c_wait(qc);	kfree(id->urb->setup_packet);	kfree(id->urb->transfer_buffer);	POISON(id->urb->setup_packet);	POISON(id->urb->transfer_buffer);	usb_free_urb(id->urb);	IDEBUG_EXIT(*id);}/* }}} *//* }}} *//* {{{ [fold] **** qc_proc:   /proc interface *********************************** */#if HAVE_PROCFSstatic struct proc_dir_entry *qc_proc_entry = NULL;	/* Initialization should not be necessary, but just in case... *//* {{{ [fold] qc_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) */static inline const char *qc_proc_yesno(Bool b){	return b ? "Yes" : "No";}static int qc_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data){	struct quickcam *qc = data;	char *out = page;	int len;	if (qc_lock(qc) < 0) return 0;	out += sprintf(out, "\tGeneral driver status\n");	out += sprintf(out, "Driver version   : %s\n", VERSION);	out += sprintf(out, "Kernel version   : %s\n", UTS_RELEASE);	if (qc->dev!=NULL) {	out += sprintf(out, "Device Id        : %04X:%04X\n", (int)GET_VENDORID(qc), (int)GET_PRODUCTID(qc));	out += sprintf(out, "USB bus number   : %i\n", qc->dev->bus->busnum);	}	out += sprintf(out, "Users            : %i\n", qc->users);	out += sprintf(out, "Connected        : %s\n", qc_proc_yesno(qc->connected));	out += sprintf(out, "\n\tPicture settings set by user\n");	out += sprintf(out, "Brightness       : %d\n", (int)qc->vpic.brightness);	out += sprintf(out, "Hue              : %d\n", (int)qc->vpic.hue);	out += sprintf(out, "Color            : %d\n", (int)qc->vpic.colour);	out += sprintf(out, "Contrast         : %d\n", (int)qc->vpic.contrast);	out += sprintf(out, "Whiteness        : %d\n", (int)qc->vpic.whiteness);	if (qc->users > 0) {	out += sprintf(out, "Depth            : %d\n", (int)qc->vpic.depth);	out += sprintf(out, "Palette          : %s\n", qc_fmt_getname(qc->vpic.palette));	}	if (qc->users > 0) {	out += sprintf(out, "\n\tOutput window\n");	out += sprintf(out, "Width            : %d\n", (int)qc->vwin.width);	out += sprintf(out, "Height           : %d\n", (int)qc->vwin.height);	}	out += sprintf(out, "\n\tSensor\n");	out += sprintf(out, "Type             : %s\n", qc->sensor_data.sensor->name);	out += sprintf(out, "Manufacturer     : %s\n", qc->sensor_data.sensor->manufacturer);	if (qc->users > 0) {	out += sprintf(out, "Maximum width    : %d\n", qc->sensor_data.maxwidth);	out += sprintf(out, "Maximum height   : %d\n", qc->sensor_data.maxheight);	out += sprintf(out, "Current width    : %d\n", qc->sensor_data.width);	out += sprintf(out, "Current height   : %d\n", qc->sensor_data.height);	}	out += sprintf(out, "\n\tI2C command stream\n");	out += sprintf(out, "Scheduled packets: %d\n", qc->i2c_data.packets);	out += sprintf(out, "Packets on queue : %d\n", (I2C_MAXCOMMANDS + qc->i2c_data.head - qc->i2c_data.tail) % I2C_MAXCOMMANDS);	if (qc->users > 0) {	out += sprintf(out, "\n\tIsochronous data stream\n");	out += sprintf(out, "Stream enabled   : %s\n", qc_proc_yesno(qc->isoc_data.streaming));	out += sprintf(out, "Transfer errors  : %d\n", qc->isoc_data.errorcount);	out += sprintf(out, "\n\tFrame buffering\n");	out += sprintf(out, "Frames on queue  : %d\n", (FRAME_BUFFERS + qc->frame_data.head - qc->frame_data.tail) % FRAME_BUFFERS);	out += sprintf(out, "Capturing        : %s\n", qc_proc_yesno(qc->stream_data.capturing));	out += sprintf(out, "Waiting processes: %d\n", qc->frame_data.waiting);	}	out += sprintf(out, "\n\tAutomatic exposure control\n");	out += sprintf(out, "Picture intensity: %d\n", qc->adapt_data.oldmidvalue);	out += sprintf(out, "Exposure setting : %d\n", qc->adapt_data.exposure);	out += sprintf(out, "Gain setting     : %d\n", qc->adapt_data.gain);	out += sprintf(out, "Delta value      : %d\n", qc->adapt_data.olddelta);	out += sprintf(out, "Control algorithm: ");	switch (qc->adapt_data.controlalg) {		case EXPCONTROL_SATURATED: out += sprintf(out, "Saturated\n"); break;		case EXPCONTROL_NEWTON:    out += sprintf(out, "Newton\n"); break;		case EXPCONTROL_FLOAT:     out += sprintf(out, "Float\n"); break;		default: out += sprintf(out, "?\n"); break;	}	out += sprintf(out, "\n\tDefault settings\n");	out += sprintf(out, "Debug            : 0x%02X\n", qcdebug);	out += sprintf(out, "Keep settings    : %s\n", qc_proc_yesno(qc->settings.keepsettings));	out += sprintf(out, "Settle max frames: %i\n", qc->settings.settle);	out += sprintf(out, "Subsampling      : %s\n", qc_proc_yesno(qc->settings.subsample));	out += sprintf(out, "Compress         : %s\n", qc_proc_yesno(qc->settings.compress));	out += sprintf(out, "Frame skipping   : %i\n", qc->settings.frameskip);	out += sprintf(out, "Image quality    : %i\n", qc->settings.quality);	out += sprintf(out, "Adaptive         : %s\n", qc_proc_yesno(qc->settings.adaptive));	out += sprintf(out, "Equalize         : %s\n", qc_proc_yesno(qc->settings.equalize));	out += sprintf(out, "User lookup-table: %s\n", qc_proc_yesno(qc->settings.userlut));	out += sprintf(out, "Retryerrors      : %s\n", qc_proc_yesno(qc->settings.retryerrors));	out += sprintf(out, "Compatible 16x   : %s\n", qc_proc_yesno(qc->settings.compat_16x));	out += sprintf(out, "Compatible DblBuf: %s\n", qc_proc_yesno(qc->settings.compat_dblbuf));	out += sprintf(out, "Compatible ToRgb : %s\n", qc_proc_yesno(qc->settings.compat_torgb));	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_entry==NULL) return -ENOTDIR;	sprintf(name, "video%d", qc->vdev.minor);	entry = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, qc_proc_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;	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) return;	TEST_BUG(!qc_proc_entry);	sprintf(name, "video%d", qc->vdev.minor);	remove_proc_entry(name, qc_proc_entry);	POISON(qc->proc_entry);	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_proc_destroy() done");}/* }}} *//* {{{ [fold] qc_proc_init(void) *//* Called when the driver is initially loaded, creates "/proc/video/quickcam" subdirectory */static int qc_proc_init(void){	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGINIT) PDEBUG("qc_proc_init()");	qc_proc_entry = create_proc_entry(qc_proc_name, S_IFDIR, NULL);		/* Create /proc/video/quickcam */	if (!qc_proc_entry) {		/* create_proc_entry failed, possibly because /proc/video is missing (patch by aceJacek <acejacek@pop.e-wro.pl>) */		proc_mkdir("video", NULL);			/* Might fail, if the directory already exists, but we don't care */		qc_proc_entry = create_proc_entry(qc_proc_name, S_IFDIR, NULL);		if (!qc_proc_entry) {			PRINTK(KERN_WARNING,"Could not register procfs dir entry");			return -ENXIO;		}	}	qc_proc_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)

⌨️ 快捷键说明

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