?? intel82527_can.c
字號:
#include <linux/module.h>
#if defined(CONFIG_SMP)
#define __SMP__
#endif
#if defined(CONFIG_MODVERSIONS)
#define MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h> /* for timers */
#include <linux/fs.h> /* file modes and device registration */
#include <linux/poll.h> /* for poll */
#include <linux/wrapper.h> /* mem_map_reserve,mem_map_unreserve */
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <linux/init.h>
#include <asm/io.h>
#include "intel82527_can.h"
/* module parameters and descriptions */
MODULE_PARM(ican_name, "s");
MODULE_PARM_DESC(ican_name, "Name of device");
MODULE_PARM(ican_debug, "1b");
MODULE_PARM_DESC(ican_debug, "Enable debugging messages");
MODULE_DESCRIPTION("ican, Sample character driver");
MODULE_AUTHOR("grd");
MODULE_LICENSE("GPL");
struct file_operations ican_fops =
{
read: ican_read,
write: ican_write,
ioctl: ican_ioctl,
open: ican_open,
release: ican_release,
poll: ican_poll,
owner: THIS_MODULE,
};
DECLARE_WAIT_QUEUE_HEAD(inq);
DECLARE_WAIT_QUEUE_HEAD(outq);
static void i82527_start_chip(CAN_Dev *dev)
{
unsigned short flags = 0;
unsigned char* base;
base=dev->reg_base;
flags =readb(base+iCTL) & (iCTL_IE|iCTL_SIE|iCTL_EIE);
writeb(flags,base+iCTL);
}
static void i82527_stop_chip(CAN_Dev *dev)
{
unsigned short flags = 0;
unsigned char* base;
base=dev->reg_base;
flags =readb(base+iCTL) & (iCTL_IE|iCTL_SIE|iCTL_EIE);
writeb(flags|(iCTL_CCE|iCTL_INI),base+iCTL);
}
static void i82527_reset_chip(CAN_Dev *dev)
{
int i=0,j=0,k=0;
unsigned char* base;
base=dev->reg_base;
/***************** register reset *******************/
writeb((iCTL_CCE | iCTL_INI),base+iCTL);// control register
writeb(0,base+iSTAT);//status reister
writeb((iCPU_DMC | iCPU_DSC | iCPU_CEN),base+iCPU);//CPU interface
//writeb(0,base+iHSR);//High Speed Read
writeb((iCLK_SL1 | iCLK_CD1),base+iCLK);//Clock Out Register
writeb((iBUS_CBY),base+iBUS);//Bus Configuration Register
readb(base+iIRQ);//interrupt register
/**************** Write test pattern ********************/
writeb(0x25,base+16+iMSGDAT0);
writeb(0x52,base+32+iMSGDAT3);
writeb(0xc3,base+160+iMSGDAT6);
if(readb(base+16+iMSGDAT0)!=0x25 ||
readb(base+32+iMSGDAT3)!=0x52 ||
readb(base+160+iMSGDAT6)!=0xc3)
{
printk("Could not read back from the hardware.\n");
printk("This probably means that your hardware is not correctly configured!\n");
return -1;
}
else
{
printk("Could read back, hardware is probably configured correctly");
}
/*************** clear message object **********************/
for(i=1;i<16;i++)
{
writeb(INTPD_RES | RXIE_RES | TXIE_RES | MVAL_RES,base+16*i+iMSGCTL0);
writeb(NEWD_RES | MLST_RES | TXRQ_RES | RMPD_RES,base+16*i+iMSGCTL1);
for(j=0;j<4;j++)
{
writeb(0,base+16*i+iMSGID0+j);
}
for(k=0;k<8;k++)
{
writeb(0,base+16*i+iMSGDAT0+j);
}
writeb(0,base+16*i+iMSGCFG);
}
/****************** set timing **************************/
writeb((uint8_t) iCanTiming[9][0],base+iBT0);//Bit Timing Register
writeb((uint8_t) iCanTiming[9][1],base+iBT1);
/****************** set mask ****************************/
writeb(0,base+iSGM0);//Standard Global Mask
writeb(0,base+iSGM1);
writeb(0,base+iEGM0);//Extended Global Mask
writeb(0,base+iEGM1);
writeb(0,base+iEGM2);
writeb(0,base+iEGM3);
writeb(0,base+i15M0);//Message 15 Mask
writeb(0,base+i15M1);
writeb(0,base+i15M2);
writeb(0,base+i15M3);
}
static int ican_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned char* base;
CAN_Dev *dev;
int myarg;
int err=0;
int i=0;
int dev_minor = MINOR(inode->i_rdev) & 0x0f;
base = canDev[dev_minor].reg_base;
dev = canDev + dev_minor;
get_user(myarg, (int *)arg);
if(_IOC_TYPE(cmd) != ICAN_IOC_BASE)
{
return -EINVAL;
}
if(_IOC_NR(cmd) > CAN_IOC_MAXNR)
{
return -EINVAL;
}
if(_IOC_DIR(cmd) & _IOC_READ)
{
err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
}
else if(_IOC_DIR(cmd) & _IOC_WRITE)
{
err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
}
if(err)
{
return -EFAULT;
}
switch(cmd)
{
case ICAN_IOC_SBAUD:
{
if((arg >= 0) && (arg <= 9))
{
i82527_stop_chip(dev);
writeb(iCanTiming[arg][0],base+iBT0);
writeb(iCanTiming[arg][1],base+iBT1);
i82527_start_chip(dev);
}
}
break;
case ICAN_IOC_MASK:
{
//none
}
break;
case ICAN_IOC_CRBUF:
{
dev->nm_rb = 0;
dev->wp_rb = 0;
dev->rp_rb =0;
}
break;
case ICAN_IOC_CWBUF:
{
dev->nm_wb = 0;
dev->wp_wb = 0;
dev->rp_wb =0;
}
break;
case ICAN_IOC_RREG:
{
if(myarg>=0x100)
{
printk("Error reister number\n");
}
else
{
printk("0x%x is 0x%x\n",myarg,readb(base+myarg));
}
}
break;
case ICAN_IOC_RTTS:
{
copy_to_user((struct timeval *)arg, &transmit_timestamp, sizeof(struct timeval));
}
break;
case ICAN_IOC_RAPS:
{
printk("Ican active_passive_status is %d\n",dev->active_passive_status);
}
break;
case ICAN_IOC_SBTR:
{
i82527_stop_chip(dev);
writeb((arg >> 8) & 0xff,base+iBT0);
writeb(arg & 0xff,base+iBT1);
i82527_start_chip(dev);
}
break;
case ICAN_IOC_START:
{
i82527_start_chip(dev);
}
break;
case ICAN_IOC_STOP:
{
i82527_stop_chip(dev);
}
break;
case ICAN_IOC_RESET:
{
i82527_reset_chip(dev);
}
break;
case ICAN_IOC_CONF_FILTER:
{
//none
}
break;
case ICAN_IOC_SEND:
{
//none
}
break;
case ICAN_IOC_RECEIVE:
{
//none
}
break;
default:
{
return -EINVAL;
}
break;
}
return 0;
}
static unsigned int ican_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = 0;
CAN_Dev *dev = filp->private_data;
poll_wait(filp, &inq, wait);
poll_wait(filp, &outq, wait);
if(dev->nm_rb > 0) /* at least one message in the buffer */
mask |= POLLIN | POLLRDNORM; /* readable */
if(dev->nm_wb < BUFFER_SIZE) /* at least one message in the buffer */
mask |= POLLOUT | POLLWRNORM; /* readable */
return mask;
}
static void read_from_INTEL82527(CAN_Dev *dev)
{
int i = 0;
uint8_t msgctlreg;
uint8_t ctl1reg;
uint8_t id0, id1, id2, id3;
unsigned char* base;
base=dev->reg_base;
ctl1reg=readb(base+16*15+iMSGCTL1);
if(dev->nm_rb < BUFFER_SIZE)
{
if( ctl1reg & MLST_SET )
{
printk("\ni82527: Previous message lost\n");
}
if(ctl1reg & NEWD_SET)
{
if (ctl1reg & RMPD_SET)
{
dev->read_buf[dev->wp_rb].rtr=1;
}
msgctlreg=readb(base+16*15+iMSGCFG);
if( msgctlreg & MCFG_XTD )
{
id0=readb(base+16*15+iMSGID3);
id1=readb(base+16*15+iMSGID2)<<8;
id2=readb(base+16*15+iMSGID1)<<16;
id3=readb(base+16*15+iMSGID0)<<24;
dev->read_buf[dev->wp_rb].type=EXTENDED;
dev->read_buf[dev->wp_rb].id=(id0|id1|id2|id3)>>3;
}
else
{
id0=readb(base+16*15+iMSGID1);
id1=readb(base+16*15+iMSGID0)<<8;
dev->read_buf[dev->wp_rb].type=STANDARD;
dev->read_buf[dev->wp_rb].id=(id0|id1|id2|id3)>>5;
}
msgctlreg &= 0xf0;
msgctlreg = msgctlreg >>4;
msgctlreg %= 9;
dev->read_buf[dev->wp_rb].len=msgctlreg;
for (i = 0; i < msgctlreg; i++)
{
dev->read_buf[dev->wp_rb].d[i]=readb(base+16*15+iMSGDAT0+i);
}
do_gettimeofday(&dev->read_buf[dev->wp_rb].timestamp);
transmit_timestamp=dev->read_buf[dev->wp_rb].timestamp;
writeb(MVAL_SET | TXIE_RES | RXIE_SET | INTPD_RES,base+16*15+iMSGCTL0);
writeb(RMPD_RES | TXRQ_RES | MLST_RES | NEWD_RES,base+16*15+iMSGCTL1);
dev->nm_rb++;
dev->wp_rb++;
wake_up_interruptible(&inq);
}
}
else
{
printk("CAN: buffer full, dropping message,this meassage will be release!\n");
}
}
static ssize_t ican_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
int pos, nmrb;
CAN_Dev *dev = (CAN_Dev *)filp->private_data;
pos = dev->rp_rb;
nmrb = dev->nm_rb;
if(nmrb == 0)
{
if(filp->f_flags & O_NONBLOCK)
{
return -EAGAIN;
}
printk("\n can_read! sleep_on inq\n");
interruptible_sleep_on(&inq);
if(signal_pending(current))
{ printk("\n signal_pending \n");
return -ERESTARTSYS;
}
}
if(nmrb > 0)
{
copy_to_user(buf, &dev->read_buf[pos],MSG_LENGTH);
dev->nm_rb--;
dev->rp_rb++;
if(dev->rp_rb == dev->wp_rb)
{ /* Buffer empty */
dev->rp_rb = 0;
dev->wp_rb = 0;
}
return MSG_LENGTH;
}
else
{
printk("No messages available nmrb=0x%x",nmrb);
return -EAGAIN;
}
}
void ican_msgobj15_read_interrupt(CAN_Dev *dev)
{
read_from_INTEL82527(dev);
}
void ican_msgobj_write_interrupt(CAN_Dev *dev)
{
int i=1,j=0;
uint8_t id0, id1, id2, id3;
unsigned long flags;
unsigned char* base;
base=dev->reg_base;
save_flags(flags);
if(dev->nm_wb > 0)
{
writeb(RMPD_RES | TXRQ_RES | CPUU_SET | NEWD_SET,base+16+iMSGCTL1);
writeb(MVAL_SET | TXIE_SET | RXIE_RES | INTPD_RES,base+16+iMSGCTL0);
dev->write_buf[dev->rp_wb].len%=9;
if(dev->write_buf[dev->rp_wb].type == EXTENDED)
{
writeb(dev->write_buf[dev->rp_wb].len<<4 | ( MCFG_DIR | MCFG_XTD ),base+16+iMSGCFG);
id0=dev->write_buf[dev->rp_wb].id << 3;
id1=dev->write_buf[dev->rp_wb].id >> 5;
id2=dev->write_buf[dev->rp_wb].id >> 13;
id3=dev->write_buf[dev->rp_wb].id >> 21;
writeb(id3,base+16+iMSGID0);
writeb(id2,base+16+iMSGID1);
writeb(id1,base+16+iMSGID2);
writeb(id0,base+16+iMSGID3);
}
else
{
writeb(dev->write_buf[dev->rp_wb].len<<4 | ( MCFG_DIR),base+16+iMSGCFG);
id0=dev->write_buf[dev->rp_wb].id << 5;
id1=dev->write_buf[dev->rp_wb].id >> 3;
writeb(id1,base+16+iMSGID0);
writeb(id0,base+16+iMSGID1);
}
for ( j=0; j <dev->write_buf[dev->rp_wb].len ; j++ )
{
writeb( dev->write_buf[dev->rp_wb].d[i],base+16+iMSGDAT0+j);
}
if (dev->write_buf[dev->rp_wb].rtr == REMOTEFRAME)
{
writeb(RMPD_RES | TXRQ_RES | CPUU_RES | NEWD_UNC,base+16+iMSGCTL1);
}
else
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -