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

📄 vme.c

📁 VME总线的驱动程序
💻 C
字号:
/*
 * linux/drivers/char/vme.h
 *
 * Copyright (C) 2006 - 2007 yang xu
 *
 * VME Bus Control Driver 0.1
 */#ifndef __KERNEL__#  define __KERNEL__#endif#include <linux/init.h>
#include <linux/kernel.h>	/* printk() */
#include <linux/module.h> 
#include <linux/fs.h> 		/* everything... */
#include <linux/slab.h> 
#include <linux/mm.h> 
#include <linux/string.h> 
#include <asm/uaccess.h> 
#include <linux/ioport.h>
#include <linux/pci.h>
#include <asm/arch/AT91RM9200_SYS.h>#include <asm/arch/AT91RM9200.h>
#include <asm/arch/pio.h>#include <asm/irq.h>#include <linux/ioctl.h>	/* O_ACCMODE */#include <linux/types.h>	/* size_t */#include <asm/io.h>#include "vme.h"
DECLARE_WAIT_QUEUE_HEAD(vme_queue);/* The declaration of some function prototypes */
static int vme_open(struct inode *inode, struct file *filp);
static int vme_release(struct inode *inode, struct file *filp) ;
static ssize_t vme_write(struct file *filp, const int *buf, size_t count, loff_t *offp) ;
static ssize_t vme_read(struct file *filp, int *buf, size_t count, loff_t *offp) ;
static int vme_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long addr);
static loff_t vme_seek(struct file *filp,loff_t off, int whence);static void vme_interrupt(int irq,void *dev_id,struct pt_regs *regs);static void vme_bus_operation(void);     
struct file_operations vme_fops=
{
	owner:		THIS_MODULE,
	read:		vme_read,
	write:		vme_write,
	open:		vme_open,
	release:	vme_release,
	llseek:		vme_seek,
    ioctl:      vme_ioctl,
};

static loff_t vme_seek(struct file *filp,loff_t off, int whence) {

	vme_RegAddr_temp = vme_RegAddr +(vme_off/4);
    return vme_RegAddr_temp;
}
static int vme_open(struct inode *inode, struct file *filp) 
{ 		//int result;	//result = request_irq(IRQ_NUMBER,vme_interrupt,SA_INTERRUPT,"VME",NULL);	//if (result) printk(KERN_INFO "vme : can't get assigned irq %i \n",IRQ_NUMBER); 	try_module_get(THIS_MODULE);	//for 2.6
	// MOD_INC_USE_COUNT; 
	return 0; 
} 
static int vme_release(struct inode *inode, struct file *filp) 
{ 	// free interrupt 	//free_irq(IRQ_NUMBER,NULL);  	module_put(THIS_MODULE);	// for 2.6
	//MOD_DEC_USE_COUNT;
	return 0; 
} 

static ssize_t vme_write(struct file *filp, const int *buf, size_t count, loff_t *offp) 
{ 	
	int i;	switch (count)	{		case 0: printk(KERN_INFO "vme_write The count must be an integer !\n");break; 		case 1: *(vme_RegAddr+VME_CSR_OFF/4)=*buf & 0xFFCFFFFF ;break;		case 2: *(vme_RegAddr+VME_CSR_OFF/4)=*(buf++) & 0xFFCFFFFF;				*(vme_RegAddr+VME_ADDR_OFF/4)=*(buf);				addr_tmp=*buf;				break;		/* if burst on is set, address need't to add itself */		default:if ((*buf & 0x40000000)!=0) 				{					vme_bus_operation();	/* bus request, bus occupy */					*(vme_RegAddr+VME_CSR_OFF/4)=*(buf++);					addr_tmp=*(buf);					*(vme_RegAddr+VME_ADDR_OFF/4)=*(buf++);					for (i=0;i<count-2;i++)					{						*(unsigned short *)(vme_RegAddr+VME_DATA_OFF/4)=*(buf++);								while ((*(vme_RegAddr+VME_CSR_OFF/4) & 0x80000)==0) NULL;						*(vme_RegAddr+VME_ADDR_OFF/4)=addr_tmp;					}				}				else 				{					vme_bus_operation();	/* bus request, bus occupy */					*(vme_RegAddr+VME_CSR_OFF/4)=*(buf++);					addr_tmp=*(buf);					*(vme_RegAddr+VME_ADDR_OFF/4)=*(buf++);					for (i=0;i<count-2;i++)					{						*(unsigned short *)(vme_RegAddr+VME_DATA_OFF/4)=*(buf++);								while ((*(vme_RegAddr+VME_CSR_OFF/4) & 0x80000)==0) NULL;						addr_tmp=addr_tmp+2;						*(vme_RegAddr+VME_ADDR_OFF/4)=addr_tmp;					}		      	}				*( vme_RegAddr+VME_CSRL_OFF)=*( vme_RegAddr+VME_CSRL_OFF) & 0xFFFFBFFF; /* bus release */	}
	return count; 
} 

static ssize_t vme_read(struct file *filp, int *buf, size_t count, loff_t *offp) 
{ 
	int i;	unsigned short data;	switch (count)	{	 case 0: interruptible_sleep_on(&vme_queue);					 vme_bus_operation();	/* bus request, bus occupy */			 			 /* the following may be need atomic process */			 /* send READ cmd */			 *(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) & 0xFFCFFFFF;			 *(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) | 0x00200000;			 /* waiting for ACK and return data */		     while ((*( vme_RegAddr+VME_CSR_OFF)& 0x80000)==0) NULL;			 data = *((unsigned short *)(vme_RegAddr+VME_DATA_OFF/4));			 *buf = (int)data;			 *(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) & 0xFFFFFFFD; /* clear iack; */			 *( vme_RegAddr+VME_CSRL_OFF)=*( vme_RegAddr+VME_CSRL_OFF) & 0xFFFFBFFF; /* bus release */			 break; 	 case 1: *buf = *(vme_RegAddr+VME_CSR_OFF/4);			 break;	 case 2: *(buf++) = *(vme_RegAddr+VME_CSR_OFF/4);			 *(buf++) = *(vme_RegAddr+VME_ADDR_OFF/4);		     break;			 /* if burst on is set, address need't to add itself */	 default:if ((*buf & 0x40000000)!=0) 			 {			   vme_bus_operation();	/* bus request, bus occupy */			  /* clear write and read bit */			  *(vme_RegAddr+VME_CSR_OFF/4)=*(buf++) & 0xFFCFFFFF;			  addr_tmp=*(buf);			  *(vme_RegAddr+VME_ADDR_OFF/4)=*(buf);			  buf--;			  /* read CSR and ADDR for check */			  *(buf++) = *(vme_RegAddr+VME_CSR_OFF/4);			  *(buf++) = *(vme_RegAddr+VME_ADDR_OFF/4);			  for(i=0;i<count-2;i++)				{
				 *(vme_RegAddr+VME_ADDR_OFF/4)=addr_tmp;				 				 /* send READ cmd */
				 *(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) & 0xFFCFFFFF;				 *(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) | 0x00200000;					 /* waiting for ACK and return data */				 while ((*( vme_RegAddr+VME_CSR_OFF)& 0x80000)==0) NULL;				 data = *((unsigned short *)(vme_RegAddr+VME_DATA_OFF/4));				 *(buf++) = (int)data;				}			  }			else 			{			  vme_bus_operation();	/* bus request, bus occupy */			  /* clear write and read bit */			  *(vme_RegAddr+VME_CSR_OFF/4)=*(buf++) & 0xFFCFFFFF;			  addr_tmp=*(buf);			  *(vme_RegAddr+VME_ADDR_OFF/4)=*(buf);			  buf--;			  /* read CSR and ADDR for check */			  *(buf++) = *(vme_RegAddr+VME_CSR_OFF/4);			  *(buf++) = *(vme_RegAddr+VME_ADDR_OFF/4);			  for(i=0;i<count-2;i++)				{
				 *(vme_RegAddr+VME_ADDR_OFF/4)=addr_tmp;				 addr_tmp=addr_tmp+2;				 /* send READ cmd */
				 *(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) & 0xFFCFFFFF;				 *(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) | 0x00200000;				 /* waiting for ACK and return data */				 while ((*( vme_RegAddr+VME_CSR_OFF)& 0x80000)==0) NULL;				 data = *((unsigned short *)(vme_RegAddr+VME_DATA_OFF/4));				 *(buf++) = (int)data;				}			 }			 *( vme_RegAddr+VME_CSRL_OFF)=*( vme_RegAddr+VME_CSRL_OFF) & 0xFFFFBFFF;		/* bus release */		}	
	return count; 
} 

static int vme_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long addr)
{		switch(cmd){		case 1: *(vme_RegAddr+VME_CSR_OFF/4)=(int) addr & 0xFFCFFFFF ;		        break;		case 2: *(vme_RegAddr+VME_ADDR_OFF/4)=(int) addr;			addr_tmp=(int) addr;			break;		case 4: *(vme_RegAddr+VME_DATA_OFF/4)=(short)addr;			break;		default:printk(KERN_INFO "vme_ioctl: Can't identify the CMD!\n"); 	}	return 1;	
}// interrupt handling,now do nothing
static void vme_interrupt(int irq,void *dev_id,struct pt_regs *regs){		*(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) | 0x00000002;	/* set iack; */	*(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) & 0xFFFFFFC2;	/* close interrupt */	/* send interrupt vector to address register;*/	*(vme_RegAddr+VME_ADDR_OFF/4)= (*(vme_RegAddr+VME_CSR_OFF/4) & 0x000000c0) >> 5;	*(vme_RegAddr+VME_CSR_OFF/4)=*(vme_RegAddr+VME_CSR_OFF/4) | 0x0000003d;	/* enable interrupt */	wake_up_interruptible(&vme_queue);	/* waking up all read processs */	}
static void vme_bus_operation(void){	while ((*( vme_RegAddr+VME_CSRL_OFF/4) & 0x8000) != 0) NULL; /* check bus state */			*( vme_RegAddr+VME_CSRL_OFF)=*( vme_RegAddr+VME_CSRL_OFF) | 0x00000100; /* bus request 0 */			while ((*( vme_RegAddr+VME_CSRL_OFF) & 0x00000200) == 0 ) NULL; /* bus allow */			*( vme_RegAddr+VME_CSRL_OFF)=*( vme_RegAddr+VME_CSRL_OFF) | 0x00004000; /* bus 占用 */}
static int __init init_vme(void)
{ 	static int result;
    AT91_SYS->EBI_SMC2_CSR[7] = 0x10003182;			
//-----------------------------------------------------------------------------------------------------------------
	if (!request_mem_region(VME_PHYSICAL_REG_ADDR,VME_PHYSICAL_REG_SIZE, "VME_DRIVER"))
    		printk("Error request mem \n");
	vme_RegAddr  = (unsigned int*) ioremap_nocache(VME_PHYSICAL_REG_ADDR,VME_PHYSICAL_REG_SIZE);		 //*(unsigned int *)( vme_RegAddr+VME_CSR_OFF)=0x3e09003d;	 *(unsigned int *)(vme_RegAddr+ VME_CSR_OFF) =0x3e190000;	// enable IRQ5;	//enable_irq(IRQ_NUMBER);
	printk("vme:Phys Reg address:%X  \n", vme_RegAddr);
	
	if (!vme_RegAddr)
    		printk("vme_init: ioremap() returned NULL\n");
    		
//-----------------------------------------------------------------------------------------------------------------
	register_chrdev(MAJOR_NUM, "vme", &vme_fops); 		result = request_irq(IRQ_NUMBER,vme_interrupt,SA_INTERRUPT,"VME",NULL);	if (result) printk(KERN_INFO "vme : can't get assigned irq %i \n",IRQ_NUMBER); 
	printk("vme device installed.\n");	
	return 0; 
} 

static void __exit exit_vme(void)
{	/* free interrupt */	free_irq(IRQ_NUMBER,NULL);  
	printk("vme device uninstalled.\n"); 
} 

module_init(init_vme);
module_exit(exit_vme);

⌨️ 快捷键说明

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