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

📄 csi.c

📁 linux下基于Arm9的嵌入式linux摄像头接口驱动。非常实用的源码!
💻 C
📖 第 1 页 / 共 2 页
字号:
	int korder;
	int required_pages;
	int extra_pages;

//alloc a tmp buffer in kernel space
	required_pages = byte_size >> PAGE_SHIFT;
	for (korder = 0 ; required_pages >> korder ; korder++) {;}
	extra_pages = (1 << korder) - required_pages;
	_kbuf = (unsigned int *)__get_free_pages(GFP_KERNEL, korder);
	if(!_kbuf)
	{
		printk("csi error: buffer alloc failed\n");
		return -1;
	}
	
//poll sof
	_reg_CSI_CSISR = BIT_SOF_INT;
	while(!(_reg_CSI_CSISR & BIT_SOF_INT));
	_reg_CSI_CSISR = BIT_SOF_INT;

//clear fifo overflow
	if(_reg_CSI_CSISR & BIT_RFF_OR_INT)
		_reg_CSI_CSISR = BIT_RFF_OR_INT;

//read rx fifo
	j = 0;
	while(1)
	{
	//overflow check
		if(_reg_CSI_CSISR & BIT_RFF_OR_INT)
		{
//			printk("csi error: overflow\n");
			_reg_CSI_CSISR = BIT_RFF_OR_INT;
		}
	//poll rx fifo full
		if(_reg_CSI_CSISR & BIT_RXFF_INT)
		{
			for(i = 0; i < g_csi_cfg.rxff_level; i ++)
				_kbuf[j ++] = _reg_CSI_CSIRXR;
		}
		if(j >= word_size)
			break;
	}
	copy_to_user(_buf, _kbuf, byte_size);

	free_pages((int)_kbuf, korder);
	_kbuf = 0;

	return 0;
}


static void csihw_reset_frame_count(void)
{
	_reg_CSI_CSICR3 |= BIT_FRMCNT_RST;
	return;
}


static int csihw_get_frame_count(void)
{
	int count;
	count = _reg_CSI_CSICR3 >> SHIFT_FRMCNT;

	return count;
}


//block until eof is detected
//not to be used with prp
static int csihw_pol_eof(int rxcnt)
{
	int cnt = 0;
	int trial_cnt = 10000000;
	
	if(rxcnt != 0)
	{
		//use this rxcnt
		_reg_CSI_CSIRXCNT = rxcnt;
	}
	else
	{
		//otherwise use the rxcnt in csi config
		_reg_CSI_CSIRXCNT = g_csi_cfg.rxcnt;
	}
	
//clear interrupt first
	if(_reg_CSI_CSISR & BIT_EOF_INT)
		_reg_CSI_CSISR = BIT_EOF_INT;
	
	while(1)
	{
		if(_reg_CSI_CSISR & BIT_EOF_INT)
		{
			_reg_CSI_CSISR = BIT_EOF_INT;
			break;
		}
		else
		{
			if(cnt ++ > trial_cnt)
			{
//				printk("csi err: eof timeout\n");
				return 1;
			}
		}
	}

	return 0;
}


//block until sof is detected
static int csihw_pol_sof(void)
{
	int cnt = 0;
	int trial_cnt = 10000000;
	
//clear interrupt first
	if(_reg_CSI_CSISR & BIT_SOF_INT)
		_reg_CSI_CSISR = BIT_SOF_INT;
	
	while(1)
	{
		if(_reg_CSI_CSISR & BIT_SOF_INT)
		{
			_reg_CSI_CSISR = BIT_SOF_INT;
			break;
		}
		else
		{
			if(cnt ++ > trial_cnt)
			{
				printk("csi err: sof timeout\n");
				return 1;
			}
		}
	}

	return 0;
}



static void csihw_clock_enable(void)
{
//turn on hclk & perclk4
//caution -- if sensor clock (mclk) is provided by csi,
//           make sure csi is resumed before sensor is resumed

	_reg_CRM_PCCR0 |= 0x80000000;
	if(g_csi_ver == 2)
		_reg_CRM_PCCR0 |= 0x00400000;
	
	return;	
}


static void csihw_clock_disable(void)
{
//shutdown hclk & perclk4
//caution -- if sensor clock (mclk) is provided by csi,
//           make sure the sensor is suspend before csi is suspend

	_reg_CRM_PCCR0 &= ~0x80000000;
	if(g_csi_ver == 2)
		_reg_CRM_PCCR0 &= ~0x00400000;

	return;
}


//csi reset, really can reset??
static void csihw_reset(void)
{
	csihw_clock_enable();
	
	_reg_CSI_CSICR1 = CSICR1_RESET_VAL;
	_reg_CSI_CSICR2 = CSICR2_RESET_VAL;
	if(g_csi_ver == 2)
	{
		_reg_CSI_CSICR3 = CSICR3_RESET_VAL;
			//need to enable hclk before CSICR3 can be access
	}

	return;
}

/*******************************************************************************
*---------------------------- LINUX OS SPECIFIC -------------------------------
*/

//global static
static devfs_handle_t devfs_handle = NULL;
static int gMajor = 0;
static struct pm_dev *pmdev;
static struct apmc_user *g_csi_apmc;


//functions and interface
static int csi_open(struct inode *inode, struct file *filp);
static int csi_release(struct inode *inode, struct file *filp);
static ssize_t csi_read(struct file *filp, char *buf, size_t size, loff_t *l);
static ssize_t csi_write(struct file *filp, const char *buf, size_t size, loff_t *l);
static int csi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
static int csi_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data);


struct file_operations csi_fops = 
{
	open:		csi_open,
	release:	csi_release,
	read:		csi_read,
	write:		csi_write,
	ioctl:		csi_ioctl,
};


/**
*@brief	The module entry function of the CSI driver.
*       It does only the basic things such as csihw_init() and register_chrdev().
*       Module clock is turned on in open().
*       DMA & IRQ are turned on later in the function csihw_config().
*
*@return      @li    0     Success
*                 @li     others     Failure
*/
int __init init_module()
{
	int result;

	printk("Motorola CSI Linux driver ver 0.1\n"
		" - Copyright (C) 2004 Motorola Inc\n\n");

	csihw_init();

//register CSI character device
 	result = devfs_register_chrdev(0, "csi", &csi_fops);
 	if ( result < 0 )
 	{
		printk("csi error: unable to register chr driver\n");
		return -ENODEV;
	}
	devfs_handle = devfs_register(NULL, "csi", DEVFS_FL_DEFAULT,
				      result, 0,
				      S_IFCHR | S_IRUSR | S_IWUSR,
				      &csi_fops, NULL);
	if(devfs_handle == NULL)
	{
		printk("csi error: unable to register driver\n");
		return -ENODEV;
	}
	gMajor = result;
	g_csi_busy = 0;

//power management
	if ((pmdev = pm_register(PM_CSI_DEV, PM_SYS_UNKNOWN, csi_pm_handler)) == NULL)
	{
		printk("csi error: failed to register PM... continuing with driver init\n");
	}
	g_csi_apmc = apmc_register(APMC_LEVEL_HIGHEST);

   	return 0;
}


/**
*@brief	The module exit function of the CSI driver.
*
*@return   NULL
*/
void __exit cleanup_module()
{ 
	csihw_cleanup();

	apmc_unregister(g_csi_apmc);
	pm_unregister(pmdev);

   	if(gMajor > 0)
   	{
		if(devfs_unregister_chrdev(gMajor, "csi") < 0)
		{
			printk("csi error: failed to unregister from devfs\n");
			return;
		}
	}
	if(devfs_handle != NULL)
		devfs_unregister(devfs_handle);
	else
	{
		printk("csi error: failed to unregister from devfs, devfs_handle = 0x%08X\n", (int)devfs_handle);
		return;
	}

	printk("CSI driver is unloaded sucessfully\n");
	
	return;
}

/**
*@brief	Open the CSI 
*
*@param	 inode structure inode list pointer
*@param filp structure file list pointer
*@return 0
*/
static int csi_open(struct inode *inode, struct file *filp)
{
	csihw_open();
	
        MOD_INC_USE_COUNT;
 	return 0;
}

/**
*@brief	Release the CSI 
*
*@param	 inode structure inode list pointer
*@param filp structure file list pointer
*@return 0
*/
static int csi_release(struct inode *inode, struct file *filp)
{
	csihw_release();

        MOD_DEC_USE_COUNT;
	return 0;	
}

/**
*@brief	This function is to read the data from the CSI client device through the CSI interface.
*       Reading the data by calling the function csihw_poll().
*
*@param filp   structure file list pointer
*@param	 buf   the buffer to store the data
*@param size   size of the buffer, the number of bytes
*@param l   loff_t type pointer, not used
*@return  0
*/
static ssize_t csi_read(struct file *filp, char *buf, size_t size, loff_t *l)
{
	g_csi_busy = 1;
	csihw_poll((unsigned int *)buf, (int)size);
	g_csi_busy = 0;
	
	return 0;
}

/**
*@brief	This function is only called when "csi error: write ioctl is not implemented" happens.
*       csi_write() includes only a statement "printk" because it's unnecessary to write to a CSI client device.
*
*@param filp   structure file list pointer
*@param	 buf   the buffer to store the data
*@param size   size of the buffer
*@param l   the register number in the I2C slave (SSI sensor)
*@return -1
*/
static ssize_t csi_write(struct file *filp, const char *buf, size_t size, loff_t *l)
{
	printk("csi error: write ioctl is not implemented\n");
	return -1;
}

/**
*@brief	CSI ioctl operation
*
*There are five kinds of commands
*@li IOCTL_CSI_READ_CONFIG
*@li IOCTL_CSI_CONFIG
*@li IOCTL_CSI_READ_STATUS
*@li IOCTL_CSI_GET_FRMCNT
*@li IOCTL_CSI_RST_FRMCNT
*
*@param	 inode   structure inode list pointer
*@param filp   structure file list pointer
*@param cmd  The command to control the codec.
*@param arg   The void pointer used to communicate with user space.
*@return      @li 0          Success
*                 @li others     Failure
*/
static int csi_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
	switch(cmd)
	{
		case IOCTL_CSI_READ_CONFIG:
		{
			csihw_read_config(&g_csi_cfg);

			if(copy_to_user((void *)arg, (void *)&g_csi_cfg, sizeof(CSI_CFG)))
				return -EFAULT;

			break;
		}
		case IOCTL_CSI_CONFIG:
		{
			if(copy_from_user((void *)&g_csi_cfg, (void *)arg, sizeof(CSI_CFG)))
				return -EFAULT;

			csihw_config(&g_csi_cfg);

			break;
		}
		case IOCTL_CSI_READ_STATUS:
		{
			csihw_read_status(&g_csi_status);

			if(copy_to_user((void *)arg, (void *)&g_csi_status, sizeof(CSI_STATUS)))
				return -EFAULT;
			
			break;
		}
		case IOCTL_CSI_GET_FRMCNT:
		{
			int count;
			count = csihw_get_frame_count();
			if(copy_to_user((void *)arg, (void *)&count, sizeof(int)))
				return -EFAULT;
			
			break;
		}
		case IOCTL_CSI_RST_FRMCNT:
		{
			csihw_reset_frame_count();
			
			break;
		}
		case IOCTL_CSI_POLL_EOF:
		{
			csihw_pol_eof(arg);	//block
			
			break;
		}
		case IOCTL_CSI_POLL_SOF:
		{
			csihw_pol_sof();	//block
			
			break;
		}
		case IOCTL_CSI_RESET:
		{
			csihw_reset();
			
			break;
		}
	}
	
	return 0;
}


static int csi_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data)
{
	switch(rqst)
	{
		case PM_SUSPEND:
		{
			if(g_csi_busy)
			{
				//does not allow suspend when there is a data transfer between csi fifo & memory
				return 1;
			}
			else
			{
				csihw_clock_disable();
//				printk("csi: suspend\n");
			}
			break;
		}
		case PM_RESUME:
		{
			csihw_clock_enable();
//			printk("csi: resume\n");
			break;
		}
	}
	
	return 0;
}

/**@}*/

⌨️ 快捷键说明

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