📄 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 + -