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

📄 cangate.c

📁 包含一个EPP-CAN板的Linux操作系统驱动
💻 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 + -