📄 obcana_pxa.c
字号:
/* * General Char Device for linux * */ #include <linux/module.h>#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/miscdevice.h>#include <linux/reboot.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <asm/uaccess.h>#include <asm/io.h> #include <asm-arm/arch-pxa/irqs.h>#include "can_pxa.h"#define mdprintk printk#define DEVICE_MINOR 100#define DEVICE_NAME "cana"#define cana_addr 0xeb200000MODULE_LICENSE("GPL");/*************************** can控制器 ***************************///#include "can.h"//1.错误代码定义#define EVerify 12 // 写入回读不同#define RESET_CAN_OK 13 // 复位成功#define RESET_CAN_ERROR 14 // 复位错误#define CAN_RESET 15 //#define CAN_DEBUG 16 //0XFF#define CAN_DEBUG_ERROR 17#define CAN_OK 11#define CAN_READ_NO_DATA 9 //无数据#define CAN_WRITE_BUSY 10 //写数据忙 //2.控制寄存器#define FlagRR 0x01 // 复位请求// 命令寄存器#define FlagCOS 0x08 // 清除超载#define FlagRRB (0x04) // 清除接收缓冲,允许接收#define FlagAT 0x02 // 中止发送#define FlagTR 0x01 // 发送请求//3.状态寄存器#define FlagBS 0x80 // 总线脱离#define FlagES 0x40 // 错误#define FlagTS 0x20 // 正在发送#define FlagRS 0x10 // 正在接收#define FlagTCS 0x08 // 发送完成#define FlagTBS 0x04 // 发送缓冲可用#define FlagDO 0x02 // 数据超载#define FlagRBS 0x01 // 接收缓冲有效//4.中断寄存器#define FlagWUI 0x10 // 唤醒中断#define FlagOI 0x08 // 超载中断#define FlagEI 0x04 // 错误中断#define FlagTI 0x02 // 发送中断#define FlagRI 0x01 // 接收中断//5.速度#define BTR0_125K 0x03 // 波特率=125Kbps(16MHZ),(3+1)*2=8#define BTR1_125K 0x1C // TSEG1=0x0C=>13,TSEG2=0x01=>2,1+13+2=16#define BTR0_500K 0x01 // 波特率=500Kbps(16MHZ),(1+1)*2=4#define BTR1_500K 0x14 // TSEG1=0x04=>5,TSEG2=0x01=>2,1+5+2=8#define BTR0_1M 0x00 // 波特率=1Mbps(16MHZ),(1)*2=2#define BTR1_1M 0x14 // TSEG1=0x04=>5,TSEG2=0x01=>2,1+5+2=8//6.其他#define DLCMask 0x0F // DLC屏蔽#define IDLMask 0xE0 // D低字节高3位屏蔽#define IDLShift 5 // ID低字节高3位右对齐移位计数#define TimeReset 100 // 复位时间,毫秒struct CanControl { char CR; //控制寄存器 char CMR;//命令寄存器 char SR; //状态寄存器 char IR;//中断寄存器 char ACR;//验收寄存器 char AMR;//屏蔽寄存器 char BTR0; char BTR1; char OCR; char TR; // 寄存器00..09 char TxDSCR[2],TxData[8];//发送ID,数据 10..19 char RxDSCR[2],RxData[8];//接收ID,数据 20..29 char XX30,CDR;//31 时钟驱动 30..31} volatile *pcan=0;static int can_irq=13;static int canid=0;static int canspeed=0;static int speed=0;static int get_sp0(){ switch( canspeed ) { case 1: return BTR0_1M; case 0: return BTR0_500K;// case B125: return BTR0_125K; } return 0;}static int get_sp1(){ switch( canspeed ) { case 1: return BTR1_1M; case 0: return BTR1_500K;// case B125: return BTR1_125K; } return 0;}#define BTR0_Data get_sp0()#define BTR1_Data get_sp1()#define CAN_IN_BUF_SIZE 100static struct canmsg_t can_in_buffer[CAN_IN_BUF_SIZE];static int can_in_buf_head=0; //接受缓冲区头指针static int can_in_buf_tail=0; //接受缓冲区尾指针static char can_write_busy=0;//初始时置0,write后置1,发送中断产生时置0static DECLARE_WAIT_QUEUE_HEAD(r_queue);static DECLARE_WAIT_QUEUE_HEAD(w_queue);static int irqt_tx=0 , irqt_rx=0 ;void interrupt_interrupt_can(int irq, void *dev_id, struct pt_regs *regs){ char ir; int i; char t1,t2; struct canmsg_t *pct = &can_in_buffer[can_in_buf_tail]; ir=(pcan->IR); if((ir&FlagRI)) {//接受中断 t1 = (pcan->RxDSCR[0]); t2 = (pcan->RxDSCR[1]); pct->id = (t1<<3) | (t2>>5); pct->length = t2&0xf; for(i=0;i<8;i++) pct->data[i] = pcan->RxData[i]; pcan->CMR=FlagRRB;//清除接受缓冲区 can_in_buf_tail++; can_in_buf_tail%=CAN_IN_BUF_SIZE; irqt_rx++; } else{ if(ir&FlagTI)//发送中断 { irqt_tx++; } else { if(ir&FlagEI) { reset_interrupt_can(); printk("some error in cana\n"); printk("can reset , SR=%x, IR=%x\n",pcan->SR,ir); } else printk("unknown interrupt\n"); } } return;}int reset_interrupt_can(void){//复为can控制器 short b; int i; pcan->CR=0x0f; pcan->CMR=0; pcan->BTR0=BTR0_Data; pcan->BTR1=BTR1_Data; printk(" 8bit read on 8bit device:%x,%x\n",pcan->BTR0,pcan->BTR1); printk("8bit read on 8bit device:%x,%x\n",BTR0_Data,BTR1_Data); if((pcan->BTR0!=BTR0_Data)|(pcan->BTR1!=BTR1_Data)) { printk("error\n"); return RESET_CAN_ERROR; } pcan->ACR=0x07; pcan->AMR=0xff; pcan->OCR=0xfa; pcan->CR &= 0xfe; can_in_buf_head = 0; can_in_buf_tail = 0; can_write_busy=0; return RESET_CAN_OK;}/* * Allow only one person to hold it open */static int g_chdrv_open(struct inode *inode, struct file *file){ mdprintk("g_chdrv device %s opened\n",DEVICE_NAME); reset_interrupt_can(); return 0;}static int g_chdrv_release(struct inode *inode, struct file *file){ mdprintk("g_chdrv device %s released\n",DEVICE_NAME); return 0;}static ssize_t g_chdrv_read(struct file *file, char *data, size_t len, loff_t *ppose){ struct canmsg_t t; //printk("g_chdrv device %s read %d bytes\n",DEVICE_NAME,len); while(can_in_buf_head==can_in_buf_tail); copy_to_user( data , &can_in_buffer[can_in_buf_head] , sizeof(t) ); can_in_buf_head++; can_in_buf_head%=CAN_IN_BUF_SIZE; return 1;}static ssize_t g_chdrv_write(struct file *file, const char *data, size_t len, loff_t *ppos){ struct canmsg_t t; int i,j; //mdprintk("g_chdrv device %s write %d bytes\n",DEVICE_NAME,len); if(pcan->SR&FlagTS) { printk("busy"); return 0; } copy_from_user( &t , data , sizeof(t) ); if( t.length>8 )t.length=8; pcan->TxDSCR[0] = t.id>>3 ; pcan->TxDSCR[1] = ((t.id&7)<<5) | (t.length&0xf); for(i=0;i<t.length;i++){ pcan->TxData[i] = t.data[i]; for(j=0;j<10;j++); } pcan->CMR=FlagTR; return 1;}static int g_chdrv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return 0;}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////static struct file_operations g_chdrv_fops = { owner: THIS_MODULE, read: g_chdrv_read, write: g_chdrv_write, ioctl: g_chdrv_ioctl, open: g_chdrv_open, release: g_chdrv_release,};static struct miscdevice g_chdrv_miscdev = { minor: DEVICE_MINOR, name: DEVICE_NAME, fops: &g_chdrv_fops,};MODULE_PARM(canid,"i");MODULE_PARM(canspeed,"i");MODULE_PARM(speed,"i");static int __init g_chdrv_init(void){ int ret; int volatile *p=0xfa00000c; *p=0x0470000+speed; can_irq = 14; pcan = cana_addr; g_chdrv_miscdev.minor = DEVICE_MINOR; g_chdrv_miscdev.name = DEVICE_NAME; set_GPIO_IRQ_edge(can_irq,GPIO_FALLING_EDGE); if( request_irq(IRQ_GPIO(can_irq), interrupt_interrupt_can,SA_INTERRUPT, g_chdrv_miscdev.name,NULL) ) { printk("Get Interrupt %d Error\n" , can_irq ); return -1; } ret = misc_register(&g_chdrv_miscdev); mdprintk("g_chdrv device %s init\n",DEVICE_NAME); if (ret) { free_irq(IRQ_GPIO(can_irq),NULL); printk("error\n"); return ret; } reset_interrupt_can(); return 0;}static void __exit g_chdrv_exit(void){ free_irq(IRQ_GPIO(can_irq),NULL); misc_deregister(&g_chdrv_miscdev); mdprintk("g_chdrv device %s exit\n",DEVICE_NAME);}module_init(g_chdrv_init);module_exit(g_chdrv_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -