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

📄 ovfx2.c

📁 支持linux2.6和linux2.4的ov511摄像头驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	int rc;	PDEBUG(5, "0x%02X:0x%02X", reg, value);	/* We don't use cbuf here, but the lock ensures we're done before	 * disconnect() completes */	down(&ov->cbuf_lock);	if (!ov->cbuf) {		up(&ov->cbuf_lock);		return -ENODEV;	}	rc = usb_control_msg(ov->dev,			     usb_sndctrlpipe(ov->dev, 0),			     OVFX2_REQ_REG_WRITE,			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)			     (__u16)value, (__u16)reg, NULL, 0, 1000);#else			     (__u16)value, (__u16)reg, NULL, 0, HZ);#endif	up(&ov->cbuf_lock);	if (rc < 0)		err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));	return rc;}/* Read from an OVFX2 register *//* returns: negative is error, pos or zero is data */static intreg_r(struct usb_ovfx2 *ov, unsigned char reg){	int rc;	down(&ov->cbuf_lock);	if (!ov->cbuf) {		up(&ov->cbuf_lock);		return -ENODEV;	}	rc = usb_control_msg(ov->dev,			     usb_rcvctrlpipe(ov->dev, 0),			     OVFX2_REQ_REG_READ,			     USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)			     0, (__u16)reg, &ov->cbuf[0], 1, 1000);#else			     0, (__u16)reg, &ov->cbuf[0], 1, HZ);#endif	if (rc < 0) {		err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));	} else {		rc = ov->cbuf[0];		PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);	}	up(&ov->cbuf_lock);	return rc;}/* * Writes bits at positions specified by mask to an OVFX2 reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value". */static intreg_w_mask(struct usb_ovfx2 *ov,	   unsigned char reg,	   unsigned char value,	   unsigned char mask){	int ret;	unsigned char oldval, newval;	if (mask == 0xff) {		newval = value;	} else {		ret = reg_r(ov, reg);		if (ret < 0)			return ret;		oldval = (unsigned char) ret;		oldval &= (~mask);		/* Clear the masked bits */		value &= mask;			/* Enforce mask on value */		newval = oldval | value;	/* Set the desired bits */	}	return (reg_w(ov, reg, newval));}static inti2c_w(struct usb_ovfx2 *ov, unsigned char reg, unsigned char value){	return i2c_smbus_write_byte_data(&ov->internal_client, reg, value);}static inti2c_w_mask(struct usb_ovfx2 *ov,	   unsigned char reg,	   unsigned char value,	   unsigned char mask){	int rc;	unsigned char oldval, newval;	if (mask == 0xff) {		newval = value;	} else {		rc = i2c_smbus_read_byte_data(&ov->internal_client, reg);		if (rc < 0)			return rc;		oldval = (unsigned char) rc;		oldval &= (~mask);		/* Clear the masked bits */		value &= mask;			/* Enforce mask on value */		newval = oldval | value;	/* Set the desired bits */	}	return i2c_smbus_write_byte_data(&ov->internal_client, reg, newval);}/********************************************************************** * * Low-level I2C I/O functions * **********************************************************************//* NOTE: Do not call this function directly! * Sets I2C read and write slave IDs, if they have changed. * Returns <0 for error */static intovfx2_i2c_adap_set_slave(struct usb_ovfx2 *ov, unsigned char slave){	int rc;	if (ov->last_slave == slave)		return 0;	/* invalidate slave */	ov->last_slave = 0;	rc = reg_w(ov, REG_I2C_ADDR, (slave<<1));	if (rc < 0)		return rc;	/* validate slave */	ov->last_slave = slave;	return 0;}static intovfx2_i2c_adap_read_byte_data(struct usb_ovfx2 *ov,			      unsigned char addr,			      unsigned char subaddr,			      unsigned char *val){	int rc;	/* Set slave addresses */		rc = ovfx2_i2c_adap_set_slave(ov, addr);	if (rc < 0)		return rc;	down(&ov->cbuf_lock);	if (!ov->cbuf) {		up(&ov->cbuf_lock);		return -ENODEV;	}	rc = usb_control_msg(ov->dev,			     usb_rcvctrlpipe(ov->dev, 0),			     OVFX2_REQ_I2C_READ,			     USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)			     0, (__u16)subaddr, &ov->cbuf[0], 1, 1000);#else			     0, (__u16)subaddr, &ov->cbuf[0], 1, HZ);#endif	if (rc < 0) {		PDEBUG(5, "error %d: %s", rc, symbolic(urb_errlist, rc));	} else {		*val = ov->cbuf[0];		PDEBUG(5, "0x%02X:0x%02X", subaddr, ov->cbuf[0]);	}	up(&ov->cbuf_lock);	return rc;}static intovfx2_i2c_adap_write_byte_data(struct usb_ovfx2 *ov,			       unsigned char addr,			       unsigned char subaddr,			       unsigned char val){	int rc;	PDEBUG(5, "(0x%02X) 0x%02X:0x%02X", addr<<1, subaddr, val);	/* Set slave addresses */		rc = ovfx2_i2c_adap_set_slave(ov, addr);	if (rc < 0)		return rc;	/* We don't use cbuf here, but the lock ensures we're done before	 * disconnect() completes */	down(&ov->cbuf_lock);	if (!ov->cbuf) {		up(&ov->cbuf_lock);		return -ENODEV;	}	rc = usb_control_msg(ov->dev,			     usb_sndctrlpipe(ov->dev, 0),			     OVFX2_REQ_I2C_WRITE,			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)			     (__u16)val, (__u16)subaddr, NULL, 0, 1000);#else			     (__u16)val, (__u16)subaddr, NULL, 0, HZ);#endif	up(&ov->cbuf_lock);	if (rc < 0)		PDEBUG(5, "error %d: %s", rc, symbolic(urb_errlist, rc));	return rc;}static intwrite_regvals(struct usb_ovfx2 *ov, struct regval *regvals){	int rc;	while (regvals->mask != 0) {		rc = reg_w_mask(ov, regvals->reg, regvals->val, regvals->mask);		if (rc < 0)			return rc;		regvals++;	}	return 0;}#ifdef OVFX2_DEBUGstatic voiddump_reg_range(struct usb_ovfx2 *ov, int reg1, int regn){	int i, rc;	for (i = reg1; i <= regn; i++) {		rc = reg_r(ov, i);		info("OVFX2[0x%02X] = 0x%02X", i, rc);	}}static voidovfx2_dump_regs(struct usb_ovfx2 *ov){	dump_reg_range(ov, 0x00, 0xff);}#endif/********************************************************************** * * Kernel I2C Interface * **********************************************************************/static intovfx2_i2c_validate_addr(struct usb_ovfx2 *ov, u16 addr){	switch (addr) {	case OV7xx0_SID:		return 0;	default:		PDEBUG(4, "Rejected slave ID 0x%04X", addr);		return -EINVAL;	}}static inline intsensor_cmd(struct usb_ovfx2 *ov, unsigned int cmd, void *arg){	struct i2c_client *c = ov->sensor_client;	if (c && c->driver->command)		return c->driver->command(ov->sensor_client, cmd, arg);	else		return -ENODEV;}#if 0static voidcall_i2c_clients(struct usb_ovfx2 *ov, unsigned int cmd, void *arg){#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)	struct i2c_client *client;	int i;	for (i = 0; i < I2C_CLIENT_MAX; i++) {		client = ov->i2c_adap.clients[i];		/* Sensor_client is not called from here for now, since it		   has different enumeration for cmd  */		if (client == ov->sensor_client)			continue;		if (client && client->driver->command)			client->driver->command(client, cmd, arg);	}#else	i2c_clients_command(&ov->i2c_adap, cmd, arg);#endif}#endifstatic intovfx2_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,		 char read_write, u8 command, int size,		 union i2c_smbus_data *data){	struct usb_ovfx2 *ov = i2c_get_adapdata(adapter);	int rc = -ENOSYS;	if (size == I2C_SMBUS_QUICK) {		PDEBUG(4, "Got probed at addr 0x%04X", addr);		rc = ovfx2_i2c_validate_addr(ov, addr);	} else if (size == I2C_SMBUS_BYTE_DATA) {		if (read_write == I2C_SMBUS_WRITE) { 			rc = ovfx2_i2c_adap_write_byte_data(ov, addr, command,							    data->byte);		} else if (read_write == I2C_SMBUS_READ) {			rc = ovfx2_i2c_adap_read_byte_data(ov, addr, command,							   &data->byte);		}	} else {		warn("Unsupported I2C transfer mode (%d)", size);		return -EINVAL;	}	/* This works around a bug in the I2C core */	if (rc > 0)		rc = 0;	return rc;}static u32ovfx2_i2c_func(struct i2c_adapter *adap){	return I2C_FUNC_SMBUS_QUICK	     | I2C_FUNC_SMBUS_BYTE_DATA;}static inti2c_attach_inform(struct i2c_client *client){	struct usb_ovfx2 *ov = i2c_get_adapdata(client->adapter);	int id = client->driver->id;	if (id == I2C_DRIVERID_OVCAMCHIP) {		int rc, mono = 0;		ov->sensor_client = client;		rc = sensor_cmd(ov, OVCAMCHIP_CMD_INITIALIZE, &mono);		if (rc < 0) {			err("ERROR: Sensor init failed (rc=%d)", rc);			ov->sensor_client = NULL;			return rc;		}		down(&ov->lock);		if (sensor_cmd(ov, OVCAMCHIP_CMD_Q_SUBTYPE, &ov->sensor) < 0)			rc = -EIO;		else if (client->addr == OV7xx0_SID)			rc = ov7xx0_configure(ov);		else			rc = -EINVAL;		up(&ov->lock);		if (rc) {			ov->sensor_client = NULL;			return rc;		}	} else	{		PDEBUG(1, "Rejected client [%s] with [%s]",#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)		       client->name, client->driver->name);#else		       client->name, client->driver->driver.name);#endif		return -1;	}	PDEBUG(1, "i2c attach client [%s] with [%s]",#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)	       client->name, client->driver->name);#else	       client->name, client->driver->driver.name);#endif	return 0;}static inti2c_detach_inform(struct i2c_client *client){	struct usb_ovfx2 *ov = i2c_get_adapdata(client->adapter);	if (ov->sensor_client == client) {		ov->sensor_client = NULL;	}	PDEBUG(1, "i2c detach [%s]", client->name);	return 0;}static int ovfx2_i2c_control(struct i2c_adapter *adapter, unsigned int cmd,		  unsigned long arg){	return 0;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)static voidovfx2_i2c_inc_use(struct i2c_adapter *adap){	MOD_INC_USE_COUNT;}static voidovfx2_i2c_dec_use(struct i2c_adapter *adap){	MOD_DEC_USE_COUNT;}#endifstatic struct i2c_algorithm ovfx2_i2c_algo = {#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)	.name =			"OVFX2 algorithm",	.id =			I2C_ALGO_SMBUS,#endif	.smbus_xfer =		ovfx2_smbus_xfer,	.algo_control =		ovfx2_i2c_control,	.functionality =	ovfx2_i2c_func,};static struct i2c_adapter i2c_adap_template = {	.name = 		"(unset)",#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)	.id =			I2C_ALGO_SMBUS | I2C_HW_SMBUS_OVFX2,#else	.id =			I2C_HW_SMBUS_OVFX2,#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 6)	.class =		I2C_CLASS_CAM_DIGITAL,#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70)	.class =		I2C_ADAP_CLASS_CAM_DIGITAL,#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)	.inc_use =		ovfx2_i2c_inc_use,	.dec_use =		ovfx2_i2c_dec_use,#else	.owner =		THIS_MODULE,#endif	.client_register =	i2c_attach_inform,	.client_unregister =	i2c_detach_inform,};static intovfx2_init_i2c(struct usb_ovfx2 *ov){	memcpy(&ov->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter));	/* Temporary name. We'll set the final one when we know the minor # */	sprintf(ov->i2c_adap.name, "OVFX2");	i2c_set_adapdata(&ov->i2c_adap, ov);	ov->i2c_adap.algo = &ovfx2_i2c_algo;	ov->internal_client.adapter = &ov->i2c_adap;	PDEBUG(4, "Registering I2C bus with kernel");	return i2c_add_adapter(&ov->i2c_adap);}/*****************************************************************************//* Pause video streaming */static inline intovfx2_pause(struct usb_ovfx2 *ov){	PDEBUG(4, "pausing stream");	ov->stopped = 1;	return reg_w_mask(ov, 0x0f, 0x00, 0x02);}/* Resume video streaming if it was stopped. */static inline intovfx2_resume(struct usb_ovfx2 *ov){	if (ov->stopped) {		PDEBUG(4, "resuming stream");		ov->stopped = 0;		return reg_w_mask(ov, 0x0f, 0x02, 0x02);	}	return 0;}/* Returns 1 if image streaming needs to be stopped while setting the specified * control, and returns 0 if not */static intsensor_needs_stop(struct usb_ovfx2 *ov, int cid){	if (!ov->stop_during_set)		return 0;	/* FIXME: I don't know whether the FX2 needs to be stopped yet. Don't	 * do it yet, since it might not be safe to pause the stream while bulk	 * requests are active */	return 0;	switch (cid) {	case OVCAMCHIP_CID_CONT:	case OVCAMCHIP_CID_BRIGHT:	case OVCAMCHIP_CID_SAT:	case OVCAMCHIP_CID_HUE:	case OVCAMCHIP_CID_EXP:		 return 1;	}

⌨️ 快捷键说明

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