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

📄 can.c

📁 2410linux下的CAN驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		} else {		//发送标准帧
			setcanport( canid,REG_FRAME_BID1,(send_buf[i].ID&0x000007f8)>>3 );
			setcanport( canid,REG_FRAME_BID2,(send_buf[i].ID&0x00000007)<<5 );
						
			if (send_buf[i].RemoteFlag==1) {	//远程帧
				setcanport(canid, REG_FRAME_INFO, send_buf[i].DataLen+0x40);
			} else {	//数据帧
				setcanport(canid, REG_FRAME_INFO, send_buf[i].DataLen);
				for (j=0;j<8;++j) 
					setcanport(canid, REG_FRAME_BDATA1+j, send_buf[i].Data[j]);
			}
		}
		
		setcanport(canid,REG_COMMAND,TR_CMD);	//发送数据
		if(  (getcanport(canid, REG_STATUS)&0x08)==0  ) {	//发送未完成
			interruptible_sleep_on_timeout(&canwrite_wq[canid],HZ);	//等待发送完成
			if(  (getcanport(canid, REG_STATUS)&0x08)==0  )	//不成功
				break;
		} 
		//printk("send success\n"); ///////////////////
		++write_num;	//发送成功数加一
	}
	
	up(&canwrite_sem[canid]);
	return write_num;
}

/*********************************************************************************************************
** 函数名称: config_can
** 功能描述: 设置CAN
** 输 入: chanal CAN设备号, pInitConfig 配置项
** 输 出: 无
********************************************************************************************************/
static void config_can(int chanal, PMCNET_INIT_CONFIG pInitConfig)
{
	unsigned char val ;
	
	val = ((pInitConfig->Filter)<<3)+0x01;	//设置滤波模式并进入复位状态
	do {  
		setcanport(chanal,REG_CONTROL,val);
    } while( (getcanport(chanal,REG_CONTROL)&0x1f)!=val );
    
	do {  
		setcanport(chanal,REG_INT_CONTROL, 0x0f);	
    } while( getcanport(chanal,REG_INT_CONTROL)!=0x0f );
	
	//setcanport(chanal, REG_INT_CONTROL, 0x0f);		//设置中断使能
	setcanport(chanal, REG_BTR0, pInitConfig->Timing0);		//设置波特率
    	setcanport(chanal, REG_BTR1, pInitConfig->Timing1);
	//设置滤波相关寄存器
	setcanport( chanal,REG_ACR0, pInitConfig->AccCode&0x000000ff );
	setcanport( chanal,REG_ACR1, (pInitConfig->AccCode&0x0000ff00)>>8 );
	setcanport( chanal,REG_ACR2, (pInitConfig->AccCode&0x00ff0000)>>16 );
	setcanport( chanal,REG_ACR3, (pInitConfig->AccCode&0xff000000)>>24 );
	setcanport( chanal,REG_AMR0, pInitConfig->AccMask&0x000000ff );
	setcanport( chanal,REG_AMR1, (pInitConfig->AccMask&0x0000ff00)>>8 );
	setcanport( chanal,REG_AMR2, (pInitConfig->AccMask&0x00ff0000)>>16 );
	setcanport( chanal,REG_AMR3, (pInitConfig->AccMask&0xff000000)>>24 );
	//设置错误计数相关寄存器
	setcanport(chanal, REG_ERR_MAX, 0xff);
	setcanport(chanal, REG_RX_ERR, 0x00);
	setcanport(chanal, REG_TX_ERR, 0x00);
	//设置输出和时钟寄存器
   	 setcanport(chanal,REG_OCR,0xda);
    	setcanport(chanal,REG_CDR,0xc8);
    
    //test_greg(chanal);
    //test_freg(chanal);

    val = getcanport(chanal,REG_CONTROL)&0xfe;	//进入工作状态
	do {
		setcanport(chanal, REG_CONTROL,val );
	} while( (getcanport(chanal,REG_CONTROL)&0x1f)!=val );
   
	return ;
}

/*********************************************************************************************************
** 函数名称: ioctl_can
** 功能描述: 
** 输 入: 无
** 输 出: 无
********************************************************************************************************/
static int ioctl_can(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
	int i,j,canid;
		
	canid = (int)filp->private_data;
	copy_from_user( &InitConfig, (void *)arg, sizeof(MCNET_INIT_CONFIG) );
	
	//printk("canid:%d  time0:%.2x  time1:%.2x  acr:%.8x  amr:%.8x   filter:%d  mode:%d", canid, InitConfig.Timing0,     ///////////////////////
	//			InitConfig.Timing1, InitConfig.AccCode, InitConfig.AccMask, InitConfig.Filter, InitConfig.Mode);  					  ///////////////////////
	
	switch (cmd) {
		case IOC_CAN_INIT:
			clearrcvbuf(canid);
			config_can(canid,&InitConfig);
			break;
		case IOC_CAN_RESET:
			clearrcvbuf(canid);
			config_can(canid,&InitConfig);
			break;
		case IOC_CAN_EXIT:
			//进入复位状态
			do {  
				setcanport(canid,REG_CONTROL,0x01);
			} while( (getcanport(canid,REG_CONTROL)&0x1f)!=0x01 );
			break;
		case	IOC_CAN_GETRCVNUM:
			(*((int *)arg)) = getrcvbufnum(canid);
			//printk("canid:%d rcvnum:%d\n", canid, (*((int *)arg)) );
			break;
		default:
			break;
	}
	
	//test_greg(canid);
	//test_wreg(canid);
    return 0;
}

/*********************************************************************************************************
** 函数名称: open_can
** 功能描述: 
** 输 入: 
** 输 出: 
********************************************************************************************************/
static int open_can(struct inode *inode,struct file *filp)
{   
    filp->private_data = (void *)MINOR(inode->i_rdev);		//次设备号保存至file结构中
    
    MOD_INC_USE_COUNT;
    return 0;
}

/*********************************************************************************************************
** 函数名称: release_can
** 功能描述: 
** 输 入: 
** 输 出: 
********************************************************************************************************/
static int release_can(struct inode *inode,struct file *filp)
{
    MOD_DEC_USE_COUNT;
    return 0;
}
/*********************************************************************************************************
** 函数名称: can_handler
** 功能描述: can控制器中断处理函数
** 输 入: 无
** 输 出: 无
** 全局变量: 无
** 调用模块: 无
********************************************************************************************************/
static void can_handler( int irq, void *dev_id, struct pt_regs *regs)
{
	int canid, i;
	unsigned char temp, val;
	unsigned int id1, id2, id3, id4;
	//注意:CAN0对应IRQ17, CAN1对应IRQ16
	if( irq==IRQ_EINT17 )
		canid=0;
	else if( irq==IRQ_EINT16 )
		canid=1;
	temp = getcanport(canid, REG_INTERRUPT);	//读中断寄存器的值
	
	if ( (temp&0x01) != 0) {		//接收中断
		printk("can%d receive irq occured.\n", canid);	
//		printk( "before  canid:%d   write point:%d,  read point:%d", canid, CANRcvBuf[canid].WritePoint, CANRcvBuf[canid].ReadPoint );
		wake_up_interruptible(&canread_wq[canid]);	//通知数据到来

		if( 0==CANRcvBuf[canid].FullFlag )	{	//缓冲区未满
			val = getcanport(canid, REG_FRAME_INFO);
			if ( (val&0x80)!=0 ) {	//扩展帧
				CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].ExternFlag = 1;
				
				id1 = getcanport(canid, REG_FRAME_PID1);
				id2 = getcanport(canid, REG_FRAME_PID2);
				id3 = getcanport(canid, REG_FRAME_PID3);
				id4 = getcanport(canid, REG_FRAME_PID4);
				CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].ID =
						(id1<<21)+(id2<<13)+(id3<<5)+(id4>>3);

				if ( (val&0x40)!=0 ) {		//远程帧
					CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].RemoteFlag = 1;
					CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].DataLen = 0;
				} else {	//数据帧
					CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].RemoteFlag = 0;
					CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].DataLen = (val&0x0f);
					for(i=0;i<8;++i)
						CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].Data[i] = 
							getcanport(canid, REG_FRAME_PDATA1+i);	
				}
			} else {				//标准帧
				CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].ExternFlag = 0;
								
				id1 = getcanport(canid, REG_FRAME_BID1);
				id2 = getcanport(canid, REG_FRAME_BID2);
				CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].ID =
						(id1<<3)+(id2>>5);

				if ( (val&0x40)!=0 ) {		//远程帧
					CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].RemoteFlag = 1;
					CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].DataLen = 0;
				} else {	//数据帧
					CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].RemoteFlag = 0;
					CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].DataLen = (val&0x0f);
					for(i=0;i<8;++i)
						CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].WritePoint].Data[i] = 
							getcanport(canid, REG_FRAME_BDATA1+i);
				}
			}
			
			if( ++CANRcvBuf[canid].WritePoint>=CAN_RCV_BUF_SIZE ) 	
				CANRcvBuf[canid].WritePoint = 0;
			if( CANRcvBuf[canid].WritePoint==CANRcvBuf[canid].ReadPoint )	//缓冲区是否已满
				CANRcvBuf[canid].FullFlag =1;
		}
	//	printk( "canid:%d   write point:%d,  read point:%d", canid, CANRcvBuf[canid].WritePoint, CANRcvBuf[canid].ReadPoint );
		setcanport(canid,REG_COMMAND,RRB_CMD);      //释放接收缓冲区
    } 
	
	if ( (temp&0x02) != 0) {		//发送中断
		printk("can%d send irq occured.\n", canid);
		wake_up_interruptible( &canwrite_wq[canid] );
	}

	if ( (temp&0x04) != 0) {		//错误报警中断
		printk("can%d err irq occured.\n", canid);
		//config_can(canid,&InitConfig);
	}

	if ( (temp&0x08) != 0) {		//数据溢出中断
		printk("can%d overflow irq occured.\n", canid);
		//setcanport(canid,REG_COMMAND,COS_CMD);      //free overflow memory
	}
}

/**************************************
** 文件函数指针结构: can_fops
** 
***************************************/
static struct file_operations can_fops={
	read :		read_can,
  	write:		write_can,
  	ioctl:			ioctl_can,
	open:		open_can,
	release:		release_can,
	owner:		THIS_MODULE,
};

/******************************************************
**  函数名称:init_module
**  功能描述:模块初始化函数
**  输入:无
******************************************************/
static int __init can_init(void)
{
	int ret;
	
	sema_init( &canread_sem[0], 1 );
	sema_init( &canwrite_sem[0], 1 );
	init_waitqueue_head( &canread_wq[0] );
	init_waitqueue_head( &canwrite_wq[0] );
	sema_init( &canread_sem[1], 1 );
	sema_init( &canwrite_sem[1], 1 );
	init_waitqueue_head( &canread_wq[1] );
	init_waitqueue_head( &canwrite_wq[1] );
	//注意:CAN0对应IRQ17, CAN1对应IRQ16
	set_external_irq( IRQ_EINT16, EXT_RISING_EDGE, GPIO_PULLUP_DIS);
	set_external_irq( IRQ_EINT17, EXT_RISING_EDGE, GPIO_PULLUP_DIS);
	ret = request_irq( IRQ_EINT16,can_handler,SA_INTERRUPT,"can1",NULL );
	if (ret<0) {
		printk("sorry, can1 irq registation failed.\n");
		return ret;
	} 
	ret = request_irq( IRQ_EINT17,can_handler,SA_INTERRUPT,"can0",NULL );
	if (ret<0)  {
		printk("sorry, can0 irq registation failed.\n");
		return ret;
	}  
	
	 dev_handle[0] = devfs_register( NULL, "can0", DEVFS_FL_DEFAULT, CAN_MAJOR, 0, 
	 							S_IFCHR, &can_fops, (void *)0 );//|S_IRUGO|S_IWUGO
	 dev_handle[1] = devfs_register( NULL, "can1", DEVFS_FL_DEFAULT, CAN_MAJOR, 1, 
	 							S_IFCHR, &can_fops, (void *)1 );
	
	 canaddr[0]= ioremap(0x28000000,0x20);
    	 canaddr[1]= ioremap(0x28400000,0x20);
	 
	printk("congraulation, can are successful registed.\n");
	return 0;
}

/*******************************************************
**  函数名称:can_clear
**  功能描述:模块卸载函数
**  输入:无
******************************************************/
static void __exit can_clear(void)
{
     	iounmap(canaddr[0]);
  	iounmap(canaddr[1]);
   	//注意:CAN0对应IRQ17, CAN1对应IRQ16
	free_irq(IRQ_EINT16,NULL);
	free_irq(IRQ_EINT17,NULL);
		   	
	devfs_unregister (dev_handle[0]);
	devfs_unregister (dev_handle[1]);
  	
  	printk("exit can successfully.\n");
}


MODULE_LICENSE("GPL");

module_init(can_init);
module_exit(can_clear);

⌨️ 快捷键说明

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