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

📄 mcp2510.c

📁 英贝德ebd9200-I开发板linux下CAN测试程序(MCP2510)
💻 C
字号:
/* * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder) * * (c) SAN People (Pty) Ltd * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version.*/#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <asm/arch/AT91RM9200_SPI.h>#include <asm/arch/pio.h>#include "mcp2510.h"#include "../spi/at91_spi.h"
#include <asm/uaccess.h>#ifdef CONFIG_DEVFS_FS#include <linux/devfs_fs_kernel.h>#endif#undef DEBUG_MCP2510//#define DEBUG_MCP2510#define CAN_MAJOR		250	/* registered device number */#define NR_CAN_DEVICES  	2	/* number of devices on SPI bus */#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_handle = NULL;static devfs_handle_t devfs_mcp2510[NR_CAN_DEVICES];#endif#define	WRITE_COM		1#define	READ_COM		2#define	RESET_COM		3#define	BWM_COM			4#define	RTS_COM			5/* ......................................................................... */static struct spi_transfer_list spi_transfer_desc;/* * Perform a SPI transfer to access the CAN device. */static int d_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,		char* txnext, int txnext_len, char* rxnext, int rxnext_len){	struct spi_transfer_list* list = (struct spi_transfer_list *)&spi_transfer_desc;	list->tx[0] = tx;	list->txlen[0] = tx_len;	list->rx[0] = rx;	list->rxlen[0] = rx_len;	list->tx[1] = txnext; 	list->txlen[1] = txnext_len;	list->rx[1] = rxnext;	list->rxlen[1] = rxnext_len;	list->nr_transfers = nr;	return spi_transfer(list);}static int mcp2510_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	void *data;	char* databuf;	char* command;			struct mcp2510_local mcpFrame;	int spi_device = MINOR(inode->i_rdev);	if (spi_device >= NR_SPI_DEVICES)		return -ENODEV;	data = (void *) arg;	if (copy_from_user(&mcpFrame,data,sizeof(struct mcp2510_local)))	{		printk("copy mcpFrame from fail\n");	}	databuf = kmalloc(mcpFrame.len, GFP_KERNEL);	if (!databuf){		printk("malloc memory fail\n");		return 0;	}	command = kmalloc(2, GFP_KERNEL);	if (!command){		printk("malloc memory fail\n");		return 0;	}	spi_access_bus(spi_device);	switch(cmd) {		case WRITE_COM:			if (copy_from_user(databuf, mcpFrame.pData, mcpFrame.len))			{				printk("copy_from_user fail\n");			}			command[0] = WRITE_CM;			command[1] = mcpFrame.addr;#ifdef DEBUG_MCP2510//			printk("WRITE:addr=%x len=%x\n",command[1],mcpFrame.len);#endif			d_spi_transfer(2,command,2,command,2,databuf,mcpFrame.len,databuf, mcpFrame.len);			break;		case READ_COM:			command[0] = READ_CM;			command[1] = mcpFrame.addr;#ifdef DEBUG_MCP2510//			printk("READ:addr=%x len=%x\n",command[1],mcpFrame.len);#endif			d_spi_transfer(2,command,2,command,2,databuf,mcpFrame.len,databuf, mcpFrame.len);			if (copy_to_user(mcpFrame.pData, databuf, mcpFrame.len))			{				printk("copy_to_user fail\n");			}			break;		case RESET_COM:			command[0] = RESET_CM;			command[1] = 0;			d_spi_transfer(1,command,2,command,2,NULL, 0, NULL, 0);			break;		case BWM_COM:			if (copy_from_user(databuf, mcpFrame.pData, mcpFrame.len))			{				printk("copy_from_user fail\n");			}			command[0] = BIT_MOD_CM;			command[1] = mcpFrame.addr;#ifdef DEBUG_MCP2510			printk("BWM:addr=%x mask=%x data=%x\n",command[1],databuf[0],databuf[1]);#endif			d_spi_transfer(2,command,2,command,2,databuf,mcpFrame.len,databuf,mcpFrame.len);			break;		case RTS_COM:			command[0] = mcpFrame.addr;			d_spi_transfer(1,command,1,command, 1, NULL, 0, NULL, 0);			break;		default:#ifdef DEBUG_MCP2510				printk("default device%d\n",spi_device-2);#endif			break;	}		spi_release_bus(spi_device);		kfree(databuf);		kfree(command);		return 0;}/* * Open the SPI device */static int mcp2510_open(struct inode *inode, struct file *file){	unsigned int spi_device = MINOR(inode->i_rdev);	if (spi_device >= NR_SPI_DEVICES)		return -ENODEV;	MOD_INC_USE_COUNT;	/*	 * 'private_data' is actually a pointer, but we overload it with the	 * value we want to store.	 */	(unsigned int) file->private_data = spi_device;	printk("CAN %i open\n",spi_device-2);//configure power for  pio	AT91_SYS->PMC_PCER = 1 << AT91C_ID_PIOC;	/* enable peripheral clock *///configure input mode	AT91_SYS->PIOC_ODR = AT91C_PIO_PC15|AT91C_PIO_PC14;	AT91_SYS->PIOC_PER = AT91C_PIO_PC15|AT91C_PIO_PC14;//enable interrupt 
        AT91_SYS->PIOC_IER = AT91C_PIO_PC15|AT91C_PIO_PC14;
    	AT91_SYS->AIC_IECR = 0x1 << AT91C_ID_PIOC ;
	return 0;}/* * Close the SPI device */static int mcp2510_close(struct inode *inode, struct file *file){	unsigned int spi_device = MINOR(inode->i_rdev);	MOD_DEC_USE_COUNT;	printk("CAN %i close\n",spi_device-2);	return 0;}/* ......................................................................... *//* * Handle interrupts from the SPI controller. */static void can_interrupt(int irq, void *dev_id, struct pt_regs *regs){ 	unsigned int status;
    unsigned int mask = 0x1 << AT91C_ID_PIOC;
    //* Disable the interrupt on the interrupt controller
    AT91_SYS->AIC_IDCR = mask ;
    //* Clear the interrupt on the Interrupt Controller ( if one is pending )
    AT91_SYS->AIC_ICCR = mask ;
    	status =AT91_SYS->PIOC_ISR;	if((status&AT91C_PIO_PC14)==AT91C_PIO_PC14){		if(((AT91_SYS->PIOC_PDSR)&AT91C_PIO_PC14?0:1))		{			printk("can_interrupt 0 %x\n",status);	    		goto exit;  		}	    	goto exit;  	}	else if((status&AT91C_PIO_PC15)==AT91C_PIO_PC15){		if(((AT91_SYS->PIOC_PDSR)&AT91C_PIO_PC15?0:1))		{			printk("can_interrupt 1 %x\n",status);	    		goto exit;  		}	    	goto exit; 	}	exit:
    //* Enable the interrupt on the interrupt controller
    AT91_SYS->AIC_IECR = 0x1 << AT91C_ID_PIOC ;
		return;}/* ......................................................................... */static struct file_operations candev_fops = {	owner:		THIS_MODULE,	llseek:		no_llseek,	read:		NULL,	write:		NULL,	ioctl:		mcp2510_ioctl,	open:		mcp2510_open,	release:	mcp2510_close,};/* ......................................................................... *//* Allocate a single SPI transfer descriptor.  We're assuming that if multiple   SPI transfers occur at the same time, spi_access_bus() will serialize them.   If this is not valid, then either (i) each dataflash 'priv' structure   needs it's own transfer descriptor, (ii) we lock this one, or (iii) use   another mechanism.   */static int __init mcp2510_init(void){	int i;	char name[2];#ifdef CONFIG_DEVFS_FS	if (devfs_register_chrdev(CAN_MAJOR, "can", &candev_fops)) {#else	if (register_chrdev(CAN_MAJOR, "can", &candev_fops)) {#endif		printk(KERN_ERR "at91_CANdev: Unable to get major %d for CAN bus\n", CAN_MAJOR);		return -EIO;	}#ifdef CONFIG_DEVFS_FS	devfs_handle = devfs_mk_dir(NULL, "can", NULL);	for (i = 0; i < NR_CAN_DEVICES; i++) {		sprintf (name, "%d", i);		devfs_mcp2510[i] = devfs_register (devfs_handle, name,			DEVFS_FL_DEFAULT, CAN_MAJOR, 2+i, S_IFCHR | S_IRUSR | S_IWUSR,			&candev_fops, NULL);	}#endif	if (request_irq(AT91C_ID_PIOC, can_interrupt, 0, "can", NULL))		return -EBUSY;	printk(KERN_INFO "CAN-Bus driver loaded\n");	return 0;}static void __exit mcp2510_exit(void){#ifdef CONFIG_DEVFS_FS	devfs_unregister(devfs_handle);	if (devfs_unregister_chrdev(CAN_MAJOR, "can")) {#else	if (unregister_chrdev(CAN_MAJOR,"can")) {#endif		printk(KERN_ERR "at91_CANdev: Unable to release major %d for CAN-Bus\n", CAN_MAJOR);		return;	}	free_irq(AT91C_ID_PIOC, 0);}EXPORT_NO_SYMBOLS;module_init(mcp2510_init);module_exit(mcp2510_exit);MODULE_LICENSE("GPL")MODULE_AUTHOR("Andrew Victor")MODULE_DESCRIPTION("CAN-Bus driver for Atmel AT91RM9200")

⌨️ 快捷键说明

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