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

📄 sja1000drv.c

📁 at91rm9200下的sja1000的linux驱动程序
💻 C
字号:
#include <linux/module.h>#include <linux/config.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/ioport.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/fcntl.h>#include <asm/arch/hardware.h>#include "sja1000.h"#ifdef CONFIG_DEVFS_FS#include <linux/devfs_fs_kernel.h>#endif#define DEBUG#ifdef DEBUG#define DPRINTK( x... )	printk("AT91rm9200:"##x)#else#define DPRINTK( x... )#endifstatic unsigned char *SJA1000_V_BASE[NR_CAN_DEVICES];static unsigned char rcv_data[NR_CAN_DEVICES][8];unsigned char READ_SJA(unsigned char reg,u8 channel) { 	unsigned char temp = 0; 	writeb(reg,SJA1000_V_BASE[channel]+0x08);   //模拟 ALE锁存地址,发地址信号; 	temp = readb(SJA1000_V_BASE[channel]);      //从指定地址读取数据 	return temp; }void WRITE_SJA(unsigned char reg,unsigned char value,u8 channel) {	writeb(reg,SJA1000_V_BASE[channel]+0x08);//ALE锁存地址,发地址信号; 	writeb(value,SJA1000_V_BASE[channel]);   //发送数据到地址 } unsigned char BCAN_CMD_PRG(unsigned char cmd,u8 channel){	WRITE_SJA(REG_COMMAND,cmd,channel);    	switch(cmd)	{	case TR_CMD:                     //发送请求命令		return 0;		break;	case AT_CMD:                     //中止发送命令  		if((READ_SJA(REG_STATUS,channel)&0x20)==0)//判断是否正在发送         		{			return 0;		}		else		{			return 1;		}   		break; 	case RRB_CMD:                    //释放接收缓冲区  		if((READ_SJA(REG_STATUS,channel)& 0x01)==1)//判断是否释放成功		{			return 1;		}		else		{			return 0;		}   		break;   	case COS_CMD:                    //清除超载状态		if((READ_SJA(REG_STATUS,channel)& 0x02)==0)//判断清除超载是否成功		{			return 0;		}		else		{			return 1;		}   		break;     	case GTS_CMD:                    //进入睡眠状态命令 		return 0;		break; 	default:		return 1;		break; 	}}unsigned char BCAN_DATA_RECEIVE(unsigned char *RcvDataBuf,u8 channel,u16 *identifier){	u8 DataCount,i; 	u8 identifier1,identifier2;	if((READ_SJA(REG_STATUS,channel)&0x01)==0)               //判断报文是否有效	{		return 1;	}	if((READ_SJA(REG_RxFrameInfo,channel)&0x10)==0)               //如果是数据帧	{		DataCount = READ_SJA(REG_RxFrameInfo,channel)&0x0f;	}	else	{		DataCount = 3;	}	identifier1 = READ_SJA(REG_RxIdentifier1,channel);	identifier2 = READ_SJA(REG_RxIdentifier2,channel);	*identifier = (identifier1<<8) | identifier2;	for(i=0;i<DataCount;i++)	{		*RcvDataBuf++ = READ_SJA((REG_RxBuffer1+i),channel);	}	return  DataCount;}unsigned char BCAN_QUIT_RETMODEL(u8 channel){	unsigned char TempData;    	TempData = READ_SJA(REG_CONTROL,channel);    WRITE_SJA(REG_CONTROL,TempData&0xfe,channel);         if((READ_SJA(REG_CONTROL,channel)&0x01) == 0)    {       return 0;    }    else    {       return 1;    }}unsigned char BCAN_SET_MOD(u8 channel){	unsigned char TempData;	TempData = READ_SJA(REG_CONTROL,channel);	WRITE_SJA(REG_CONTROL,TempData&0xf8,channel);	WRITE_SJA(REG_EMLR,0xc0,channel);	return 0;}/************************************************************************;*函数原型:    BCAN_SET_OBJECT                                          **参数说明:                                                              * *    BCAN_ACR:存放验收代码寄存器(ACR)的参数设置                      * *    BCAN_AMR:存放接收屏蔽寄存器(AMR)的参数设置                      *;*返回值:                                                               *;*           0 ;通信对象设置成功                                        *;*           1 ;通信对象设置失败                                        *;*                                                                      * ;*说明:设置CAN节点的通讯对象,允许接收的报文ID号的高8位(D10--D3) 。     *;*     允许接收的报文,是由AMR和ACR共同决定的.                           *  ;*    满足以下条件的ID号的报文才可以被接收                              *;*[(ID.10-ID.3)≡(AC.7-AC.0)]||(AM.7-AM.0)≡11111111              *;*    该子程序只能用于复位模式                                          *                                                                                                                     *             ;************************************************************************/unsigned char BCAN_SET_OBJECT(unsigned char BCAN_ACR,unsigned char BCAN_AMR,u8 channel){	unsigned char i;	WRITE_SJA(REG_ACR,BCAN_ACR,channel);	if(READ_SJA(REG_ACR,channel) != BCAN_ACR)	{		return 1; 	}	WRITE_SJA(REG_AMR,BCAN_AMR,channel);	if(READ_SJA(REG_AMR,channel) != BCAN_AMR)	{			return 1; 	}//add by chris for debug	for(i=0;i<4;i++)		WRITE_SJA((REG_AMR+i),BCAN_AMR,channel);	for(i=0;i<4;i++)		WRITE_SJA((REG_ACR+i),0xff,channel);	return 0;}//@16M 晶振30P电容unsigned char SJA_BTR_CODETAB[]={    0x53,0x2F,		              //   ;20KBPS的预设值    0x87,0xFF,                     //;40KBPS的预设值    0x47,0x2F,                     //;50KBPS的预设值    0x83,0xFF,                     //;80KBPS的预设值    0x43,0x2f,                     //;100KBPS的预设值    0x03,0x1c,                     //;125KBPS的预设值    0x81,0xfa,                     //;200KBPS的预设值    0x01,0x1c,                     //;250KBPS的预设值    0x80,0xfa,                     //;400KBPS的预设值    0x00,0x1c,                     //;500KBPS的预设值    0x80,0xb6,                     //;666KBPS的预设值    0x00,0x16,                     //;800KBPS的预设值    0x00,0x14                     //;1000KBPS的预设值};unsigned char BCAN_SET_BANDRATE(unsigned char CAN_ByteRate,u8 channel){	unsigned char BTR0_num,BTR1_num;	BTR0_num = SJA_BTR_CODETAB[CAN_ByteRate*2];	BTR1_num = SJA_BTR_CODETAB[CAN_ByteRate*2+1];	WRITE_SJA(REG_BTR0,BTR0_num,channel);	if(READ_SJA(REG_BTR0,channel) != BTR0_num)			//校验写入值	{		return 1; 	}	WRITE_SJA(REG_BTR1,BTR1_num,channel);	if(READ_SJA(REG_BTR1,channel) != BTR1_num)			//校验写入值	{		return  1; 	}	return 0;}  /************************************************************************;*函数原型: unsigned char  BCAN_SET_OUTCLK (unsigned char Out_Control, 	        *                                  unsigned char  Clock_Out,unsigned char num);     *;*参数说明:										      					* *    Out_Control:存放输出控制寄存器 (OC)  的参数设置                   * *    Clock_Out:存放时钟分频寄存器 (CDR) 的参数设置                     * *                                                                      *   ;*返回值:                                                               *;*           0 ;设置成功                                                *;*           1 ;设置失败                                                *;*                                                                      * ;*说明:设置SJA1000的输出模式和时钟分频 。该子程序只能用于复位模式       *                                                                                                                     *             ;************************************************************************/unsigned char BCAN_SET_OUTCLK (unsigned char Out_Control,                         unsigned char Clock_Out,u8 channel){	WRITE_SJA(REG_OCR,Out_Control,channel);	  	if(READ_SJA(REG_OCR,channel) != Out_Control)		//校验写入值	{		return 1; 	} 	WRITE_SJA(REG_CDR,Clock_Out,channel);		return 0;}unsigned char BCAN_CREATE_COMMUNATION(u8 channel,unsigned char value){  	WRITE_SJA(REG_TEST,value,channel);	if(READ_SJA(REG_TEST,channel) == value)	{		return 0x00;	}	else	{		return 0x01;	} }      unsigned char BCAN_ENTER_RETMODEL(u8 channel){	unsigned char TempData;	TempData = READ_SJA(REG_CONTROL,channel);	WRITE_SJA(REG_CONTROL,TempData|0x01,channel);	    	if((READ_SJA(REG_CONTROL,channel)&0x01) == 1)	{		return 0;	}	else	{		return 1;	}}unsigned char BCAN_DATA_WRITE(unsigned char *SendDataBuf,u8 channel,u8 frameInfo,u16 identifier){	unsigned char DataCount,i;	if((READ_SJA(REG_STATUS,channel)&0x08)==0)         //判断上次发送是否完成	{		return	1;	}	if((READ_SJA(REG_STATUS,channel)&0x04)==0)   //判断发送缓冲区是否锁定	{		return	1;	}   	if((frameInfo&0x10)==0)        //判断RTR,从而得出是数据帧还是远程帧	{ 		DataCount = frameInfo&0x0f;	}	else	{		DataCount = 2;	}	WRITE_SJA(REG_TxFrameInfo,frameInfo,channel);	WRITE_SJA(REG_TxIdentifier1,identifier&0xff,channel);	WRITE_SJA(REG_TxIdentifier2,identifier>>8,channel);	for(i=0;i<DataCount;i++)	{		WRITE_SJA((REG_TxBuffer1+i),SendDataBuf[i],channel);	}	return 0;}void Sja_1000_Init(u8 channel){//	unsigned char s;	BCAN_CREATE_COMMUNATION(channel,0xaa);	BCAN_ENTER_RETMODEL(channel);	BCAN_SET_OUTCLK(0xaa,0xc1,channel);	//Pelican ,disable clkout,disable comparator,RX1->Vss	//BCAN_SET_BANDRATE(0x04,num);	BCAN_SET_BANDRATE(ByteRate_1000k,channel);	BCAN_SET_OBJECT(0xaa,0xff,channel);	BCAN_SET_MOD(channel);		//set to normal	BCAN_QUIT_RETMODEL(channel);//	WRITE_SJA(REG_IER,0x09,channel);//enable  receive INT	WRITE_SJA(REG_IER,0x08,channel);	//disable receive interrupt	WRITE_SJA(REG_RCN,0x00,channel);//clear wrong cnt	WRITE_SJA(REG_TCN,0x00,channel);}/*static void SJA_irq_handler(int irq,void *dev_id,struct pt_regs *regs){	volatile s32 status;//	u8 i;	unsigned int mask = 0x1 << AT91C_ID_PIOA;	// Disable the interrupt on the interrupt controller	AT91_SYS->AIC_IDCR = mask;	// Clear the interrupt on the Interrupt Controller ( if one is pending )	AT91_SYS->AIC_ICCR = mask;	status =AT91_SYS->PIOA_ISR;	if((status&AT91C_PIO_PA20)==AT91C_PIO_PA20)	{		if(((AT91_SYS->PIOA_PDSR)&AT91C_PIO_PA20?0:1))		{			//printk("can_interrupt !\n");		}		for(i=0;i<NR_CAN_DEVICES;i++) {			if((READ_SJA(REG_INTERRUPT,i)&0x01)==1)               //判断报文是否有效								//if there is receive interrupt			{				printk("Can %d interrupt !\n",i);			}		}	}    // Enable the interrupt on the interrupt controller    AT91_SYS->AIC_IECR = 0x1 << AT91C_ID_PIOA;    return;}*/static int sja1000_open(struct inode *inode, struct file *filp){	unsigned short CanNo = MINOR(inode->i_rdev);	if(CanNo >= NR_CAN_DEVICES)		return -ENODEV;	MOD_INC_USE_COUNT;	printk(KERN_INFO "open CAN-Bus %d\n",CanNo);//configure power for  pio	AT91_SYS->PMC_PCER = 1 << AT91C_ID_PIOA;	/* enable peripheral clock *///configure input mode	AT91_SYS->PIOA_ODR = AT91C_PIO_PA20;	AT91_SYS->PIOA_PER = AT91C_PIO_PA20;//enable interrupt	AT91_SYS->PIOA_IER = AT91C_PIO_PA20;	AT91_SYS->AIC_IECR = 0x1 << AT91C_ID_PIOA;	Sja_1000_Init(CanNo);	return 0;} static int sja1000_release(struct inode *inode, struct file *filp) {	unsigned short CanNo = MINOR(inode->i_rdev);	MOD_DEC_USE_COUNT;	printk(KERN_INFO "close CAN-Bus %d\n",CanNo);	return 0;}static ssize_t sja1000_read(struct file * filp, char *buf, size_t count, loff_t * ppos){	return 0;}static ssize_t sja1000_write(struct file *filp, const char *buf,size_t count,loff_t *loff){	return count;}static int sja1000_ioctl(struct inode *inode, struct file *filp,                        unsigned int cmd, unsigned long arg){    void* data;    char* databuf;    struct can_local canFrame;	unsigned short CanNo = MINOR(inode->i_rdev);	    if(_IOC_TYPE(cmd) != GPIO_IOC_MAGIC)    {        return -ENOTTY;    }    if(_IOC_NR(cmd) >= GPIO_MAXNR)    {        return -ENOTTY;    }	data = (void *)arg;	if(copy_from_user(&canFrame,data,sizeof(struct can_local)))	{		printk("copy canFrame fail\n");	}		switch(cmd)    {	case CAN_RD:		if((READ_SJA(REG_INTERRUPT,CanNo)&0x01)==1)		{			canFrame.len = BCAN_DATA_RECEIVE(rcv_data[CanNo],CanNo,&canFrame.identifier);			BCAN_CMD_PRG(RRB_CMD,CanNo);			if(copy_to_user(canFrame.rdata,rcv_data[CanNo],canFrame.len))			{				printk("copy_to_user fail\n");			}		}		else			canFrame.len = 0;		if(copy_to_user(data,&canFrame,sizeof(struct can_local)))		{			printk("copy_to_user fail\n");		}		break;	case CAN_WR:		databuf = (char*)kmalloc(canFrame.len, GFP_KERNEL);		if(!databuf) {			printk("malloc memory fail\n");			return 0;		}		if(copy_from_user(databuf, canFrame.pData, canFrame.len))		{			printk("copy_from_user fail\n");		}		BCAN_DATA_WRITE(databuf,CanNo,canFrame.frameInfo,canFrame.identifier);		BCAN_CMD_PRG(TR_CMD,CanNo);		kfree(databuf);		break;	case CAN_CMD:		BCAN_CMD_PRG(canFrame.cmd,CanNo);		break;	default:		return -ENOTTY;		break;	}	return 0;}static char SJA1000_NAME[] = "sja1000dev";static unsigned int canMajor;#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_can_handle = NULL;static devfs_handle_t devfs_sja1000[NR_CAN_DEVICES];#endifstatic struct file_operations sja1000_fops ={	owner:		THIS_MODULE,	open:		sja1000_open,	release:	sja1000_release,	read:		sja1000_read,	write:		sja1000_write,	ioctl:		sja1000_ioctl,};static int __init sja1000drv_init_module(void){	int i;	int result;	char name[2];		AT91_SYS->EBI_SMC2_CSR[7] = (AT91C_SMC2_NWS & 0x7f) | AT91C_SMC2_WSEN                                   | (AT91C_SMC2_TDF & 0x300) | AT91C_SMC2_BAT | AT91C_SMC2_DBW_8;	result = register_chrdev(0,SJA1000_NAME,&sja1000_fops);	if(result<0)	{		printk("cannot get can major number\n");		return result;	}	canMajor = result;#ifdef CONFIG_DEVFS_FS	devfs_can_handle = devfs_mk_dir(NULL, "can_b", NULL);	for(i = 0;i < NR_CAN_DEVICES;i++) {		sprintf(name, "%d", i);		devfs_sja1000[i] = devfs_register(devfs_can_handle, name,			DEVFS_FL_DEFAULT, canMajor, i, S_IFCHR | S_IRUSR | S_IWUSR,			&sja1000_fops, NULL);	}#endif	for(i = 0;i < NR_CAN_DEVICES;i++) {		SJA1000_V_BASE[i] = (unsigned char *)ioremap(SJA1000_HW_BASE(i), SJA1000_PHYSICAL_REG_SIZE);		if(!SJA1000_V_BASE[i]) {			printk("SJA1000 ioremap failed!\n");			return -EFAULT;		}	}//	if(request_irq(AT91C_ID_PIOA, SJA_irq_handler, 0, "sja1000", NULL))//		return -EBUSY;	printk(KERN_INFO "CAN-Bus driver loaded\n");	return 0;}static void __exit sja1000drv_cleanup(void){	int i;//	free_irq(AT91C_ID_PIOA,0);#ifdef CONFIG_DEVFS_FS	devfs_unregister(devfs_can_handle);	if(devfs_unregister_chrdev(canMajor,SJA1000_NAME)) {#else	if(unregister_chrdev(canMajor,SJA1000_NAME)) {#endif		printk(KERN_ERR "at91_CANdev: Unable to release major %d for CAN-Bus\n", canMajor);		return;	}	for(i = 0; i < NR_CAN_DEVICES; i++) {		iounmap(SJA1000_V_BASE[i]);	}	printk("<1>SJA1000DRV:GOOD-bye!\n");}module_init(sja1000drv_init_module);module_exit(sja1000drv_cleanup);MODULE_LICENSE("GPL");MODULE_DESCRIPTION("linux2.4.at91rm9200 sja1000 driver");

⌨️ 快捷键说明

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