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

📄 s3c2410-can-mcp2510.c

📁 CAN总线设备驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
}// Setup the CAN buffers used by the application.// We currently use only one for reception and one for transmission.// It is possible to use several to get a simple form of queue.//// We setup the unit to receive all CAN messages.// As we only have at most 4 different messages to receive, we could use the// filters to select them for us.//// mcp_init() should already have been called.static void MCP2510_Setup(PCanFilter pfilter){    // As no filters are active, all messages will be stored in RXB0 only if    // no roll-over is active. We want to recieve all CAN messages (standard and extended)    // (RXM<1:0> = 11).    //SPI_mcp_write_bits(RXB0CTRL, RXB_RX_ANY, 0xFF);    //SPI_mcp_write_bits(RXB1CTRL, RXB_RX_ANY, 0xFF);    // But there is a bug in the chip, so we have to activate roll-over.	if(pfilter){	//有过滤器		MCP2510_WriteBits(RXB0CTRL, (RXB_BUKT|RXB_RX_STDEXT|RXB_RXRTR|RXB_RXF0), 0xFF);		MCP2510_WriteBits(RXB1CTRL, RXB_RX_STDEXT, 0xFF);	}	else{		MCP2510_WriteBits(RXB0CTRL, (RXB_BUKT|RXB_RX_ANY|RXB_RXRTR), 0xFF);		MCP2510_WriteBits(RXB1CTRL, RXB_RX_ANY, 0xFF);	}}/***********************************************************************************\								发送数据	参数:		data,发送数据	Note: 使用三个缓冲区循环发送,没有做缓冲区有效检测\***********************************************************************************/static int ntxbuffer=0;static inline void MCP2510_canTxBuffer(void){	switch(ntxbuffer){	case 0:		MCP2510_transmit(TXB0CTRL);		ntxbuffer=1;		break;	case 1:		MCP2510_transmit(TXB1CTRL);		ntxbuffer=2;		break;	case 2:		MCP2510_transmit(TXB2CTRL);		ntxbuffer=0;		break;	}}static inline void MCP2510_canWrite(PCanData data){	MCP2510_Write_Can(ntxbuffer, data);	MCP2510_canTxBuffer();}static inline void MCP2510_canWriteData(char *pbuffer, int nbuffer){	MCP2510_Write_CanData(ntxbuffer, pbuffer, nbuffer);	MCP2510_canTxBuffer();}static inline void MCP2510_canWriteRTR(void){	MCP2510_Write_CanRTR(ntxbuffer);	MCP2510_canTxBuffer();}/***********************************************************************************\								中断服务程序									\***********************************************************************************/static void s3c2410_isr_mcp2510(int irq, void *dev_id, struct pt_regs *reg){	unsigned char byte;	DPRINTK("enter interrupt!\n");	byte=MCP2510_Read(CANINTF);		if(byte & RX0INT){		MCP2510_Read_Can(3,&(mcp2510dev.MCP2510_Candata[mcp2510dev.nCanRevpos]));		MCP2510_WriteBits(CANINTF, ~RX0INT, RX0INT); // Clear interrupt		NextCanDataPos(mcp2510dev.nCanRevpos);		DPRINTK("mcp2510dev.nCanRevpos= %d\n", mcp2510dev.nCanRevpos);		DPRINTK("mcp2510dev.nCanReadpos= %d\n", mcp2510dev.nCanReadpos);	}	if(byte & RX1INT){		MCP2510_Read_Can(4,&(mcp2510dev.MCP2510_Candata[mcp2510dev.nCanRevpos]));		MCP2510_WriteBits(CANINTF, ~RX1INT, RX1INT); // Clear interrupt		NextCanDataPos(mcp2510dev.nCanRevpos);	}	if(byte & (RX0INT|RX1INT)){		wake_up_interruptible(&(mcp2510dev.wq));	}}/*********************************************************************\	CAN设备初始化函数	参数:	bandrate,CAN波特率\*********************************************************************/static int init_MCP2510(CanBandRate bandrate){	unsigned char i,j,a;	MCP2510_Reset();	MCP2510_SetBandRate(bandrate,FALSE);	// Disable interrups.	MCP2510_Write(CANINTE, NO_IE);	// Mark all filter bits as don't care:	MCP2510_Write_Can_ID(RXM0SIDH, 0, TRUE);	MCP2510_Write_Can_ID(RXM1SIDH, 0, TRUE);	// Anyway, set all filters to 0:	MCP2510_Write_Can_ID(RXF0SIDH, 0, 0);	MCP2510_Write_Can_ID(RXF1SIDH, 0, 0);	MCP2510_Write_Can_ID(RXF2SIDH, 0, 0);	MCP2510_Write_Can_ID(RXF3SIDH, 0, 0);	MCP2510_Write_Can_ID(RXF4SIDH, 0, 0);	MCP2510_Write_Can_ID(RXF5SIDH, 0, 0);	MCP2510_Write_Can_ID(TXB0SIDH, 123, 0);	MCP2510_Write_Can_ID(TXB1SIDH, 100, 0);	MCP2510_Write_Can_ID(TXB2SIDH, 111, 0);	//Enable clock output	MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1);	// Clear, deactivate the three transmit buffers	a = TXB0CTRL;	for (i = 0; i < 3; i++) {		for (j = 0; j < 14; j++) {			MCP2510_Write(a, 0);			a++;	        }       	a += 2; // We did not clear CANSTAT or CANCTRL	}	// and the two receive buffers.	MCP2510_Write(RXB0CTRL, 0);	MCP2510_Write(RXB1CTRL, 0);	// The two pins RX0BF and RX1BF are used to control two LEDs; set them as outputs and set them as 00.	MCP2510_Write(BFPCTRL, 0x3C);		return 0;}static void MCP2510_SetFilter(PCanFilter pfilter){	MCP2510_Write(MCP2510REG_CANCTRL, MODE_CONFIG);	// Disable interrups.	MCP2510_Write(CANINTE, NO_IE);	if(!pfilter){		// Mark all filter bits as don't care:		MCP2510_Write_Can_ID(RXM0SIDH, 0, TRUE);		MCP2510_Write_Can_ID(RXM1SIDH, 0, TRUE);		// Anyway, set all filters to 0:		MCP2510_Write_Can_ID(RXF0SIDH, 0, 0);		MCP2510_Write_Can_ID(RXF1SIDH, 0, 0);		MCP2510_Write_Can_ID(RXF2SIDH, 0, 0);		MCP2510_Write_Can_ID(RXF3SIDH, 0, 0);		MCP2510_Write_Can_ID(RXF4SIDH, 0, 0);		MCP2510_Write_Can_ID(RXF5SIDH, 0, 0);	}	else{		// Mark		MCP2510_Write_Can_ID(RXM0SIDH, pfilter->Mask, TRUE);		MCP2510_Write_Can_ID(RXM1SIDH, pfilter->Mask, TRUE);		// set all filters to same = pfilter->Filter:		MCP2510_Write_Can_ID(RXF0SIDH, pfilter->Filter, pfilter->IsExt);		MCP2510_Write_Can_ID(RXF1SIDH, pfilter->Filter, pfilter->IsExt);		MCP2510_Write_Can_ID(RXF2SIDH, pfilter->Filter, pfilter->IsExt);		MCP2510_Write_Can_ID(RXF3SIDH, pfilter->Filter, pfilter->IsExt);		MCP2510_Write_Can_ID(RXF4SIDH, pfilter->Filter, pfilter->IsExt);		MCP2510_Write_Can_ID(RXF5SIDH, pfilter->Filter, pfilter->IsExt);	}	//Enable clock output	if(mcp2510dev.loopbackmode)		MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1);	else		MCP2510_Write(CLKCTRL, MODE_NORMAL| CLKEN | CLK1);	// and the two receive buffers.	MCP2510_Write(RXB0CTRL, 0);	MCP2510_Write(RXB1CTRL, 0);	MCP2510_Setup(pfilter);}static int s3c2410_mcp2510_ioctl(struct inode *inode, struct file *file,                                 unsigned int cmd, unsigned long arg){	int flags;local_irq_save(flags);	switch (cmd){	case UPCAN_IOCTRL_SETBAND:	//set can bus band rate		MCP2510_SetBandRate((CanBandRate)arg ,TRUE);		mdelay(10);		break;	case UPCAN_IOCTRL_SETID:	//set can frame id data		MCP2510_Write_Can_ID(TXB0SIDH, arg, arg&UPCAN_EXCAN);		MCP2510_Write_Can_ID(TXB1SIDH, arg, arg&UPCAN_EXCAN);		MCP2510_Write_Can_ID(TXB2SIDH, arg, arg&UPCAN_EXCAN);		break;	case UPCAN_IOCTRL_SETLPBK:	//set can device in loop back mode or normal mode		if(arg){			MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1);			mcp2510dev.loopbackmode=1;		}		else{			MCP2510_Write(CLKCTRL, MODE_NORMAL| CLKEN | CLK1);			mcp2510dev.loopbackmode=0;		}		break;	case UPCAN_IOCTRL_SETFILTER://set a filter for can device		MCP2510_SetFilter((PCanFilter)arg);		break;	case UPCAN_IOCTRL_PRINTRIGISTER://set a filter for can device		printGPE();		printSPI();		printRegisters();		break;			}	local_irq_restore(flags);		DPRINTK("IO control command=0x%x\n", cmd);	return 0;}/***************************************************************\*	write and send Can data interface for can device	 file					**	there are 2 mode for send data:									**		1, if write data size = sizeof(CanData) then send a full can frame	**		2, if write data size <=8 then send can data,					**		    we must set frame id first									*\****************************************************************/static ssize_t s3c2410_mcp2510_write(struct file *file, const char *buffer, 				    size_t count, loff_t * ppos){	char sendbuffer[sizeof(CanData)];	if(count==sizeof(CanData)){		//send full Can frame---frame id and frame data		copy_from_user(sendbuffer, buffer, sizeof(CanData));		MCP2510_canWrite((PCanData)sendbuffer);		DPRINTK("Send a Full Frame\n");		return count;	}	if(count>8)		return 0;	//count <= 8	copy_from_user(sendbuffer, buffer, count);	MCP2510_canWriteData(sendbuffer, count);	DPRINTK("Send data size=%d\n", count);       DPRINTK("data=%x,%x,%x,%x,%x,%x,%x,%x\n",		sendbuffer[0],sendbuffer[1],sendbuffer[2],sendbuffer[3],		sendbuffer[4],sendbuffer[5],sendbuffer[6],sendbuffer[7]);	return count;}static int RevRead(CanData *candata_ret){	spin_lock_irq(&(mcp2510dev.lock));	memcpy(candata_ret, 		&(mcp2510dev.MCP2510_Candata[mcp2510dev.nCanReadpos]), 		sizeof(CanData));	NextCanDataPos(mcp2510dev.nCanReadpos);	spin_unlock_irq(&(mcp2510dev.lock));	return sizeof(CanData);}static ssize_t s3c2410_mcp2510_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){	CanData candata_ret;		DPRINTK("run in s3c2410_mcp2510_read\n");retry: 	if (mcp2510dev.nCanReadpos !=  mcp2510dev.nCanRevpos) {		int count;		count = RevRead(&candata_ret);		if (count) copy_to_user(buffer, (char *)&candata_ret, count);		DPRINTK("read data size=%d\n", count);		DPRINTK("id=%x, data=%x,%x,%x,%x,%x,%x,%x,%x\n", 			candata_ret.id, candata_ret.data[0],			candata_ret.data[1], candata_ret.data[2], 			candata_ret.data[3], candata_ret.data[4],			candata_ret.data[5], candata_ret.data[6],			candata_ret.data[7]);		return count;	} else {		if (filp->f_flags & O_NONBLOCK) {			return -EAGAIN;		}		interruptible_sleep_on(&(mcp2510dev.wq));		if (signal_pending(current)){			return -ERESTARTSYS;		}		goto retry;	}	DPRINTK("read data size=%d\n", sizeof(candata_ret));	return sizeof(candata_ret);}static int s3c2410_mcp2510_open(struct inode *inode, struct file *file){	int i,j,a;	if(opencount==1)		return -EBUSY;	opencount++;	memset(&mcp2510dev, 0 ,sizeof(mcp2510dev));	init_waitqueue_head(&(mcp2510dev.wq));	//Enable clock output	MCP2510_Write(CLKCTRL, MODE_NORMAL| CLKEN | CLK1);	// Clear, deactivate the three transmit buffers	a = TXB0CTRL;	for (i = 0; i < 3; i++) {		for (j = 0; j < 14; j++) {			MCP2510_Write(a, 0);			a++;	    }	    a += 2; // We did not clear CANSTAT or CANCTRL	}	// and the two receive buffers.	MCP2510_Write(RXB0CTRL, 0);	MCP2510_Write(RXB1CTRL, 0);	//Open Interrupt	MCP2510_Write(CANINTE, RX0IE|RX1IE);	MCP2510_Setup(NULL);	MCP2510_OPEN_INT();	set_gpio_ctrl(GPIO_MCP2510_CS);	MOD_INC_USE_COUNT;	DPRINTK("device open\n");	return 0;}static int s3c2410_mcp2510_release(struct inode *inode, struct file *filp){	opencount--;	MCP2510_Write(CANINTE, NO_IE);	MCP2510_Write(CLKCTRL, MODE_LOOPBACK| CLKEN | CLK1);	MCP2510_CLOSE_INT();	MOD_DEC_USE_COUNT;	DPRINTK("device release\n");	return 0;}static struct file_operations s3c2410_fops = {	owner:	THIS_MODULE,	write:	s3c2410_mcp2510_write,	read:	s3c2410_mcp2510_read,	ioctl:	s3c2410_mcp2510_ioctl,	open:	s3c2410_mcp2510_open,	release:	s3c2410_mcp2510_release,};#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_spi_dir, devfs_spiraw;#endifstatic int __init s3c2410_mcp2510_init(void){	int ret;	int flags;	set_gpio_ctrl(GPIO_MCP2510_CS);	printGPE();  	printSPI();	printRegisters();	local_irq_save(flags);		init_MCP2510(BandRate_250kbps);	/* Register IRQ handlers */		ret = set_external_irq(MCP2510_IRQ, EXT_LOWLEVEL, GPIO_PULLUP_DIS);	if (ret)		return ret;	local_irq_restore(flags);	ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);	if (ret < 0) {		printk(DEVICE_NAME " can't get major number\n");		return ret;	}	Major = ret;	/* Enable touch interrupt */	ret = request_irq(MCP2510_IRQ, s3c2410_isr_mcp2510, SA_INTERRUPT, 			  DEVICE_NAME, s3c2410_isr_mcp2510);	if (ret) 			return ret;	MCP2510_CLOSE_INT();#ifdef CONFIG_DEVFS_FS	devfs_spi_dir = devfs_mk_dir(NULL, "can", NULL);	devfs_spiraw = devfs_register(devfs_spi_dir, "0", DEVFS_FL_DEFAULT,			Major, SPIRAW_MINOR, S_IFCHR | S_IRUSR | S_IWUSR,			&s3c2410_fops, NULL);#endif	printk(DEVICE_NAME " initialized\n");		return 0;}static void __exit s3c2410_mcp2510_exit(void){	printk(DEVICE_NAME " unloaded\n");}module_init(s3c2410_mcp2510_init);module_exit(s3c2410_mcp2510_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -