📄 sja1000drv.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 + -