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

📄 ov511.c

📁 ov511.c是linux下的wabcam的驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
}/* Do not call this function directly! */static intov51x_i2c_write_mask_internal(struct usb_ov511 *ov,			      unsigned char reg,			      unsigned char value,			      unsigned char mask){	int rc;	unsigned char oldval, newval;	if (mask == 0xff) {		newval = value;	} else {		if (ov->bclass == BCL_OV518)			rc = ov518_i2c_read_internal(ov, reg);		else			rc = ov511_i2c_read_internal(ov, 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 */	}	if (ov->bclass == BCL_OV518)		return (ov518_i2c_write_internal(ov, reg, newval));	else		return (ov511_i2c_write_internal(ov, reg, newval));}/* Writes bits at positions specified by mask to an I2C 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 inti2c_w_mask(struct usb_ov511 *ov,	   unsigned char reg,	   unsigned char value,	   unsigned char mask){	int rc;	down(&ov->i2c_lock);	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);	up(&ov->i2c_lock);	return rc;}/* Set the read and write slave IDs. The "slave" argument is the write slave, * and the read slave will be set to (slave + 1). ov->i2c_lock should be held * when calling this. This should not be called from outside the i2c I/O * functions. */static inline inti2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave){	int rc;	rc = reg_w(ov, R51x_I2C_W_SID, slave);	if (rc < 0) return rc;	rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);	if (rc < 0) return rc;	return 0;}/* Write to a specific I2C slave ID and register, using the specified mask */static inti2c_w_slave(struct usb_ov511 *ov,	    unsigned char slave,	    unsigned char reg,	    unsigned char value,	    unsigned char mask){	int rc = 0;	down(&ov->i2c_lock);	/* Set new slave IDs */	rc = i2c_set_slave_internal(ov, slave);	if (rc < 0) goto out;	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);out:	/* Restore primary IDs */	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)		err("Couldn't restore primary I2C slave");	up(&ov->i2c_lock);	return rc;}/* Read from a specific I2C slave ID and register */static inti2c_r_slave(struct usb_ov511 *ov,	    unsigned char slave,	    unsigned char reg){	int rc;	down(&ov->i2c_lock);	/* Set new slave IDs */	rc = i2c_set_slave_internal(ov, slave);	if (rc < 0) goto out;	if (ov->bclass == BCL_OV518)		rc = ov518_i2c_read_internal(ov, reg);	else		rc = ov511_i2c_read_internal(ov, reg);out:	/* Restore primary IDs */	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)		err("Couldn't restore primary I2C slave");	up(&ov->i2c_lock);	return rc;}/* Sets I2C read and write slave IDs. Returns <0 for error */static intov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid){	int rc;	down(&ov->i2c_lock);	rc = i2c_set_slave_internal(ov, sid);	if (rc < 0) goto out;	// FIXME: Is this actually necessary?	rc = ov51x_reset(ov, OV511_RESET_NOREGS);	if (rc < 0) goto out;out:	up(&ov->i2c_lock);	return rc;}static intwrite_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals){	int rc;	while (pRegvals->bus != OV511_DONE_BUS) {		if (pRegvals->bus == OV511_REG_BUS) {			if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)				return rc;		} else if (pRegvals->bus == OV511_I2C_BUS) {			if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)				return rc;		} else {			err("Bad regval array");			return -1;		}		pRegvals++;	}	return 0;}#ifdef OV511_DEBUGstatic voiddump_i2c_range(struct usb_ov511 *ov, int reg1, int regn){	int i, rc;	for (i = reg1; i <= regn; i++) {		rc = i2c_r(ov, i);		info("Sensor[0x%02X] = 0x%02X", i, rc);	}}static voiddump_i2c_regs(struct usb_ov511 *ov){	info("I2C REGS");	dump_i2c_range(ov, 0x00, 0x7C);}static voiddump_reg_range(struct usb_ov511 *ov, int reg1, int regn){	int i, rc;	for (i = reg1; i <= regn; i++) {		rc = reg_r(ov, i);		info("OV511[0x%02X] = 0x%02X", i, rc);	}}static voidov511_dump_regs(struct usb_ov511 *ov){	info("CAMERA INTERFACE REGS");	dump_reg_range(ov, 0x10, 0x1f);	info("DRAM INTERFACE REGS");	dump_reg_range(ov, 0x20, 0x23);	info("ISO FIFO REGS");	dump_reg_range(ov, 0x30, 0x31);	info("PIO REGS");	dump_reg_range(ov, 0x38, 0x39);	dump_reg_range(ov, 0x3e, 0x3e);	info("I2C REGS");	dump_reg_range(ov, 0x40, 0x49);	info("SYSTEM CONTROL REGS");	dump_reg_range(ov, 0x50, 0x55);	dump_reg_range(ov, 0x5e, 0x5f);	info("OmniCE REGS");	dump_reg_range(ov, 0x70, 0x79);	/* NOTE: Quantization tables are not readable. You will get the value	 * in reg. 0x79 for every table register */	dump_reg_range(ov, 0x80, 0x9f);	dump_reg_range(ov, 0xa0, 0xbf);}static voidov518_dump_regs(struct usb_ov511 *ov){	info("VIDEO MODE REGS");	dump_reg_range(ov, 0x20, 0x2f);	info("DATA PUMP AND SNAPSHOT REGS");	dump_reg_range(ov, 0x30, 0x3f);	info("I2C REGS");	dump_reg_range(ov, 0x40, 0x4f);	info("SYSTEM CONTROL AND VENDOR REGS");	dump_reg_range(ov, 0x50, 0x5f);	info("60 - 6F");	dump_reg_range(ov, 0x60, 0x6f);	info("70 - 7F");	dump_reg_range(ov, 0x70, 0x7f);	info("Y QUANTIZATION TABLE");	dump_reg_range(ov, 0x80, 0x8f);	info("UV QUANTIZATION TABLE");	dump_reg_range(ov, 0x90, 0x9f);	info("A0 - BF");	dump_reg_range(ov, 0xa0, 0xbf);	info("CBR");	dump_reg_range(ov, 0xc0, 0xcf);}#endif/*****************************************************************************//* Temporarily stops OV511 from functioning. Must do this before changing * registers while the camera is streaming */static inline intov51x_stop(struct usb_ov511 *ov){	PDEBUG(4, "stopping");	ov->stopped = 1;	if (ov->bclass == BCL_OV518)		return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));	else		return (reg_w(ov, R51x_SYS_RESET, 0x3d));}/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not * actually stopped (for performance). */static inline intov51x_restart(struct usb_ov511 *ov){	if (ov->stopped) {		PDEBUG(4, "restarting");		ov->stopped = 0;		/* Reinitialize the stream */		if (ov->bclass == BCL_OV518)			reg_w(ov, 0x2f, 0x80);		return (reg_w(ov, R51x_SYS_RESET, 0x00));	}	return 0;}/* Resets the hardware snapshot button */static voidov51x_clear_snapshot(struct usb_ov511 *ov){	if (ov->bclass == BCL_OV511) {		reg_w(ov, R51x_SYS_SNAP, 0x00);		reg_w(ov, R51x_SYS_SNAP, 0x02);		reg_w(ov, R51x_SYS_SNAP, 0x00);	} else if (ov->bclass == BCL_OV518) {		warn("snapshot reset not supported yet on OV518(+)");	} else {		err("clear snap: invalid bridge type");	}}#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)/* Checks the status of the snapshot button. Returns 1 if it was pressed since * it was last cleared, and zero in all other cases (including errors) */static intov51x_check_snapshot(struct usb_ov511 *ov){	int ret, status = 0;	if (ov->bclass == BCL_OV511) {		ret = reg_r(ov, R51x_SYS_SNAP);		if (ret < 0) {			err("Error checking snspshot status (%d)", ret);		} else if (ret & 0x08) {			status = 1;		}	} else if (ov->bclass == BCL_OV518) {		warn("snapshot check not supported yet on OV518(+)");	} else {		err("check snap: invalid bridge type");	}	return status;}#endif/* This does an initial reset of an OmniVision sensor and ensures that I2C * is synchronized. Returns <0 for failure. */static intinit_ov_sensor(struct usb_ov511 *ov){	int i, success;	/* Reset the sensor */	if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;	/* Wait for it to initialize */	schedule_timeout(1 + 150 * HZ / 1000);	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {		if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&		    (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {			success = 1;			continue;		}		/* Reset the sensor */		if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;		/* Wait for it to initialize */		schedule_timeout(1 + 150 * HZ / 1000);		/* Dummy read to sync I2C */		if (i2c_r(ov, 0x00) < 0) return -EIO;	}	if (!success)		return -EIO;	PDEBUG(1, "I2C synced in %d attempt(s)", i);	return 0;}static intov511_set_packet_size(struct usb_ov511 *ov, int size){	int alt, mult;	if (ov51x_stop(ov) < 0)		return -EIO;	mult = size >> 5;	if (ov->bridge == BRG_OV511) {		if (size == 0) alt = OV511_ALT_SIZE_0;		else if (size == 257) alt = OV511_ALT_SIZE_257;		else if (size == 513) alt = OV511_ALT_SIZE_513;		else if (size == 769) alt = OV511_ALT_SIZE_769;		else if (size == 993) alt = OV511_ALT_SIZE_993;		else {			err("Set packet size: invalid size (%d)", size);			return -EINVAL;		}	} else if (ov->bridge == BRG_OV511PLUS) {		if (size == 0) alt = OV511PLUS_ALT_SIZE_0;		else if (size == 33) alt = OV511PLUS_ALT_SIZE_33;		else if (size == 129) alt = OV511PLUS_ALT_SIZE_129;		else if (size == 257) alt = OV511PLUS_ALT_SIZE_257;		else if (size == 385) alt = OV511PLUS_ALT_SIZE_385;		else if (size == 513) alt = OV511PLUS_ALT_SIZE_513;		else if (size == 769) alt = OV511PLUS_ALT_SIZE_769;		else if (size == 961) alt = OV511PLUS_ALT_SIZE_961;		else {			err("Set packet size: invalid size (%d)", size);			return -EINVAL;		}	} else {		err("Set packet size: Invalid bridge type");		return -EINVAL;	}	PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);	if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)		return -EIO;	if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {		err("Set packet size: set interface error");		return -EBUSY;	}	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)		return -EIO;	ov->packet_size = size;	if (ov51x_restart(ov) < 0)		return -EIO;	return 0;}/* Note: Unlike the OV511/OV511+, the size argument does NOT include the * optional packet number byte. The actual size *is* stored in ov->packet_size, * though. */static intov518_set_packet_size(struct usb_ov511 *ov, int size){	int alt;	if (ov51x_stop(ov) < 0)		return -EIO;	if (ov->bclass == BCL_OV518) {		if (size == 0) alt = OV518_ALT_SIZE_0;		else if (size == 128) alt = OV518_ALT_SIZE_128;		else if (size == 256) alt = OV518_ALT_SIZE_256;		else if (size == 384) alt = OV518_ALT_SIZE_384;		else if (size == 512) alt = OV518_ALT_SIZE_512;		else if (size == 640) alt = OV518_ALT_SIZE_640;		else if (size == 768) alt = OV518_ALT_SIZE_768;		else if (size == 896) alt = OV518_ALT_SIZE_896;		else {			err("Set packet size: invalid size (%d)", size);			return -EINVAL;		}	} else {		err("Set packet size: Invalid bridge type");		return -EINVAL;	}	PDEBUG(3, "%d, alt=%d", size, alt);	ov->packet_size = size;	if (size > 0) {		/* Program ISO FIFO size reg (packet number isn't included) */		ov518_reg_w32(ov, 0x30, size, 2);		if (ov->packet_numbering)			++ov->packet_size;	}	if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {		err("Set packet size: set interface error");		return -EBUSY;	}	/* Initialize the stream */	if (reg_w(ov, 0x2f, 0x80) < 0)		return -EIO;	if (ov51x_restart(ov) < 0)		return -EIO;	if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)		return -EIO;	return 0;}/* Upload compression params and quantization tables. Returns 0 for success. */static intov511_init_compression(struct usb_ov511 *ov){	int rc = 0;	if (!ov->compress_inited) {		reg_w(ov, 0x70, phy);		reg_w(ov, 0x71, phuv);		reg_w(ov, 0x72, pvy);		reg_w(ov, 0x73, pvuv);		reg_w(ov, 0x74, qhy);		reg_w(ov, 0x75, qhuv);		reg_w(ov, 0x76, qvy);		reg_w(ov, 0x77, qvuv);		if (ov511_upload_quan_tables(ov) < 0) {			err("Error uploading quantization tables");			rc = -EIO;			goto out;		}	}	ov->compress_inited = 1;out:	return rc;}/* Upload compression params and quantization tables. Returns 0 for success. */static intov518_init_compression(struct usb_ov511 *ov){	int rc = 0;	if (!ov->compress_inited) {		if (ov518_upload_quan_tables(ov) < 0) {			err("Error uploading quantization tables");			rc = -EIO;			goto out;		}	}	ov->compress_inited = 1;out:	return rc;}/* -------------------------------------------------------------------------- *//* Sets sensor's contrast setting to "val" */static intsensor_set_contrast(struct usb_ov511 *ov, unsigned short val){	int rc;	PDEBUG(3, "%d", val);

⌨️ 快捷键说明

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