www.pudn.com > canbus.rar > mcpcan.c


#include 
#include 
//#include 
#include 
#include  //fla
#include //fla
#include  //fla
#include   //fla
#include  //fla
#if defined(CONFIG_SMP)
#define __SMP__
#endif

#if defined(CONFIG_MODVERSIONS)
#define MODVERSIONS
#endif

#include 
#include 
#include 
#include  	/* for -EBUSY */
//#include 
#include 
#include 	/* for verify_area */
#include 
#include 
//#include 
#include 
#include 
#include 
#include 		/* for module_init */
#include 

#include 
#include 
#include 
#include 
#include 
#include   	/* for get_user and put_user */
#include 
#include 
#include 

#include   //fla
#include  

//#include 

//#include 

//#include 
//#include	
//#include "S3C2410_2.h"

#include "mcpcan.h"
#include	"spi_cmd.h"
#include    "spi.h"

#define	MCP2510_FLAG

#define BUF_SIZE sizeof(struct MCP_device) * 100

unsigned long eintmask,spcon0,spsta0,sppin0,sppre0,sptdat0,sprdat0,spcon1,spsta1,sppin1,sppre1,sptdat1,sprdat1; //fla add for init interrupt!

//#define DEBUG

#ifdef DEBUG
#define DbgPrintk(S) printk(S)
#else
#define DbgPrintk(S)
#endif

struct MCP_device {
       volatile unsigned long RecvBuf;
       volatile unsigned long RecvHead;
       volatile unsigned long RecvTail;
       volatile unsigned long RecvNum;
                                                                                                                                               
       wait_queue_head_t inq;   //or use as a global variable
                                                                                                                                               
       struct semaphore sem;    //semaphore used for mutex
                                                                                                                                               
       unsigned int      IrqNum;
       unsigned int      MinorNum;/*device minor number*/
       unsigned int      BaudRate;
                                                                                                                                               
       unsigned char     *SendBuf;
       unsigned int      SendNum;
       volatile unsigned long SendHead;
       volatile unsigned long SendTail;
};//__attribute__((aligned(L1_CACHE_BYTES),packed));
                                                                                                                                               

/*****************************Variable define*******************************/
unsigned int MCP_major = MCP_MAJOR;
struct MCP_device *Device[MCP_NUM];
unsigned int MCP_irq[MCP_NUM] = {IRQ_EINT8t23,IRQ_EINT8t23};
static char *MCP_name[MCP_NUM] = {"mcpcan0","mcpcan1"};



/*****************************SJA device initialize*************************/
//这个函数用来对struct MCP_device进行初始化
static int MCP_device_init(void)
{
        int res,i;
//        printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);
        for(i=0;iRecvBuf = (unsigned char *)get_free_page(GFP_KERNEL);  //malloc the recv buffer
                Device[i]->RecvBuf = (unsigned long)kmalloc(sizeof(struct MCP_device) * 100,GFP_KERNEL);  //malloc the recv buffer
                if(Device[i]->RecvBuf == 0) {
                        printk(KERN_ALERT"allocate Recv memory failed.\n");
                        return(-ENOMEM);
                }
                memset((char *)Device[i]->RecvBuf,0,sizeof(struct MCP_device) * 100);

                Device[i]->RecvHead = Device[i]->RecvBuf;
                Device[i]->RecvTail = Device[i]->RecvBuf;
                Device[i]->RecvNum = 0;
                //Device[i]->RecvQueue = NULL;

                
                //Device[i]->SendBuf = (unsigned char *)get_free_page(GFP_KERNEL);   //malloc the send buffer
                Device[i]->SendBuf = kmalloc(sizeof(struct MCP_device) * 100,GFP_KERNEL);  //malloc the send buffer
                if(Device[i]->SendBuf == NULL) {
                        printk(KERN_ALERT"allocate Send memory failed.\n");
                        return(-ENOMEM);
                }
                memset((char *)Device[i]->SendBuf,0,sizeof(struct MCP_device) * 100);

                Device[i]->MinorNum = i;
                //Device[i]->FrameMode = 1;
                Device[i]->IrqNum = MCP_irq[i];
                //Device[i]->BaudRate = MCP_baudrate[i];
		init_waitqueue_head(&(Device[i]->inq));
		//init_waitqueue_head(&(Device[i]->outq));
		init_MUTEX(&(Device[i]->sem));
		}
        return 0;
}


/*****************************MCP device initialize*************************/
/* Initialize the mcp2510 */
void MCP2510_Init(int MinorNum )
{
	// Configure the SPI Interface in MX1
	//int canstat = 0;
//  printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);
	SPI_Init( ); 
	// Configure the mcp2510 through spi interface
//  printk("look if in configure mode:%s\n",CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANSTAT)), ARG_UNUSED, ARG_UNUSED )>>5!=0x04?"faile":"okay");
	// Reset controller
	CAN_SPI_CMD( SPI_CMD_RESET, ARG_UNUSED, ARG_UNUSED, ARG_UNUSED );
	

	CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANCTRL)), 0xe0, 0x80 );		// CONFIG MODE

	// make sure we are in configuration mode
	while( (CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANSTAT)), ARG_UNUSED, ARG_UNUSED )>>5)!=0x04 );
//  printk("look if in configure mode:%s\n",CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANSTAT)), ARG_UNUSED, ARG_UNUSED )>>5!=0x04?"faile":"okay");
//  printk("hmmmmmmmmmmm!MCAP2510 NOW IN CONFIGURE MODE!\n");
	// start configuration
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->BFPCTRL)), 	BFPCTRL_INIT_VAL, 	ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXRTSCTRL)), 	TXRTSCTRL_INIT_VAL, ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CNF3)), 		CNF3_INIT_VAL, 		ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CNF2)), 		CNF2_INIT_VAL, 		ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CNF1)),		CNF1_INIT_VAL, 		ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CANINTE)),	CANINTE_INIT_VAL, 	ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->CANINTF)), 	CANINTF_INIT_VAL, 	ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->EFLG)), 		EFLG_INIT_VAL, 		ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0CTRL)), 	TXBnCTRL_INIT_VAL, 	ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB1CTRL)), 	TXBnCTRL_INIT_VAL, 	ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB2CTRL)), 	TXBnCTRL_INIT_VAL, 	ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->RXB0CTRL)), 	RXB1CTRL_INIT_VAL, 	ARG_UNUSED);
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->RXB1CTRL)), 	RXB1CTRL_INIT_VAL, 	ARG_UNUSED);
	
	// switch to normal mode or loopback mode ( for testing)
	//CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANCTRL)), 0xe0, 0x40 );		// LOOP BACK MODE
	CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANCTRL)), 0xe0, 0x00 );		// normal mode
	
	//printk("look if in configure mode:%s\n\
//failed is right,because now in loop back mode!\n",CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANSTAT)), ARG_UNUSED, ARG_UNUSED )>>5!=0x04?"faile":"okay");
	//fla mask for a while!CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANCTRL)), 0xe0, 0x00 );	// NORMAL OPERATION MODE
	
	// Flush the MX1 SPI receive buffer
	
	CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANSTAT)), ARG_UNUSED, ARG_UNUSED );
}




/* Transmit data */
/*
 TxBuf	: select the transmit buffer( 0=buffer0 or 1=buffer1 2=buffer2 )
 IdType	: 0=standard id or 1=extended id
 id	: frame identifier
 DataLen	: the number of byte
 data	: the pointer to data byte
*/
void MCP2510_TX( int TxBuf, int IdType, unsigned int id, int DataLen, char * data )
{
	int i, offset;
  printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);
	switch( TxBuf ){
		case TXBUF0:
			offset = 0;
			break;
		case TXBUF1:
			offset = 0x10;
			break;
		case TXBUF2:
			offset = 0x20;
			break;
	}
	//printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);
	// Set the frame identifier
	if( IdType==STANDID ){
		//printk(KERN_ERR "STANDID,line %d passed!\n",__LINE__);
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0SIDL))+offset, (id&0x7)<<5, ARG_UNUSED );
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0SIDH))+offset, (id>>3)&0xff, ARG_UNUSED );
	}else if( IdType==EXTID ){
		//printk(KERN_ERR "EXTID,line %d passed!\n",__LINE__);
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0EID0))+offset, id&0xff, ARG_UNUSED );
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0EID8))+offset, (id>>8)&0xff, ARG_UNUSED );			
		CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0SIDL)), ((id>>16)&0x3)|0x08, ARG_UNUSED );
	}
	// Set the data length
	CAN_SPI_CMD( SPI_CMD_WRITE, TOLONG(&(MCP2510_MAP->TXB0DLC))+offset, DataLen, ARG_UNUSED );
	// fill the data
	if( DataLen>8 )
		DataLen = 8;
	for( i=0; iTXB0D0))+offset+i, data[i], ARG_UNUSED );
	}

	// initiate transmit
	i = 0;
	while( CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->TXB0CTRL))+offset, ARG_UNUSED, ARG_UNUSED )&0x08 ){
		i++;
		if(i == 1000)printk("Please connect the CAN PORT with wire.");
	}
	printk("HELLO,jupm over error!!\n");
	CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->TXB0CTRL))+offset, 0x08, 0x08 );
}

/* Receive data */
/*
 * RxBuf		: The receive buffer from which the data is get
 * IdType		: Identifier type of the data frame ( STANDID, EXTID )
 * id		: The identifier of the received frame
 * DataLen	: The number of bytes received
 * data		: The received data
 */
void MCP2510_RX( int RxBuf, int *IdType, unsigned int *id, int *DataLen, char *data )
{
	unsigned int flag;
	int offset, i;
	//printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);
	switch( RxBuf ){
		case RXBUF0:
			flag = 0x1;
			offset = 0x00;
			break;
		case RXBUF1:
			flag = 0x2;
			offset = 0x10;
			break;
	}
	// wait for a frame to com
	while( !(CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANINTF)), ARG_UNUSED, ARG_UNUSED )&flag) );

	// Get the identifier
	if( CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->RXB0SIDL))+offset, ARG_UNUSED, ARG_UNUSED )&0x08 ){
		// Extended identifier
		if( IdType )
			*IdType = EXTID;
		if( id ){
			*id = (CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->RXB0SIDL))+offset, ARG_UNUSED, ARG_UNUSED )&0x3)<<16;
			*id |= (CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->RXB0EID8))+offset, ARG_UNUSED, ARG_UNUSED ))<<8;
			*id |= (CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->RXB0EID0))+offset, ARG_UNUSED, ARG_UNUSED ));
		}
	}else{
		// Standard identifier
		if( IdType )
			*IdType = STANDID;
		if( id ){
			*id = (CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->RXB0SIDH))+offset, ARG_UNUSED, ARG_UNUSED ))<<3;
			*id |= (CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->RXB0SIDL))+offset, ARG_UNUSED, ARG_UNUSED ))>>5;
		}
	}
	// Get the data frame lenth
	if( DataLen )
		*DataLen = (CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->RXB0DLC))+offset, ARG_UNUSED, ARG_UNUSED )&0xf);
	// Get the data
	for( i=0; DataLen&&(i<*DataLen)&&data; i++ ){
		data[i] = CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->RXB0D0))+offset+i, ARG_UNUSED, ARG_UNUSED );
	}
	// clear the receive int flag
	CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANINTF)), flag, 0x00 );
	
}


/*
 * Atomicly increment an index into shortp_in_buffer
 */
static inline void incr_buffer_pointer(volatile unsigned long*index, int delta, int i)
{
	unsigned long newvalue = *index + delta;
	//printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);
	barrier ();  /* Don't optimize these two together */
	*index = (newvalue >= (Device[i]->RecvBuf + BUF_SIZE)) ? Device[i]->RecvBuf : newvalue;
}

//add irqreturn_t fla
static irqreturn_t mcpcan0_handler(int irq, void *dev_id, struct pt_regs *reg)
{
	struct MCP_device *dev = dev_id;
	struct mcpcan_data datagram;
	int written;
	char regvalue, regvalue2;
	//struct mcpcan_data *datagramptr;
  printk(KERN_ERR "hello,finally enter %s!!!!!!!!!!!!!!!!!!!!!!!!\n",__FUNCTION__);
	printk(KERN_ERR "\rextern irq 8 handled\n");

	regvalue = CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANINTE)), ARG_UNUSED, ARG_UNUSED );
	//printk("CANINTE = 0x%02x\n",regvalue);

	regvalue = CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANINTF)), ARG_UNUSED, ARG_UNUSED );
	//printk("CANINTF = 0x%02x\n",regvalue);

	if(regvalue & 0x01){
		datagram.BufNo = RXBUF0;
		MCP2510_RX(datagram.BufNo, &(datagram.IdType), &(datagram.id), &(datagram.DataLen), datagram.data );
		//printk("RXBUF0\n");

        //printk("datagram.BufNo = %d\n",datagram.BufNo);
        //printk("datagram.IdType = %d\n",datagram.IdType);
        //printk("datagram.id = %d\n",datagram.id);
        //printk("datagram.DataLen = %d\n",datagram.DataLen);
        //printk("datagram.data = %s\n",datagram.data);

	    /* Write a 16 byte record. Assume BUF_SIZE is a multiple of 16 */
		memcpy((void *)dev->RecvHead, &datagram, sizeof(struct mcpcan_data));
		//datagramptr = (struct mcpcan_data *)dev->RecvHead;
		//printk("RecvHead->BufNo = %d\n",datagramptr->BufNo);
		//printk("RecvHead->IdType = %d\n",datagramptr->IdType);
		//printk("RecvHead->id = %d\n",datagramptr->id);
		//printk("RecvHead->DataLen = %d\n",datagramptr->DataLen);
		//printk("RecvHead->data = %s\n",datagramptr->data);


		incr_buffer_pointer(&(dev->RecvHead), sizeof(struct mcpcan_data), dev->MinorNum);
		wake_up_interruptible(&(dev->inq)); /* awake any reading process */
		CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANINTF)), 0x01, 0x00 );     //in fact already clear interrupt bit in RX 
	}

	if(regvalue & 0x02){
		datagram.BufNo = RXBUF1;

		//this function should be rewritten to receive datagram from RXB1??????????????????
		MCP2510_RX(datagram.BufNo, &(datagram.IdType), &(datagram.id), &(datagram.DataLen), datagram.data );
		//printk("RXBUF1\n");


	    /* Write a 16 byte record. Assume BUF_SIZE is a multiple of 16 */
		memcpy((void *)dev->RecvHead, &datagram, sizeof(struct mcpcan_data));
		

		incr_buffer_pointer(&(dev->RecvHead), sizeof(struct mcpcan_data), dev->MinorNum);
		wake_up_interruptible(&dev->inq); /* awake any reading process */
		CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANINTF)), 0x02, 0x00 );     //in fact already clear interrupt bit in RX
	}

	if(regvalue & 0xe0){
		printk("CAN error with CANINTF = 0x%02x.\n", regvalue);
		if(regvalue & 0x80)printk("MERRF:message error.\n");
		if(regvalue & 0x40)printk("WAKIF:wake up interrupt.\n");
		if(regvalue & 0x20)printk("ERRIF:CAN bus error interrupt.\n");
		
		regvalue2 = CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->EFLG)), ARG_UNUSED, ARG_UNUSED );
		printk("EFLG = 0x%02x.\n", regvalue2);
                regvalue2 = CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->TEC)), ARG_UNUSED, ARG_UNUSED );
                printk("TEC = 0x%02x.\n", regvalue2);
                regvalue2 = CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->REC)), ARG_UNUSED, ARG_UNUSED );
                printk("REC = 0x%02x.\n", regvalue2);

		CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANINTF)), 0xe0, 0x00 );
	}

	if(CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANINTF)), ARG_UNUSED, ARG_UNUSED ) & 0x1c){  //didn't open the 3 send interrupts
		CAN_SPI_CMD( SPI_CMD_BITMOD, TOLONG(&(MCP2510_MAP->CANINTF)), 0x1c, 0x00 ); //clear TX bits directly(it will set 1,but no int)
	}

        regvalue = CAN_SPI_CMD( SPI_CMD_READ, TOLONG(&(MCP2510_MAP->CANINTF)), ARG_UNUSED, ARG_UNUSED );
	//printk("after interrupt processing, CANINTF = 0x%02x\n",regvalue);
	
	return IRQ_HANDLED; //fla
}

static void mcpcan1_handler(int irq, void *dev_id, struct pt_regs *regs)
{
	//printk("\rextern irq ? handled");



}

/*****************************MCPCAN open**********************************/
static int device_open(struct inode *inode,struct file *filp)
{
    int MinorNum;
	int eint_irq;
	int ret_val;
    struct MCP_device *dev;
	static int irqcount0=0, irqcount1=0;
	
	//printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);

   // MinorNum = MINOR(inode->i_rdev);
    MinorNum = iminor(inode);
    
    if(MinorNum >= MCP_NUM) return(-ENODEV);
        
    dev = Device[MinorNum];
    filp->private_data = dev;        //save to private_data

	
	//request_region(0x59000000,0x38,"MCPCAN");    //SPI interface
	request_mem_region(0x59000000,0x38,"MCPCAN");
	
	//request_region(0x56000000,0x94,"MCPCAN");  //I/O port
	request_mem_region(0x56000000,0x94,"MCPCAN");
	
	//request_region(0x4c00000c,4,"MCPCAN");  //clock
   request_mem_region(0x4c00000c,4,"MCPCAN");

	if(irqcount0 == 0){
		eint_irq = IRQ_EINT11;
		
		
//now set extint for eint8 instead of the up line!

s3c2410_gpio_cfgpin(S3C2410_GPG3, S3C2410_GPG3_EINT11);
writel(readl(S3C2410_INTMSK)& (~(1<<5)),S3C2410_INTMSK);
writel(readl(eintmask)& (~(1<<11)),eintmask);
writel(readl(S3C2410_EXTINT1)|(0x00007000)&(0xffffbfff),S3C2410_EXTINT1);
s3c2410_gpio_pullup(S3C2410_GPG3,0); //dis

ret_val = request_irq(eint_irq, mcpcan0_handler, SA_INTERRUPT | SA_SHIRQ, MCP_name[dev->MinorNum], dev);
		if (ret_val < 0) {
			return ret_val;
		}
		irqcount0++;
	}

	MCP2510_Init(MinorNum);
printk(KERN_ERR "INTMSK = %08x\nEINTMASK = %08x\n\
CLKCON = %08x\nSPCON0 = %08x\nGPECON = %08x\nGPGCON = %08x\n",readl(S3C2410_INTMSK),readl(eintmask),
readl(S3C2410_CLKCON),readl(spcon0),readl(rGPECON),readl(rGPGCON));
//	MOD_INC_USE_COUNT;
    return 0;
}

/*****************************Functin MCP_release**************************/
static int device_release(struct inode *inode,struct file *filp)
{
	struct MCP_device *dev = filp->private_data;
  //printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);
	release_region(0x59000000,0x38);
	release_region(0x56000000,0x94);
	release_region(0x4c00000c,4);

	free_irq(dev->IrqNum,dev);    //shared irq

	//MOD_DEC_USE_COUNT;
	return 0;
}

ssize_t device_read (struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
	int count0;
	
	struct MCP_device *dev = filp->private_data;
	//printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);
	if (down_interruptible(&dev->sem))
		return -ERESTARTSYS;

	while (dev->RecvHead == dev->RecvTail) 
	{ /* nothing to read */
		up(&dev->sem); /* release the lock */
		if (filp->f_flags & O_NONBLOCK)
			return -EAGAIN; 
		if (wait_event_interruptible(dev->inq, (dev->RecvHead != dev->RecvTail)))
			{
			return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
			}
		/* otherwise loop, but first reacquire the lock */
		
		if (down_interruptible(&dev->sem))
			return -ERESTARTSYS;
	}
	/* ok, data is there, return something */
	/* count0 is the number of readable data bytes */
	count0 = dev->RecvHead - dev->RecvTail;
	if (count0 < 0) /* wrapped */
		count0 = dev->RecvBuf + BUF_SIZE - dev->RecvTail;
	if (count0 < count) count = count0;
	if (copy_to_user(buf, (char *)dev->RecvTail, count)){
		up (&dev->sem);
		return -EFAULT;
	}
	incr_buffer_pointer(&(dev->RecvTail), count, dev->MinorNum);
	up (&dev->sem);

	return count;
}

ssize_t device_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
	mcpcan_data     temp;
	//printk(KERN_ERR "hello,enter %s\n",__FUNCTION__);
	struct MCP_device *dev = filp->private_data;
	if(down_interruptible(&dev->sem))
		return -ERESTARTSYS;
	copy_from_user(&temp, buf, sizeof(struct mcpcan_data));
        printk(KERN_ERR "hello,TX data in kernel is %s\n",temp.data);
		
	MCP2510_TX(temp.BufNo,temp.IdType,temp.id,temp.DataLen,temp.data );
	up(&dev->sem);
       
	return count;
}





/* This function is called whenever a process tries to 
 * do an ioctl on our device file. We get two extra 
 * parameters (additional to the inode and file 
 * structures, which all device functions get): the number
 * of the ioctl called and the parameter given to the 
 * ioctl function.
 *
 * If the ioctl is write or read/write (meaning output 
 * is returned to the calling process), the ioctl call 
 * returns the output of this function.
 */
/*
int device_ioctl(
    struct inode *inode,
    struct file *file,
    unsigned int ioctl_num,// The number of the ioctl 
    unsigned long ioctl_param) // The parameter to it 
{
}
*/



/*****************************File operations define************************/
struct file_operations Fops = {
    .open = device_open,    //open
    .release = device_release,    //release
	.read = device_read,
	.write = device_write
};

/****************************Module initialize******************************/
static int __init mcpcan_init_module(void)
{
        int res;

        //EXPORT_NO_SYMBOLS;
//       printk(KERN_ERR "hello,enter mcpcan_init_module!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        /* Register the character device (atleast try) */
        res = register_chrdev(MCP_major,"MCPCAN",&Fops);
        if(res < 0) {
               printk("device register failed with %d.\n",res);
               return res;
        }

        if(MCP_major == 0) MCP_major = res;


	    MCP_device_init();
   
    //intmsk = ioremap(0x4A000008,4);
    eintmask = ioremap(0x560000A4,4);
   // extint0 = ioremap(0x56000088,4);
    //extint1 = ioremap(0x5600008c,4);
    //extint2 = ioremap(0x56000090,4);
    
    //map spi regs for spi.c
    spcon0 = ioremap(0x59000000,4);
    spsta0 = ioremap(0x59000004,4);
    sppin0 = ioremap(0x59000008,4);
    sppre0 = ioremap(0x5900000c,4);
    sptdat0 = ioremap(0x59000010,4);
    sprdat0 = ioremap(0x59000014,4);
    
    spcon1 = ioremap(0x59000020,4);
    spsta1 = ioremap(0x59000024,4);
    sppin1 = ioremap(0x59000028,4);
    sppre1 = ioremap(0x5900002c,4);
    sptdat1 = ioremap(0x59000030,4);
    sprdat1 = ioremap(0x59000034,4);
    
    //printk(KERN_ERR "in mcpcan.c:the maped addr of sptdat = %#p",sptdat0);
		//printk ("%s The major device number is %d.\n",
			//	"Registeration is a success", 
			//	MCP_major);
		          
		printk (KERN_ERR "hello,you have insert module that support MCP2510,to make\n");
		printk (KERN_ERR "use of it, you must use: mknod /dev/%s c %d 0,and you can\n","can",MCP_major);
		printk (KERN_ERR "run test demo named 2510test for a test in loop back mode\n");
    printk (KERN_ERR "you'll modify the driver to make it fall into normal mode\n");

        return 0;
}

/****************************Module release********************************/
static void __exit mcpcan_cleanup_module(void)
{
	int i;
    unregister_chrdev(MCP_major,"MCPCAN");
	for(i=0; i<2; i++){
		kfree((void *)Device[i]->RecvBuf);
		kfree(Device[i]->SendBuf);
		kfree(Device[i]);
	}
    printk("MCPCAN release success.\n");
}

module_init(mcpcan_init_module);
module_exit(mcpcan_cleanup_module);

MODULE_AUTHOR("witech ");
MODULE_DESCRIPTION("MCP251X driver");
MODULE_LICENSE("Dual BSD/GPL");