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

📄 qc-driver.c

📁 罗技qc摄像头的linux下驱动程序及引用程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (ret < 0) goto fail;	ret = qc->dmabuf[0];	if (sensor->length_id>1) ret |= qc->dmabuf[1]<<8;	/* Assume LSB is always first from data received via USB */	if (qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_get_i2c(reg=0x%04X) = %04X", reg, ret);	return ret;fail:	PDEBUG("qc_get_i2c failed, code=%i",ret);	return ret;}/* }}} *//* {{{ [fold] int qc_stv_set(struct quickcam *qc, unsigned short reg, unsigned char val) *//* * Set one byte register in the STV-chip. qc_i2c_init() must be called first! */int qc_stv_set(struct quickcam *qc, unsigned short reg, unsigned char val){	int ret;	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_set(qc=%p,reg=0x%04X,val=%u)",qc,(int)reg,(int)val);	TEST_BUGR(qc==NULL);	if (sizeof(qc->dmabuf)<1) BUG();	qc_i2c_wait(qc);		/* Wait until no pending commands from qc_i2c_* */	qc->dmabuf[0] = val;	ret = usb_control_msg(qc->dev, usb_sndctrlpipe(qc->dev, 0),		0x04,			/* Request */		0x40,			/* RequestType */		reg, 0,			/* Value, Index */		qc->dmabuf, 1, 3*HZ);	if ((qcdebug&QC_DEBUGERRORS || qcdebug&QC_DEBUGLOGIC) && ret<0) PDEBUG("Failed qc_stv_set()=%i", ret);	if (ret<0) return ret;	return 0;}/* }}} *//* {{{ [fold] int qc_stv_get(struct quickcam *qc, unsigned short reg) *//* * Read one byte register in the STV-chip. qc_i2c_init() must be called first! * Return the unsigned register value or negative error code on error. */int qc_stv_get(struct quickcam *qc, unsigned short reg){	int ret;	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_get(qc=%p,reg=0x%04X)",qc,(int)reg);	TEST_BUGR(qc==NULL);	if (sizeof(qc->dmabuf)<1) BUG();	qc_i2c_wait(qc);		/* Wait until no pending commands from qc_i2c_* */	ret = usb_control_msg(qc->dev, usb_rcvctrlpipe(qc->dev, 0),		0x04,			/* Request */		0xC0,			/* RequestType */		reg, 0,			/* Value, Index */		qc->dmabuf, 1, 3*HZ);	if ((qcdebug&QC_DEBUGERRORS || qcdebug&QC_DEBUGLOGIC) && ret<0) PDEBUG("Failed qc_stv_get()=%i", ret);	if (ret<0) return ret;	if (qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_get(reg=0x%04X)=%02X", reg, qc->dmabuf[0]);	return qc->dmabuf[0];}/* }}} *//* {{{ [fold] int qc_stv_setw(struct quickcam *qc, unsigned short reg, unsigned short val) *//* * Set two byte register in the STV-chip. qc_i2c_init() must be called first! * "w" means either "word" or "wide", depending on your religion ;) */int qc_stv_setw(struct quickcam *qc, unsigned short reg, unsigned short val){	int ret;	if (qcdebug&QC_DEBUGLOGIC || qcdebug&QC_DEBUGCAMERA) PDEBUG("qc_stv_setw(qc=%p,reg=0x%04X,val=%i)",qc,(int)reg,(int)val);	TEST_BUGR(qc==NULL);	if (sizeof(qc->dmabuf)<2) BUG();	qc_i2c_wait(qc);	qc->dmabuf[0] = val & 0xFF;	qc->dmabuf[1] = (val >> 8) & 0xFF;	ret = usb_control_msg(qc->dev, usb_sndctrlpipe(qc->dev, 0),		0x04,		0x40,		reg, 0,		qc->dmabuf, 2, 3*HZ);	if ((qcdebug&QC_DEBUGERRORS || qcdebug&QC_DEBUGLOGIC) && ret<0) PDEBUG("Failed qc_stv_setw()=%i", ret);	if (ret<0) return ret;	return 0;}/* }}} *//* {{{ [fold] void qc_hsv2rgb(s16 hue, u16 sat, u16 val, int *red, int *green, int *blue) *//* Convert HSI (hue, saturation, intensity) to RGB (red, green, blue). * All input and output values are 0..65535. * Hue is actually signed, so it is -32768..32767, but this is equivalent * since it is the angle around full circle (0=Red, 21845=Green, 43690=Blue). * Based on libgimp, converted to 16.16 fixed point by tuukkat. */void qc_hsv2rgb(s16 hue, u16 sat, u16 val, int *red, int *green, int *blue){	unsigned int segment, valsat;	signed int   h = (u16)hue;	unsigned int s = (sat<32768) ? 0 : (sat-32768)*2;	/* 32768 or less = no saturation */	unsigned int v = val;					/* value = intensity */	unsigned int p;#if 1	/* Make common case more efficient */	if (s == 0) {		*red   = v;		*green = v;		*blue  = v;		return;	}#endif	segment = (h + 10923) & 0xFFFF;			segment = segment*3 >> 16;		/* 0..2: 0=R, 1=G, 2=B */	hue -= segment * 21845;			/* -10923..10923 */	h = hue;	h *= 3;	valsat = v*s >> 16;			/* 0..65534 */	p = v - valsat;	if (h>=0) {		unsigned int t = v - (valsat * (32769 - h) >> 15);		switch (segment) {		default:			PDEBUG("hsi2rgb: this can never happen!");		case 0:	/* R-> */			*red   = v;			*green = t;			*blue  = p;			break;		case 1:	/* G-> */			*red   = p;			*green = v;			*blue  = t;			break;		case 2:	/* B-> */			*red   = t;			*green = p;			*blue  = v;			break;		}	} else {		unsigned int q = v - (valsat * (32769 + h) >> 15);		switch (segment) {		default:			PDEBUG("hsi2rgb: this can never happen!");		case 0:	/* ->R */			*red   = v;			*green = p;			*blue  = q;			break;		case 1:	/* ->G */			*red   = q;			*green = v;			*blue  = p;			break;		case 2:	/* ->B */			*red   = p;			*green = q;			*blue  = v;			break;		}	}	//PDEBUG("hue=%i sat=%i val=%i  segment=%i h=%i  r=%i g=%i b=%i",hue,sat,val, segment,h, *red,*green,*blue);}/* }}} *//* {{{ [fold] int qc_lock(struct quickcam *qc) *//* Takes a lock on quickcam_list_lock and verifies that the given qc is available *//* Returns 0 on success in which case the lock must be freed later or negative error code */static int qc_lock(struct quickcam *qc){	struct quickcam *q;	if (down_interruptible(&quickcam_list_lock)) return -ERESTARTSYS;	/* Search for the device in the list of plugged quickcams (this prevents a race condition) */	list_for_each_entry(q, &quickcam_list, list) {		if (q == qc) break;			/* Found it? */	}	if (q != qc) {		PDEBUG("can not find the device to open");		up(&quickcam_list_lock);		return -ENODEV;	}	return 0;}/* }}} *//* }}} *//* {{{ [fold] **** qc_i2c:    I2C URB messaging routines (qc_i2c_*) ************* *//* We have here a quite typical producer-consumer scheme: * URB interrupt handler routine consumes i2c data, while * kernel mode processes create more of it. * Ref: Linux Device Drivers, Alessandro Rubini et al, 2nd edition, pg. 279 * "Using Circular Buffers" */static const int qc_i2c_maxbufsize = 0x23;/* {{{ [fold] (private) qc_i2c_nextpacket(struct quickcam *qc) *//* Fill URB and submit it, if there are more data to send  * Consume data from "commands" array. May be called from interrupt context. * Return standard error code. */static int qc_i2c_nextpacket(struct quickcam *qc){	struct qc_i2c_data *id = &qc->i2c_data;	struct urb *urb = id->urb;	u8 *tb = urb->transfer_buffer, flags;	struct usb_ctrlrequest *cr = (struct usb_ctrlrequest *)urb->setup_packet;	unsigned int newtail, length, regnum, i, j;	signed int r;	if (qcdebug&QC_DEBUGLOGIC) PDEBUG("qc_i2c_nextpacket(quickcam=%p), tail=%i, head=%i, interrupt=%i",qc,id->tail,id->head,(int)in_interrupt());	IDEBUG_TEST(*id);	if (!qc->connected) {		/* Device was disconnected, cancel all pending packets and return */		id->tail = id->head = id->newhead = 0;		id->packets = 0;		return -ENODEV;	}	newtail = id->tail;					/* First data to fetch */	if (id->packets<=1 && newtail==id->head) {	/* packets==0 or 1: no extra URB need to be scheduled */		if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("No more control URBs to send");		r = 0;		goto nourbs;	}	if (id->packets<=1) {		/* Collect data from circular buffer to URB transfer buffer */		/* Now id->tail!=id->head: there's at least one packet to send */		TEST_BUGR(newtail==id->head);		id->packets = 1;		if (GET_PRODUCTID(qc)==0x0850) id->packets = 2;		regnum = 0x0400;		length = qc_i2c_maxbufsize;		i = 0;							/* Transfer buffer position */		if (!(id->commands[newtail].flags & I2C_FLAG_WORD)) {			/* Normal byte-wide register write */			if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("Setting byte-wide registers");			do {				tb[i]      = id->commands[newtail].regnum;				tb[i+0x10] = id->commands[newtail].loval;				flags      = id->commands[newtail].flags;				i++;				newtail    = (newtail + 1) % I2C_MAXCOMMANDS;	/* Next data to fetch */				if (flags & I2C_FLAG_BREAK) break;		/* Start new packet */				if (newtail == id->head) break;		/* No more data? */				if (i > 0x0F) break;			/* Transfer buffer full? */				if (id->commands[newtail].flags & I2C_FLAG_WORD) break;			} while (TRUE);/*if (flags&I2C_FLAG_BREAK) PDEBUG("breaking!!!!!!!!!!");{int mm;for(mm=0;mm<i;mm++) printk("%02X=%02X ",tb[mm],tb[mm+0x10]);printk("\n");}*/			for (j=i; j<0x10; j++) tb[j+0x10] = 0;	/* Zero out unused register values just to be sure */		} else {			/* Two-byte-wide register write (used in Photobit) */			if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("Setting word-wide registers");			do {				tb[i]        = id->commands[newtail].regnum;				tb[i*2+0x10] = id->commands[newtail].loval;				tb[i*2+0x11] = id->commands[newtail].hival;				flags        = id->commands[newtail].flags;				i++;				newtail = (newtail + 1) % I2C_MAXCOMMANDS;	/* Next data to fetch */				if (flags & I2C_FLAG_BREAK) break;		/* Start new packet */				if (newtail == id->head) break;		/* No more data? */				if (i > 0x07) break;			/* Transfer buffer full? */				if (!(id->commands[newtail].flags & I2C_FLAG_WORD)) break;			} while (TRUE);			for (j=i*2; j<0x10; j++) tb[j+0x10] = 0;	/* Zero out unused register values just to be sure */		}		for (j=i; j<0x10; j++) tb[j] = 0;	/* Zero out unused register addresses just to be sure */		tb[0x20] = qc->sensor_data.sensor->i2c_addr;		tb[0x21] = i-1;			/* Number of commands to send - 1 */		tb[0x22] = 1;			/* Write cmd, 03 would be read. */		id->tail = newtail;		if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("sending i2c packet, cmds=%i, reg0=%02X, val0=%02X",tb[0x21]+1,tb[0],tb[0x10]);	} else {		/* id->packets==2: send extra packet for QuickCam Web */		if (qcdebug&QC_DEBUGCONTROLURBS) PDEBUG("sending finalization packet");		id->packets = 1;		regnum = 0x1704;		length = 1;		tb[0] = 1;	}	urb->dev    = qc->dev;		/* 2.4.x zeroes urb->dev after submission */	urb->pipe   = usb_sndctrlpipe(qc->dev, 0);	urb->transfer_buffer_length = length;	cr->wValue  = cpu_to_le16(regnum);	cr->wLength = cpu_to_le16(length);	r = usb_submit_urb(urb,GFP_ATOMIC);	CHECK_ERROR(r<0, nourbs, "Failed qc_i2c_nextpacket()=%i", r);	return 0;nourbs:	id->packets = 0;	/* No more URBs are scheduled */	wake_up(&id->wq);	//FIXME: race condition: now packets=0, so id could be freed and wake_up do oops	return r;}/* }}} *//* {{{ [fold] (private) qc_i2c_handler(struct urb *urb) *//* This is URB completion handler and is called in interrupt context. * For each submitted URB, this function is guaranteed to be called exactly once. * This function may not be called reentrantly for the same qc (should be ok, IRQs don't nest). * It will resubmit the same URB, if * - The previous URB completed without error * - Camera is still connected (qc->connected == TRUE) * - There is still commands to be sent in commands buffer or pid=0x850 and finalization packet is not yet sent. */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)static void qc_i2c_handler(struct urb *urb, struct pt_regs *ptregs)#elsestatic void qc_i2c_handler(struct urb *urb)#endif{	struct quickcam *qc = urb->context;	if (qcdebug&QC_DEBUGINTERRUPTS) PDEBUG("[INTR] qc_i2c_handler(urb=%p)",urb);	TEST_BUG(urb==NULL);	TEST_BUG(qc==NULL);	IDEBUG_TEST(qc->i2c_data);	if (urb->status<0) {		switch (urb->status) {		default:			/* Seen here: ECONNABORTED    103     Software caused connection abort */			PRINTK(KERN_ERR,"Unhandled control URB error %i",urb->status);		case -EPROTO:		/* Bitstuff error or unknown USB error */		case -EILSEQ:		/* CRC mismatch */		case -ETIMEDOUT:	/* Transfer timed out */		case -EREMOTEIO:	/* Short packet detected */		case -EPIPE:		/* Babble detect or endpoint stalled */			/* We could try resubmitting the URB here */		case -ENOENT:		/* URB was unlinked */		case -ENODEV:		/* Device was removed */		case -ECONNRESET:	/* Asynchronous unlink, should not happen */			PRINTK(KERN_ERR,"Control URB error %i",urb->status);			qc->i2c_data.packets = 0;	/* Don't schedule more URBs */			wake_up(&qc->i2c_data.wq);			return;		}	}	qc_i2c_nextpacket(qc);}/* }}} *//* {{{ [fold] qc_i2c_flush(struct quickcam *qc) */

⌨️ 快捷键说明

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