mycan.c

来自「基于MCF2812的FLEXCAN总线驱动程序」· C语言 代码 · 共 370 行

C
370
字号
#define CONFIG_M5282 //added
#define CONFIG_CLOCK_20MHz //added
#define CONFIG_COLDFIRE//added


#ifndef	__KERNEL__
#define	__KERNEL__
#endif

#ifndef	MODULE
#define	MODULE
#endif

#ifdef	MODULE
	#include <linux/module.h>
	#include <linux/version.h>
#else
	#define MOD_INC_USE_COUNT
	#define MOD_DEC_USE_COUNT
#endif

#include <asm/coldfire.h>
#include <asm/mcfsim.h>

#include <linux/kernel.h>
#include "sched.h"
#include <linux/interrupt.h>

#include <linux/poll.h>		//for select
#include <asm/delay.h>
#include "mycan.h"

DECLARE_TASKLET(bh_can_data,get_can_data,0);


volatile unsigned char user_open = 0;
void can_release(void);
int can_open(struct inode *inode, struct file *file);
int can_close(struct inode *inode, struct file *file);
ssize_t can_read(struct file *file,char *buf,size_t count,loff_t *loff);
unsigned int can_select(struct file *file, struct poll_table_struct *wait);
ssize_t can_write( struct file *file, const char *buf, size_t count, loff_t *loff);

struct file_operations can_fops = {
    read:		can_read,
    write:		can_write,
    poll:		can_select,
    open:		can_open,
    release:	can_close,
};


//................file operations................


ssize_t can_write( struct file *file, const char *buf, size_t count, loff_t *loff)
{

		can_obj *pcan;
		unsigned short i=1;
				pcan = (can_obj *)(MCFFLEXCAN_BASE+0x80+0x10*i);
    
				//Writing the Control/Status word to hold Tx MB inactive (code = 1000)
			  pcan->bid.code = 0x8;   
				//Writing the ID_HIGH and ID_LOW words.
				pcan->bid.id0=0;
				pcan->bid.id15=0;
				pcan->bid.id18=0;
				pcan->bid.srr=1;
				pcan->bid.ide=1;
				pcan->bid.rtr=0;
				//* Writing the Data bytes "MYCAN!"
                pcan->msg= "MYCAN!" ;
				printk("Sending....\n");
			// Writing the Control/Status word (cold=1100, active Code, Length=7)	
			pcan->bid.code = 0xc; pcan->bid.length=0x7;
			printk("Sending completed!\n");

	return -EIO;
}		//write function to be implemented


ssize_t can_read(struct file *file,char *buf,size_t count,loff_t *loff)
{
		can_obj *pcan;
		unsigned short i;
		char msg[9];

		for(i=3;i<=15;i++)
		{
			pcan = (can_obj *)(MCFFLEXCAN_BASE+0x80+0x10*i);
			if(( int len=(int)pcan->bid.length )!=0)   //if the box is not empty
			{
				int j;
				for(j=0;j<len;j++)
				{
					msg[j]=pcan->msg[j];
				}
				
				printk("There are %d words in the message box %d,it is:\n",len,i);
				printk(msg);//...........??? to be checked in linux

				pcan->bid.code = 0x4;  // set active and empty
				return -EIO;
			}
			
		}
				
        printk("No message in every box!\n");
	return -EIO;			//read function to be implemented
	
}

unsigned int can_select(struct file *file, struct poll_table_struct *wait)  //检查是否可读或可写
//一般用于程序询间设备是否可读和写,或是否一个“异常”条件发生了。如果指针为NULL,系统假设设备总是可读和可写的.而且没有异常需要处理。
{
	unsigned int mask=0;
	unsigned int minor = file->f_dentry->d_inode->i_rdev;//设备的从设备好
	poll_wait(file,&read_wq[minor],wait);//将当前进程进入等待队列排队
	if(user_mes[minor].head != user_mes[minor].tail)
		mask |= POLLIN|POLLRDNORM;//管道能无阻塞可读
	mask |= POLLOUT|POLLWRNORM;	//管道能无阻塞可写
	return mask;
}

// ................can open and close..................

int can_open(struct inode *inode, struct file *file)
{
	int	minor=MINOR(inode->i_rdev);
	file->f_dentry->d_inode->i_rdev = minor;
	if(!user_open)	//一个子设备也没有devserver open 队列初始化
	{
		user_mes[0].head = user_mes[0].tail = 0;
		user_mes[1].head = user_mes[1].tail = 0;
		//rx_buf.head = rx_buf.tail = 0;
		
		if(can_init()<0) return -ENXIO;//CAN的初始化
		init_waitqueue_head(&read_wq[0])	;//载入进程
		init_waitqueue_head(&ack_wq);
	}
	
	file->f_op = &can_fops; //the interrupt-driven 程序首地址

	MOD_INC_USE_COUNT;    //用户数+1
	user_open |= 1<<minor;
	return 0;
}

int can_close(struct inode *inode, struct file *file)
{
	unsigned int minor = file->f_dentry->d_inode->i_rdev;
	printk("can_close enter\n");
	if(user_open&(1<<minor))
	{
		user_open &= ~(1<<minor);
		MOD_DEC_USE_COUNT;     //用户数-1
		if(!user_open) can_release();
		return 0;
	}
	return -EBADF;
}
//.........................intterupt.........................




volatile unsigned short rec_mask=0;


void can_interrupt(int irq,void *dev_id,struct pt_regs *ptregs)
{
	//136,137,138 map to mb0~mb2	tx-buf no interrupt 153,154,155 map to error bus wakeup

	
	if(irq>138 && irq<152)
	{
		char code;
		can_obj *pcan;
		unsigned short i=3;
		unsigned short mask = 0x8;	//from mb 3 start
		while(pCanBase->iflag & 0xfff8)
		{
			if(pCanBase->iflag & mask)
			{
				pcan = (can_obj *)(MCFFLEXCAN_BASE+0x80+0x10*i);
    			code =pcan->bid.code; //
				pcan->bid.code = 0;   //message buffer is not active
				if(code == 2 ||code == 6)//if full
				{
					rec_mask |= mask;
					tasklet_schedule(&bh_can_data);
				}
				pCanBase->iflag |= mask;		//clear iflag;
			}
			mask = mask<<1;	i++;
		}
	}
	else if(irq == 152)	//收发错误中断
	{
		pCanBase->estat &= 0xfc;
		printk("estate txerr rxerr %x %x %x\n",pCanBase->estat,pCanBase->txectr,pCanBase->rxectr);
	}
	else if(irq == 153)	//总线中断
	{
		can_init();
	}
	else
		printk("candrv unknown interrupt source %d\n",irq);
}









//..................................CAN cleanup and init//////////////
#ifdef	MODULE
void cleanup_module(void)//在模块被卸载时调用,负责进行设备驱动程序的清除工作。
                        //仅当模块被下载前才被调用,好像它跟内核说: "我不在这里了,别调用我了"
{
	can_release();//释放申请的I/O地址
	unregister_chrdev(CAN_MAJOR, "cancard");//注销登记的字符设备
}

extern	int	init_module(void)//供insmod在加载此模块的时候自动调用,负责进行设备驱动程序的初始化工作。
                             //init_module返回0以表示初始化成功,返回负数表示失败。
							 //init_module为以后调用模块的函数做准备.好像在说:"我在这里这是我能做的" 
#else
extern	int	candrv_init(void)
#endif
{
	int i;
	if(register_chrdev(100, "cancard",&can_fops)< 0)//若小于0,则无法申请此设备号,返回负数
	{
	 	printk("CAN driver can't get Major %d\n", CAN_MAJOR);
  		return(-EIO);
	}
	printk(KERN_INFO"MCF5282 CAN Driver " __DATE__  " " __TIME__ "\n");
	printk(KERN_INFO"emc lib eme8@tsinghua.edu.cn\n");
	DisableInterrupt();//中断无效
	for(i = 136; i < 155; i++)
	{
		if(request_irq(i,can_interrupt,SA_SHIRQ, "cancard",NULL)<0)//申请中断号
		{
	    		printk(KERN_INFO "candrv_init: can't get irq %i\n",i);//得不到所要申请的硬件中断号	
	    		return -1;
   		}
	}
	for(i=0;i<19;i++)//interrupt
	{
		((volatile unsigned char*)(MCF_MBAR+0xd48+i)) =0x3f; //赋值操作Interrupt Control Register 1 08 to 26 优先级等
         //volatile是C++关键字,是一个声明变量时用的修饰符,说明这个变量有可能被其他的线程或者中断等外部条件改变。如果在多线程环境中,线程间共享变量应该用这个修饰符。
	 }
	*((volatile unsigned long *)(MCF_MBAR+0xd0c)) = 0xf80000fe;	//赋值操作Interrupt Mask Register
	//for(i=0;i<MAX_SLAVE_ADDR;i++)	can_dev[i] = LINK_OFF;//终止驱动
	return 0;
}




///////////////////////////////////////--refer by others--------------===========
/*can_init函数:初始化Memory Map,除了Rx Error Counter和Tx Error Counter没有初始化外,其他的都初始化赋值了。先初始化Message Buffer Structure,再初始化Message Buffer Memory Map步骤如下:
1.将引脚AS2,AS3,AS4,AS5作为primary function引脚(P548)。IPSBAR=0x40000000(P184)
2.初始化寄存器CANMCR:先中止CAN时钟,然后进行软件复位,复位失败则跳出初始化函数。
3.设置控制寄存器0:允许Buss off中断,并设置收发引脚的配置控制(0为显性,1为隐性)
4.设置控制寄存器1:Sampling mode为0,设置Propagation segment time为5个时钟周期(时钟周期为多少?)
5.设置控制寄存器2:其值为:1110_0100B。Resynchronizaton Jump Width=4个周期,length of phase buffer segment 1=5个周期,length of phase buffer segment 2=5个周期
6.通过配置寄存器PRESDIV,设置S-clock的大小为:系统频率的1/4(系统频率为多少?)
7.设置RXGMASK, RX14MASK, and RX15MAS:1_1111_0000_0000(h) 0(l):MB4-Id(设置收发ID?)
8.定义Message Buffers的收发情况:0~2为发,3~15为收
9.初始化中断标志位iflag和屏蔽位imask(收发后BUFFER0,BUFFER1,BUFFER2不产生中断,其他的BUFFER产生中断——即收到信号后产生中断,发送后不产生中断)
10.初始化estat:初始化错误状态和总线状态
11.通过CANMCR激活CAN
12.显示几个初始化寄存器的值
**********************************************************************************************************************
**********************************************************************************************************************
reset_rx_mb函数:将对应的Buffern设置为“收”
1.将Message Buffers置于不激活状态
2.第3~14个Message Buffers收信号地址为0;
3.第15个Message Buffers收信号地址为11_1100_0000_0000
4.将Message Buffers置于“空且激活”状态
*/
int can_init(void)
{
	unsigned short reg;

	//MCF5282_GPIO_PASPAR = 0x0FF0; /* Initialize Port AS PAR to have Can TX/RX signals enabled */
	*((volatile unsigned short *)(0x40100056)) = 0x0FF0;/* Initialize Port AS PAR to have Can TX/RX signals enabled */
	pCanBase->canmcr = CANMCR_STOP_CLOCK|CANMCR_SOFT_RST;
	udelay(20);
	reg = pCanBase->canmcr;
	if(reg&CANMCR_SOFT_RST)
	{
		printk("can_init fail\n");
		return -1;
	}
	/* Initialize the transmit and receive pin modes and enable Bus_off and error interrupt in control register 0 */
	//pCanBase->canctrl0 = ENABLE_BOFF_INT|0x02;		//rx- recessive	tx-Open drain
	pCanBase->canctrl0 = ENABLE_BOFF_INT|0|0;		//rx- negative polarity	tx-positive polarity
	//PRESDIV  S-CLOCK 	PROPSEG  PSEG1  PSEG2  RJW
	//0x02 		16M		  4 		4 	 4 		4
 	pCanBase->canctrl1	= SAMP|CAN_PROPSEG_1000K;			//CANCTRL1 SAMP|TSYNC|LBUF|LOM|PROPSEG
	pCanBase->canctrl2 	= (CAN_RJW<<6)|(CAN_PSEG1_1000K<<3)|CAN_PSEG2_1000K;	//CANCTRL2 RJW|PSEG1|PSEG2 00 111000	
	pCanBase->presdiv	= CAN_PRESDIV_1000K;				//PRESDIV PRES_DIV

	//printk("bit time %x %x\n",pCanBase->canctrl1,pCanBase->canctrl2);
	//printk("prop seg1 seg2 %d %d %d %x\n",CAN_PROPSEG_1000K,CAN_PSEG1_1000K,CAN_PSEG2_1000K,pCanBase->canctrl2);

	pCanBase->rxgmskhi	= 0x1f00;	/*滤波器设置*/
	pCanBase->rxgmsklo	= 0;
	pCanBase->rx14mskhi = 0x1f00;
	pCanBase->rx14msklo = 0;
	pCanBase->rx15mskhi = 0x1f00;
	pCanBase->rx15msklo = 0;
	
	for(reg=0;reg<3;reg++)	//message buffer 0~2	for tx
		*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*reg)) = 0x80;	//tx not active
	for(reg=3;reg<=15;reg++)	//message buffer 3~15 	for rx
  		reset_rx_mb(reg);       //just below it 

	//reg = pCanBase->timer;		//release all message buffer
	pCanBase->iflag |= 0xffff;
	pCanBase->estat &= 0xfff8;
	pCanBase->imask = 0xfff8;		//enable rx interrupt;
	pCanBase->canmcr = 0;
	udelay(20);
	printk("can init end cmr estat iflag %x %x %x\n",pCanBase->canmcr,pCanBase->estat ,pCanBase->iflag);
	printk("txe rxe %x %x\n",pCanBase->rxectr,pCanBase->txectr);
	return 0;
}

/////////////////////////////////////////

inline void reset_rx_mb(int no)
{
	*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no)) = 0;				// rx not ready
	if(no != 15)
		*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no+2)) = 0x0008;	//receive msg addr is 0
	else
		*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no+2)) = 0x1f08;	//message buffer 15 for broadcast information
	*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no+4)) = 0;				//ID|data frmae
	*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x80+0x10*no)) = 0x40;			//rx active and empty ready for receive
}

//////////by other///////////


void can_release(void)
{
	int i;
	DisableInterrupt();//中断无效
	*((volatile unsigned short *)(MCFFLEXCAN_BASE)) = 0x1000;
	for(i=136;i<155;i++)free_irq(i,NULL);//释放在init_module()中申请的中断
}


///////////by other////////////////

inline static void DisableInterrupt(void)
{
	*((volatile unsigned char *)(MCFFLEXCAN_BASE + 6))	 = 0x0|0|2;	//控制寄存器0,关闭总线与错误中断
	*((volatile unsigned short *)(MCFFLEXCAN_BASE+0x22)) = 0;		//中断掩码寄存器
}
//////////////////////////

⌨️ 快捷键说明

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