📄 cangate.c
字号:
#include <linux/kernel.h>#include <linux/module.h>#if CONFIG_MODVERSIONS==1#define MODVERSIONS#include <linux/modversions.h>#endif #include <linux/fs.h>#include <linux/wrapper.h>#include <asm/semaphore.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/ioport.h>#include <linux/poll.h>#include "cangate.h"#define DEVICE_NAME "cangate"#define BASE_ADDRESS 0x378 //并口基地址#define EPP_IRQ_VECTOR 7#define inp(addr) inb(addr)#define outp(addr,val) outb(val,addr)unsigned char read_sja(unsigned char addr);void write_sja(unsigned char addr,unsigned char val);unsigned char Receive(unsigned char *RCdata);void Transmit(unsigned char *TXdata);int init(void);int init_module(void);void cleanup_module(void);DECLARE_MUTEX(sem);int log_flag = 1; // 0 -- stop buffer CAN frames. 1 -- start buffer CAN frames.#define MAX_NR_FRAMES 100/*rd_buf: 保存CAN总线数据.*/struct rec{ unsigned char databuf[11 * MAX_NR_FRAMES]; /*最多存储10帧数据*/ int start,end; /*0,1,2,...9*/} rd_buf;void init_rd_buf(){ rd_buf.start = 0; rd_buf.end = 0;}int is_empty_rd_buf(){ return (rd_buf.start == rd_buf.end);}int is_full_rd_buf(){ return (rd_buf.start == (rd_buf.end+1) % MAX_NR_FRAMES);}void out_rd_buf(unsigned char *buf){ if(is_empty_rd_buf()) return; memcpy(buf, &rd_buf.databuf[rd_buf.start*11],11); rd_buf.start = ++rd_buf.start % MAX_NR_FRAMES;}void in_rd_buf(unsigned char *buf){ if(is_full_rd_buf()) return; memcpy(&rd_buf.databuf[rd_buf.end*11],buf,11); rd_buf.end = ++rd_buf.end % MAX_NR_FRAMES;}void epp_interrupt(int irq, void *dev_id, struct pt_regs *regs){ unsigned char buf[11]; int intrkind; intrkind=read_sja(3); if(intrkind & 0x01 == 0){/*not receive interrupt*/ goto out; } Receive(buf);// printk("int1 : %2x %2x %2x %2x %2x\n",buf[0],buf[1],buf[2],buf[3],buf[4]); if(log_flag) in_rd_buf(buf); //buffer this frameout: write_sja(1,4); //clear sja receive buffer in order to clear it's INT signal// *(volatile unsigned long*)(MCF_MBAR + 0x20) |= 0x80000000;//clear pending bit //clear EPP interrupt}/*--------------------------------------------------- 两个最基本的SJA1000寄存器读写函数*/unsigned char read_sja(unsigned char sja_reg_addr){ int i; unsigned char bValue; cli(); down(&sem); sja_reg_addr &= 0x7F; /*最高位清0*/ //address lock outp(BASE_ADDRESS+2,0xd5); outp(BASE_ADDRESS,sja_reg_addr); outp(BASE_ADDRESS+2,0xd4); outp(BASE_ADDRESS+2,0xd5); //read data outp(BASE_ADDRESS+2,0xd7); outp(BASE_ADDRESS+2,0xf7); //read enable bValue=inp(BASE_ADDRESS); outp(BASE_ADDRESS+2,0xf5); outp(BASE_ADDRESS+2,0xd5); up(&sem); sti(); return (bValue);}void write_sja(unsigned char sja_reg_addr, unsigned char bValue){ int i; cli(); down(&sem); sja_reg_addr &= 0x7F; /*最高位清0*/ //addr is the address of the SJA1000 outp(BASE_ADDRESS+2,0xd5); //1101 0101 outp(BASE_ADDRESS,sja_reg_addr); outp(BASE_ADDRESS+2,0xd4); //1101 0100 outp(BASE_ADDRESS+2,0xd5); //1101 0101 outp(BASE_ADDRESS,bValue); outp(BASE_ADDRESS+2,0xdd); //1101 1101 outp(BASE_ADDRESS+2,0xd5); //1101 0101 up(&sem); sti();}/*--------------------------------------------------- 读写数据帧函数.外部程序不可见*/unsigned char Receive(unsigned char *RCdata){ int i=16; int j=0; unsigned char sr = read_sja(2); /*读出总线状态寄存器*/ for(;j<11;i++,j++){ RCdata[j] = read_sja(i); } write_sja(0x01,0x04); /*清空SJA1000的接收寄存器*/ return sr; /*返回值为未知错误 */}void Transmit(unsigned char *TXdata){ int i=16; int j=0; do{ }while( !(read_sja(2)&0x04) ); for(;j<11;i++,j++){ write_sja(i,TXdata[j]); } write_sja(1,0x01); /*送出发送命令,使用重发机制*/}/*--------------------------------------------------- ioctl用来让外部程序访问SJA1000的寄存器从而可以配置其工作方式以及了解其状态*/static int qspi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int error, n, rc = 0; struct sja_op *sja_op_data = 0; switch (cmd) {// case QSPIIOCS_LOGCANFRAMES:// log_flag = arg;// break; case QSPIIOCS_WRITESJA: /*写SJA1000寄存器*/// copy_from_user(&sja_op_data,(void *)arg,sizeof(struct sja_op)); sja_op_data = (struct sja_op*)arg;// error = verify_area(VERIFY_READ, sja_op_data,// sizeof(struct sja_op));// if (error)// return error; write_sja(sja_op_data->sja_reg_addr, sja_op_data->sja_reg_value); break; case QSPIIOCS_READSJA: /*读SJA1000寄存器*/// copy_from_user(&sja_op_data,(void *)arg,sizeof(struct sja_op)); sja_op_data = (struct sja_op*)arg;// error = verify_area(VERIFY_READ, sja_op_data,// sizeof(struct sja_op));// if (error)// return error; sja_op_data->sja_reg_value = read_sja(sja_op_data->sja_reg_addr);// copy_to_user((void *)arg,&sja_op_data,sizeof(struct sja_op)); break; default: rc = -EINVAL; break; } return rc;}void ResetEpp(){ int i; unsigned char data,reset; data = inp(BASE_ADDRESS+2); reset = data&0xfb; outp(BASE_ADDRESS+2,reset); for(i=0;i<10000;i++) nop(); outp(BASE_ADDRESS+2,data); for(i=0;i<10000;i++) nop();}static int qspi_open(struct inode *inode, struct file *file){ MOD_INC_USE_COUNT; return 0;}static int qspi_release(struct inode *inode, struct file *file){ MOD_DEC_USE_COUNT; return 0;}static loff_t qspi_llseek(struct file *filep, loff_t off, int mod){ return off;}/*---------------------------------------------------*/static ssize_t qspi_read(struct file *filep,char *buffer,size_t length,loff_t *ppos){ int total = 0;// down(&sem); be careful! /*一直读到length或者rd_buf为空*/ while(1){ if(total >= length) break; if(is_empty_rd_buf()) break; out_rd_buf(buffer+total); total+=11; }// up(&sem); return total;}static ssize_t qspi_write(struct file *filep,const char *buffer,size_t length, loff_t *ppos){ int total = 0; unsigned char TXdata[11];// down(&sem);/* memcpy(dbuf, buffer, length);*/ while(total+11 <= length){ memcpy(TXdata,buffer+total,11); Transmit(TXdata); total += 11; } // up(&sem); return total;}unsigned int qspi_poll(struct file *filep, struct poll_table_struct *table){ unsigned int mask = 0; if(! is_empty_rd_buf() ) mask = POLLIN; return mask; }struct file_operations Fops = { owner: THIS_MODULE,// llseek: qspi_llseek, read: qspi_read, poll: qspi_poll, llseek: qspi_llseek, write: qspi_write, ioctl: qspi_ioctl, open: qspi_open, release: qspi_release, /* a.k.a. close */};/*--------------------------------------------------- 模块的安装与卸载*/int init(){ if(check_region(BASE_ADDRESS,2) != 0){ printk("address is occupied by other driver.\n"); return -1; } request_region(BASE_ADDRESS,2,DEVICE_NAME); if(request_irq(EPP_IRQ_VECTOR, epp_interrupt, SA_INTERRUPT, "ColdFire INT1", NULL)){ printk("INT1: Unable to attach ColdFire INT1 interrupt " "vector=%d\n", EPP_IRQ_VECTOR); release_region(BASE_ADDRESS,2); return -EINVAL; } ResetEpp(); printk("canport driver init ok.\n"); return 0;}/* init for module driver */int init_module(){ int ret; if ((ret = register_chrdev(QSPI_MAJOR, DEVICE_NAME, &Fops) < 0)) { printk ("%s device failed with %d\n", "Sorry, registering the character", ret); return ret; } init_rd_buf(); //init read buffer return init();} /* Cleanup - undid whatever init_module did */void cleanup_module(){ int ret; free_irq(EPP_IRQ_VECTOR, NULL); release_region(BASE_ADDRESS,2); /* Unregister the device */ if ((ret = unregister_chrdev(QSPI_MAJOR, DEVICE_NAME)) < 0) printk("Error in unregister_chrdev: %d\n", ret);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -