📄 can.c
字号:
/****************************************Copyright (c)**************************************************
**
** 山西华控伟业
** http://www.hkwy.net.cn
**--------------文件信息--------------------------------------------------------------------------------
**文 件 名: cannew.c
**创 建 人: 田涛
**最后修改日期: 2007年2月8日
**-------------- 历史版本信息----------------------------------------------------------------------------
** 创建人: 田涛
** 版 本: v1.0
** 日 期: 2007年2月8日
** 描 述: 原始版本
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
//注意:CAN0对应IRQ17, CAN1对应IRQ16
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include "linux/capability.h"
#include "linux/smp_lock.h"
#include "linux/devfs_fs_kernel.h"
#include "linux/module.h"
#include "asm/hardware.h"
#include "asm/io.h"
#include "linux/init.h"
#include "asm/semaphore.h"
#include "asm/uaccess.h"
#include "linux/wait.h"
#include "linux/config.h"
#include "linux/irq.h"
#include "sja1000.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
#include "linux/smp_lock.h"
#endif
//注意:CAN0对应IRQ17, CAN1对应IRQ16
#define CAN_RCV_BUF_SIZE 5
#define CAN_NUM 2
#define CAN_MAJOR 200
#define CAN_SEND_MAX 25
//char kernel_version[]=UTS_RELEASE;
static devfs_handle_t dev_handle[CAN_NUM];
static unsigned int* canaddr[CAN_NUM]; //can控制器的映射起始地址
static wait_queue_head_t canread_wq[2], canwrite_wq[2];
static struct semaphore canread_sem[CAN_NUM];
static struct semaphore canwrite_sem[CAN_NUM];
typedef struct _CAN_RCV_CYCLEBUF_
{
U32 WritePoint; //CAN的写指针
U32 ReadPoint; //CAN的读指针
U8 FullFlag; //CAN缓冲区满标志
MCNET_CAN_OBJ RcvBuf[CAN_RCV_BUF_SIZE];
} CAN_RCV_CYCLEBUF, *PCAN_RCV_CYCLEBUF;
static CAN_RCV_CYCLEBUF CANRcvBuf[CAN_NUM];
static MCNET_INIT_CONFIG InitConfig;
/*********************************************************************************************************
** 函数名称: setcanport
** 功能描述: 设置can控制器相应寄存器的值
** 输 入: chanal:can通道号,reg:寄存器地址,data1:寄存器要设置的值
** 输 出: 无
** 全局变量: can0addr,can1addr
** 调用模块: 无
********************************************************************************************************/
static void setcanport(int chanal, unsigned char reg, unsigned char data1)
{
if(chanal>=CAN_NUM) {
printk("the biggest value of can number is %d", CAN_NUM-1);
return;
}
writeb(reg,canaddr[chanal]+100); //先发送地址信号,再发送数据
writeb(data1,canaddr[chanal]);
}
/*********************************************************************************************************
** 函数名称: getcanport
** 功能描述: 读取can控制器相应寄存器的值
** 输 入: chanal:can通道号,reg:寄存器地址
** 输 出: 读取的值
********************************************************************************************************/
static unsigned char getcanport(int chanal, unsigned char reg)
{
unsigned char temp;
if(chanal>=CAN_NUM) {
printk("the biggest value of can number is %d", CAN_NUM-1);
return 0;
}
writeb(reg,canaddr[chanal]+100); //先发送地址信号,再发送数据
return readb(canaddr[chanal]);
}
/*********************************************************************************************************
** 函数名称: getrcvbufnum
** 功能描述: 判断接受缓冲器中数据的数目
** 输 入: chanal:can通道号
** 输 出: 1:有数据 0:无数据
********************************************************************************************************/
static unsigned int getrcvbufnum(int chanal)
{
unsigned int temp;
if ( CANRcvBuf[chanal].FullFlag==1 ) //缓冲区已满
return CAN_RCV_BUF_SIZE;
if ( CANRcvBuf[chanal].WritePoint>=CANRcvBuf[chanal].ReadPoint )
return (CANRcvBuf[chanal].WritePoint-CANRcvBuf[chanal].ReadPoint);
else
return (CAN_RCV_BUF_SIZE+CANRcvBuf[chanal].WritePoint-CANRcvBuf[chanal].ReadPoint);
}
/*********************************************************************************************************
** 函数名称: clearrcvbuf
** 功能描述: 清除接受缓冲器
** 输 入: chanal:can通道号
** 输 出:
********************************************************************************************************/
static void clearrcvbuf(int chanal)
{
CANRcvBuf[chanal].FullFlag = 0;
CANRcvBuf[chanal].ReadPoint = 0;
CANRcvBuf[chanal].WritePoint = 0;
}
/*********************************************************************************************************
** 函数名称: testreg
** 功能描述:
** 输 入:
** 输 出: 无
********************************************************************************************************/
void test_greg(int chanal)
{
printk("This is CAN %d!\n",chanal);
printk( "REG_CONTROL: %.2x ", getcanport(chanal,REG_CONTROL) );
printk( "REG_STATUS: %.2x ", getcanport(chanal,REG_STATUS) );
printk( "REG_INTERRUPT: %.2x ", getcanport(chanal,REG_INTERRUPT) );
printk( "REG_INT_CONTROL: %.2x ", getcanport(chanal,REG_INT_CONTROL) );
printk( "REG_BTR0 : %.2x ", getcanport(chanal,REG_BTR0 ) );
printk( "REG_BTR1: %.2x ", getcanport(chanal,REG_BTR1) );
printk( "REG_OCR: %.2x ", getcanport(chanal,REG_OCR) );
printk( "REG_CDR: %.2x ", getcanport(chanal,REG_CDR) );
printk( "REG_ARBIT_LOSE: %.2x ", getcanport(chanal,REG_ARBIT_LOSE) );
printk( "REG_ERR_CODE : %.2x ", getcanport(chanal,REG_ERR_CODE ) );
printk( "REG_ERR_MAX: %.2x ", getcanport(chanal,REG_ERR_MAX) );
printk( "REG_RX_ERR: %.2x ", getcanport(chanal,REG_RX_ERR) );
printk( "REG_TX_ERR: %.2x\n", getcanport(chanal,REG_TX_ERR) );
}
void test_wreg(int chanal){
printk("This is CAN %d!\n",chanal);
printk( "REG_FRAME_INFO: %.2x ", getcanport(chanal,REG_FRAME_INFO) );
printk( "REG_FRAME_PID1: %.2x ", getcanport(chanal,REG_FRAME_PID1) );
printk( "REG_FRAME_PID2: %.2x ", getcanport(chanal,REG_FRAME_PID2) );
printk( "REG_FRAME_PID3: %.2x ", getcanport(chanal,REG_FRAME_PID3) );
printk( "REG_FRAME_PID4: %.2x ", getcanport(chanal,REG_FRAME_PID4) );
printk( "REG_FRAME_PDATA1: %.2x ", getcanport(chanal,REG_FRAME_PDATA1) );
printk( "REG_FRAME_PDATA2: %.2x ", getcanport(chanal,REG_FRAME_PDATA2) );
printk( "REG_FRAME_PDATA3: %.2x ", getcanport(chanal,REG_FRAME_PDATA3) );
printk( "REG_FRAME_PDATA4: %.2x ", getcanport(chanal,REG_FRAME_PDATA4) );
printk( "REG_FRAME_PDATA5: %.2x ", getcanport(chanal,REG_FRAME_PDATA5) );
printk( "REG_FRAME_PDATA6: %.2x ", getcanport(chanal,REG_FRAME_PDATA6) );
printk( "REG_FRAME_PDATA7: %.2x ", getcanport(chanal,REG_FRAME_PDATA7) );
printk( "REG_FRAME_PDATA8: %.2x\n", getcanport(chanal,REG_FRAME_PDATA8) );
}
void test_freg(int chanal){
printk("This is CAN %d!\n",chanal);
printk( "REG_ACR0: %.2x ", getcanport(chanal,REG_ACR0) );
printk( "REG_ACR1: %.2x ", getcanport(chanal,REG_ACR1) );
printk( "REG_ACR2: %.2x ", getcanport(chanal,REG_ACR2) );
printk( "REG_ACR3: %.2x ", getcanport(chanal,REG_ACR3) );
printk( "REG_AMR0: %.2x ", getcanport(chanal,REG_AMR0) );
printk( "REG_AMR1: %.2x ", getcanport(chanal,REG_AMR1) );
printk( "REG_AMR2: %.2x ", getcanport(chanal,REG_AMR2) );
printk( "REG_AMR3: %.2x\n", getcanport(chanal,REG_AMR3) );
}
/*********************************************************************************************************
** 函数名称: read_can
** 功能描述: 从CAN中读数据
** 输 入: filp文件指针,buf用户缓冲区,count要读的CAN帧的数目
** 输 出: 实际读到的CAN帧的数目
********************************************************************************************************/
static int read_can(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
int i,canid;
unsigned int num, read_num;
PMCNET_CAN_OBJ p_buf;
////////////////////////////////////////////
//printk( "write point:%d, read point:%d", CANRcvBuf[canid].WritePoint, CANRcvBuf[canid].ReadPoint );
///////////////////////////////////////
canid = (int)filp->private_data;
p_buf = (PMCNET_CAN_OBJ)buf;
down_interruptible(&canread_sem[canid]); //占用读信号量
for( read_num=0; read_num<count; ++read_num ) {
if( (CANRcvBuf[canid].FullFlag==0)&&(CANRcvBuf[canid].ReadPoint==CANRcvBuf[canid].WritePoint) ) { //缓冲区中无数据
if( read_num!=0 ) //已经读到数据
break;
else { //还没读到数据
while (1) {
interruptible_sleep_on(&canread_wq[canid]); //等待数据到来
if ( (CANRcvBuf[canid].WritePoint!=CANRcvBuf[canid].ReadPoint)||(CANRcvBuf[canid].FullFlag==1) ) { //有数据到来
copy_to_user( &p_buf[0], &CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].ReadPoint], sizeof(MCNET_CAN_OBJ) );
if( (++CANRcvBuf[canid].ReadPoint)>=CAN_RCV_BUF_SIZE )
CANRcvBuf[canid].ReadPoint =0;
CANRcvBuf[canid].FullFlag = 0;
break;
}
}
read_num=1;
break;
}
} else { //缓冲区中有数据
copy_to_user( &p_buf[read_num], &CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].ReadPoint], sizeof(MCNET_CAN_OBJ) );
if( (++CANRcvBuf[canid].ReadPoint)>=CAN_RCV_BUF_SIZE )
CANRcvBuf[canid].ReadPoint =0;
CANRcvBuf[canid].FullFlag = 0;
}
}
/* num = getrcvbufnum(canid); //缓冲区中数据的数目
if ( num>=count ) { //缓冲区中的数据足够多
for ( i=0;i<count;++i) {
copy_to_user( p_buf, &CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].ReadPoint], sizeof(MCNET_CAN_OBJ) );
p_buf++;
if( (++CANRcvBuf[canid].ReadPoint)>=CAN_RCV_BUF_SIZE )
CANRcvBuf[canid].ReadPoint =0;
CANRcvBuf[canid].FullFlag = 0;
}
read_num = count;
} else if ( (num<count)&&(num!=0) ) { //缓冲区中有数据但少于请求数据
for ( i=0;i<num;++i) {
copy_to_user( p_buf, &CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].ReadPoint], sizeof(MCNET_CAN_OBJ) );
p_buf++;
if( (++CANRcvBuf[canid].ReadPoint)>=CAN_RCV_BUF_SIZE )
CANRcvBuf[canid].ReadPoint =0;
CANRcvBuf[canid].FullFlag = 0;
}
read_num = num;
} else if ( num==0 ) { //缓冲区中无数据
while (1) {
interruptible_sleep_on(&canread_wq[canid]); //等待数据到来
if ( getrcvbufnum(canid)!=0 ) {
copy_to_user( buf, &CANRcvBuf[canid].RcvBuf[CANRcvBuf[canid].ReadPoint], sizeof(MCNET_CAN_OBJ) );
if( (++CANRcvBuf[canid].ReadPoint)>=CAN_RCV_BUF_SIZE )
CANRcvBuf[canid].ReadPoint =0;
CANRcvBuf[canid].FullFlag = 0;
break;
}
}
read_num = 1;
}*/
//printk( "write point:%d, read point:%d", CANRcvBuf[canid].WritePoint, CANRcvBuf[canid].ReadPoint );
up(&canread_sem[canid]);
return read_num;
}
/*********************************************************************************************************
** 函数名称: write_can
** 功能描述: 往CAN中写数据
** 输 入: filp文件指针,buf用户缓冲区,count要写的CAN帧的数目
** 输 出: 实际读到的CAN帧的数目
********************************************************************************************************/
static int write_can(struct file *filp,const char *buf,size_t count,loff_t *f_pos)
{
int i,j,canid;
unsigned int num, write_num;
MCNET_CAN_OBJ send_buf[CAN_SEND_MAX];
canid = (int)filp->private_data;
copy_from_user( send_buf,buf,count*sizeof(MCNET_CAN_OBJ) );
/*
printk("canid:%d ID:%.4x RTR:%d FF:%d DataLen:%.2x Data:", canid, send_buf[0].ID,
send_buf[0].RemoteFlag,send_buf[0].ExternFlag,send_buf[0].DataLen);
for(i = 0; i<8;i++)
printk("%.2x ",send_buf[0].Data[i]);
printk("\n");
*/
down_interruptible(&canwrite_sem[canid]); //占用写信号量
write_num = 0;
for ( i=0;i<count;++i) {
if (send_buf[i].ExternFlag==1) { //发送扩展帧
setcanport( canid,REG_FRAME_PID1,(send_buf[i].ID&0x1fe00000)>>21 );
setcanport( canid,REG_FRAME_PID2,(send_buf[i].ID&0x001fe000)>>13 );
setcanport( canid,REG_FRAME_PID3,(send_buf[i].ID&0x00001fe0)>>5 );
setcanport( canid,REG_FRAME_PID4,(send_buf[i].ID&0x0000001f)<<3 );
if (send_buf[i].RemoteFlag==1) { //远程帧
setcanport(canid, REG_FRAME_INFO, send_buf[i].DataLen+0x80+0x40);
} else { //数据帧
//printk("send extern data frame\n");//////////////
setcanport(canid, REG_FRAME_INFO, send_buf[i].DataLen+0x80);
for (j=0;j<8;++j)
setcanport(canid, REG_FRAME_PDATA1+j, send_buf[i].Data[j]);
//test_wreg(canid);///////////////////////////////
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -