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

📄 ov511.c

📁 用于ARM S3C44B0/S3C4510嵌入式系统的ov511驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	static void	create_proc_ov511_cam(struct usb_ov511 *ov)	{		char dirname[10];		if (!ov511_proc_entry || !ov)			return;		/* Create per-device directory */		snprintf(dirname, 10, "%d", ov->vdev.minor);		PDEBUG(4, "creating /proc/video/ov511/%s/", dirname);		ov->proc_devdir = create_proc_entry(dirname, S_IFDIR, ov511_proc_entry);		if (!ov->proc_devdir)			return;		ov->proc_devdir->owner = THIS_MODULE;		/* Create "info" entry (human readable device information) */		PDEBUG(4, "creating /proc/video/ov511/%s/info", dirname);		ov->proc_info = create_proc_read_entry("info", S_IFREG|S_IRUGO|S_IWUSR,			ov->proc_devdir, ov511_read_proc_info, ov);		if (!ov->proc_info)			return;		ov->proc_info->owner = THIS_MODULE;		/* Don't create it if old snapshot mode on (would cause race cond.) */		if (!snapshot) {			/* Create "button" entry (snapshot button status) */			PDEBUG(4, "creating /proc/video/ov511/%s/button", dirname);			ov->proc_button = create_proc_read_entry("button",				S_IFREG|S_IRUGO|S_IWUSR, ov->proc_devdir,				ov511_read_proc_button, ov);			if (!ov->proc_button)				return;		}		ov->proc_button->owner = THIS_MODULE;		/* Create "control" entry (ioctl() interface) */		PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname);		lock_kernel();		ov->proc_control = create_proc_entry("control",	S_IFREG|S_IRUGO|S_IWUSR,			ov->proc_devdir);		if (!ov->proc_control) {			unlock_kernel();			return;		}		ov->proc_control->owner = THIS_MODULE;		ov->proc_control->data = ov;		ov->proc_control->proc_fops = &ov511_control_fops;		unlock_kernel();	}	static void	destroy_proc_ov511_cam(struct usb_ov511 *ov)	{		char dirname[10];		if (!ov || !ov->proc_devdir)			return;		snprintf(dirname, 10, "%d", ov->vdev.minor);		/* Destroy "control" entry */		if (ov->proc_control) {			PDEBUG(4, "destroying /proc/video/ov511/%s/control", dirname);			remove_proc_entry("control", ov->proc_devdir);			ov->proc_control = NULL;		}		/* Destroy "button" entry */		if (ov->proc_button) {			PDEBUG(4, "destroying /proc/video/ov511/%s/button", dirname);			remove_proc_entry("button", ov->proc_devdir);			ov->proc_button = NULL;		}		/* Destroy "info" entry */		if (ov->proc_info) {			PDEBUG(4, "destroying /proc/video/ov511/%s/info", dirname);			remove_proc_entry("info", ov->proc_devdir);			ov->proc_info = NULL;		}		/* Destroy per-device directory */		PDEBUG(4, "destroying /proc/video/ov511/%s/", dirname);		remove_proc_entry(dirname, ov511_proc_entry);		ov->proc_devdir = NULL;	}	static void	proc_ov511_create(void)	{		/* No current standard here. Alan prefers /proc/video/ as it keeps		 * /proc "less cluttered than /proc/randomcardifoundintheshed/"		 * -claudio		 */		if (video_proc_entry == NULL) {			err("Error: /proc/video/ does not exist");			return;		}		ov511_proc_entry = create_proc_entry("ov511", S_IFDIR,						     video_proc_entry);		if (ov511_proc_entry)			ov511_proc_entry->owner = THIS_MODULE;		else			err("Unable to create /proc/video/ov511");	}	static void	proc_ov511_destroy(void)	{		PDEBUG(3, "removing /proc/video/ov511");		if (ov511_proc_entry == NULL)			return;		remove_proc_entry("ov511", video_proc_entry);	}#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */	/**********************************************************************	 *	 * Register I/O	 *	 **********************************************************************/	/* Write an OV51x register */	static int	reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)	{		int rc;		PDEBUG(5, "0x%02X:0x%02X", reg, value);		down(&ov->cbuf_lock);		ov->cbuf[0] = value;		rc = usb_control_msg(ov->dev,				     usb_sndctrlpipe(ov->dev, 0),				     (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,				     USB_TYPE_VENDOR | USB_RECIP_DEVICE,				     0, (__u16)reg, &ov->cbuf[0], 1, HZ);		up(&ov->cbuf_lock);		if (rc < 0)			err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));		return rc;	}	/* Read from an OV51x register */	/* returns: negative is error, pos or zero is data */	static int	reg_r(struct usb_ov511 *ov, unsigned char reg)	{		int rc;		down(&ov->cbuf_lock);		rc = usb_control_msg(ov->dev,				     usb_rcvctrlpipe(ov->dev, 0),				     (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,				     USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,				     0, (__u16)reg, &ov->cbuf[0], 1, HZ);		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 OV51x 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 int	reg_w_mask(struct usb_ov511 *ov,		   unsigned char reg,		   unsigned char value,		   unsigned char mask)	{		int ret;		unsigned char oldval, newval;		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));	}	/* 	 * Writes multiple (n) byte value to a single register. Only valid with certain	 * registers (0x30 and 0xc4 - 0xce).	 */	static int	ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)	{		int rc;		PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);		down(&ov->cbuf_lock);		*((u32 *)ov->cbuf) = __cpu_to_le32(val);		rc = usb_control_msg(ov->dev,				     usb_sndctrlpipe(ov->dev, 0),				     1 /* REG_IO */,				     USB_TYPE_VENDOR | USB_RECIP_DEVICE,				     0, (__u16)reg, ov->cbuf, n, HZ);		up(&ov->cbuf_lock);		if (rc < 0)			err("reg write multiple: error %d: %s", rc,			    symbolic(urb_errlist, rc));		return rc;	}	static int	ov511_upload_quan_tables(struct usb_ov511 *ov)	{		unsigned char *pYTable = yQuanTable511;		unsigned char *pUVTable = uvQuanTable511;		unsigned char val0, val1;		int i, rc, reg = R511_COMP_LUT_BEGIN;		PDEBUG(4, "Uploading quantization tables");		for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {			if (ENABLE_Y_QUANTABLE)	{				val0 = *pYTable++;				val1 = *pYTable++;				val0 &= 0x0f;				val1 &= 0x0f;				val0 |= val1 << 4;				rc = reg_w(ov, reg, val0);				if (rc < 0)					return rc;			}			if (ENABLE_UV_QUANTABLE) {				val0 = *pUVTable++;				val1 = *pUVTable++;				val0 &= 0x0f;				val1 &= 0x0f;				val0 |= val1 << 4;				rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);				if (rc < 0)					return rc;			}			reg++;		}		return 0;	}	/* OV518 quantization tables are 8x4 (instead of 8x8) */	static int	ov518_upload_quan_tables(struct usb_ov511 *ov)	{		unsigned char *pYTable = yQuanTable518;		unsigned char *pUVTable = uvQuanTable518;		unsigned char val0, val1;		int i, rc, reg = R511_COMP_LUT_BEGIN;		PDEBUG(4, "Uploading quantization tables");		for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {			if (ENABLE_Y_QUANTABLE) {				val0 = *pYTable++;				val1 = *pYTable++;				val0 &= 0x0f;				val1 &= 0x0f;				val0 |= val1 << 4;				rc = reg_w(ov, reg, val0);				if (rc < 0)					return rc;			}			if (ENABLE_UV_QUANTABLE) {				val0 = *pUVTable++;				val1 = *pUVTable++;				val0 &= 0x0f;				val1 &= 0x0f;				val0 |= val1 << 4;				rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);				if (rc < 0)					return rc;			}			reg++;		}		return 0;	}	static int	ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)	{		int rc;		/* Setting bit 0 not allowed on 518/518Plus */		if (ov->bclass == BCL_OV518)			reset_type &= 0xfe;		PDEBUG(4, "Reset: type=0x%02X", reset_type);		rc = reg_w(ov, R51x_SYS_RESET, reset_type);		rc = reg_w(ov, R51x_SYS_RESET, 0);		if (rc < 0)			err("reset: command failed");		return rc;	}	/**********************************************************************	 *	 * Low-level I2C I/O functions	 *	 **********************************************************************/	/* NOTE: Do not call this function directly!	 * The OV518 I2C I/O procedure is different, hence, this function.	 * This is normally only called from i2c_w(). Note that this function	 * always succeeds regardless of whether the sensor is present and working.	 */	static int	ov518_i2c_write_internal(struct usb_ov511 *ov,				 unsigned char reg,				 unsigned char value)	{		int rc;		PDEBUG(5, "0x%02X:0x%02X", reg, value);		/* Select camera register */		rc = reg_w(ov, R51x_I2C_SADDR_3, reg);		if (rc < 0) return rc;		/* Write "value" to I2C data port of OV511 */		rc = reg_w(ov, R51x_I2C_DATA, value);		if (rc < 0) return rc;		/* Initiate 3-byte write cycle */		rc = reg_w(ov, R518_I2C_CTL, 0x01);		if (rc < 0) return rc;		return 0;	}	/* NOTE: Do not call this function directly! */	static int	ov511_i2c_write_internal(struct usb_ov511 *ov,				 unsigned char reg,				 unsigned char value)	{		int rc, retries;		PDEBUG(5, "0x%02X:0x%02X", reg, value);		/* Three byte write cycle */		for (retries = OV511_I2C_RETRIES; ; ) {			/* Select camera register */			rc = reg_w(ov, R51x_I2C_SADDR_3, reg);			if (rc < 0) return rc;			/* Write "value" to I2C data port of OV511 */			rc = reg_w(ov, R51x_I2C_DATA, value);			if (rc < 0) return rc;			/* Initiate 3-byte write cycle */			rc = reg_w(ov, R511_I2C_CTL, 0x01);			if (rc < 0) return rc;			do rc = reg_r(ov, R511_I2C_CTL);			while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */			if (rc < 0) return rc;			if ((rc&2) == 0) /* Ack? */				break;#if 0			/* I2C abort */			reg_w(ov, R511_I2C_CTL, 0x10);#endif			if (--retries < 0) {				err("i2c write retries exhausted");				return -1;			}		}		return 0;	}	/* NOTE: Do not call this function directly!	 * The OV518 I2C I/O procedure is different, hence, this function.	 * This is normally only called from i2c_r(). Note that this function	 * always succeeds regardless of whether the sensor is present and working.	 */	static int	ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)	{		int rc, value;		/* Select camera register */		rc = reg_w(ov, R51x_I2C_SADDR_2, reg);		if (rc < 0) return rc;		/* Initiate 2-byte write cycle */		rc = reg_w(ov, R518_I2C_CTL, 0x03);		if (rc < 0) return rc;		/* Initiate 2-byte read cycle */		rc = reg_w(ov, R518_I2C_CTL, 0x05);		if (rc < 0) return rc;		value = reg_r(ov, R51x_I2C_DATA);		PDEBUG(5, "0x%02X:0x%02X", reg, value);		return value;	}	/* NOTE: Do not call this function directly!	 * returns: negative is error, pos or zero is data */	static int	ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)	{		int rc, value, retries;		/* Two byte write cycle */		for (retries = OV511_I2C_RETRIES; ; ) {			/* Select camera register */			rc = reg_w(ov, R51x_I2C_SADDR_2, reg);			if (rc < 0) return rc;			/* Initiate 2-byte write cycle */			rc = reg_w(ov, R511_I2C_CTL, 0x03);			if (rc < 0) return rc;			do rc = reg_r(ov, R511_I2C_CTL);			while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */			if (rc < 0) return rc;			if ((rc&2) == 0) /* Ack? */				break;			/* I2C abort */			reg_w(ov, R511_I2C_CTL, 0x10);			if (--retries < 0) {				err("i2c write retries exhausted");				return -1;			}		}		/* Two byte read cycle */		for (retries = OV511_I2C_RETRIES; ; ) {			/* Initiate 2-byte read cycle */			rc = reg_w(ov, R511_I2C_CTL, 0x05);			if (rc < 0) return rc;			do rc = reg_r(ov, R511_I2C_CTL);			while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */			if (rc < 0) return rc;			if ((rc&2) == 0) /* Ack? */				break;			/* I2C abort */			rc = reg_w(ov, R511_I2C_CTL, 0x10);			if (rc < 0) return rc;			if (--retries < 0) {				err("i2c read retries exhausted");				return -1;			}		}		value = reg_r(ov, R51x_I2C_DATA);		PDEBUG(5, "0x%02X:0x%02X", reg, value);		/* This is needed to make i2c_w() work */		rc = reg_w(ov, R511_I2C_CTL, 0x05);		if (rc < 0)			return rc;		return value;	}	/* returns: negative is error, pos or zero is data */	static int	i2c_r(struct usb_ov511 *ov, unsigned char reg)	{		int rc;		down(&ov->i2c_lock);		if (ov->bclass == BCL_OV518)			rc = ov518_i2c_read_internal(ov, reg);		else			rc = ov511_i2c_read_internal(ov, reg);

⌨️ 快捷键说明

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