?? cpci50401a.c
字號(hào):
#ifndef __KERNEL__#define __KERNEL__#endif#ifndef __SIM_INT_MODE#define __SIM_INT_MODE#endif#ifndef MODULE#define MODULE#endif#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/proc_fs.h>#include <linux/fcntl.h>#include <linux/pci.h>#include <linux/timer.h>#include <linux/poll.h>#include <asm/io.h>#include <linux/delay.h>#include <linux/time.h>#include "cpci50401.h"MODULE_LICENSE("GPL v2");MODULE_AUTHOR("USTB.");MODULE_DESCRIPTION("cpci50401b Dev Driver");#ifndef CONFIG_PCI# error "This driver needs PCI support to be available"#endifEXPORT_NO_SYMBOLS;int cpci50401b_major = 247;static int drv_file_opened = 0;static unsigned long cfg_base_address, mem_base0_address,mem_base1_address;int cpci50401b_irq;struct CPCI50401_IO_MEM cpci50401b_io;static struct pci_dev *cpci50401b_dev;struct fasync_struct *async_queue = NULL;static int intr_enb = 0;#define TIME_FILTER 0static unsigned long newtime = 0;static unsigned long oldtime = 0;static unsigned long delta = 0; static void enable_pci_int(void){ int val; val = readw((unsigned)cpci50401b_io.int_enb); rmb(); val = (val | Lint1_ENB | Lint1_HIGH | Lint1_EDGE | Lint2_ENB | Lint2_HIGH | Lint2_EDGE | Lint1_CLRINT | Lint2_CLRINT | PCI_ENB); writew(val, (unsigned)cpci50401b_io.int_enb); wmb();}static void disable_pci_int(void){ int val; val = readw((unsigned)cpci50401b_io.int_enb); rmb(); val = val & ~PCI_ENB; writew(val, (unsigned)cpci50401b_io.int_enb); wmb();}#ifdef __SIM_INT_MODE#define VECQLEN 1024static struct vectorqueue { int vec[VECQLEN]; int front; int rear;} vecq;static int add_vecq(int vec){ int tmprear = (vecq.rear + 1) % VECQLEN; if(tmprear == vecq.front) return -1; vecq.vec[vecq.rear] = vec; vecq.rear = (vecq.rear + 1) % VECQLEN; /*if(vecq.rear - vecq.front > 10) printk("<1>cpci50401b: geu interrupt overspeed!\r\n");*/ return 0;}static int del_vecq(unsigned long *vec){ *vec = vecq.vec[vecq.front]; vecq.front = (vecq.front + 1) % VECQLEN; return 0;}static int is_consuming = 1;static int co = 0;void cpci50401b_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs){ int get; int ret=0; get = readw((unsigned)cpci50401b_io.int_enb); rmb(); if(get & Lint1_ACT) // local 1 { // printk("<1>Get Local1 Int : 0x%x\n",get); int i,j; for(i = 0;i<500;i++) for(j=0;j<100;j++); /* clear local1 intr */ ret = add_vecq(0130);// printk("<1>cpci50401b: vector = 130\n"); if(ret < 0){ /* intr queue full */ is_consuming = 0; vecq.front = vecq.rear = 0; /* interrupt disable */// disable_pci_int();// printk("<1>cpci50401b: vector queue length is too short!\n"); } get |= 0x400; writew(get, (unsigned)cpci50401b_io.int_enb); wmb(); } if(get & Lint2_ACT) // local 2 {// printk("<1>Get Local2 Int : 0x%x\n",get);#if TIME_FILTER struct timeval tv; static int sum = 0; do_gettimeofday(&tv); newtime = tv.tv_sec * 1000 * 1000 + tv.tv_usec; if(oldtime != 0){ delta = newtime - oldtime; if((delta > 15000) && (delta < 18000)){ if (async_queue) kill_fasync(&async_queue, SIGIO, POLL_IN); }else{ sum += delta; if((sum > 15000) && (sum < 18000)){ if (async_queue) kill_fasync(&async_queue, SIGIO, POLL_IN); sum = 0; } } } oldtime = newtime;#else if (async_queue) kill_fasync(&async_queue, SIGIO, POLL_IN);#endif /* clear local2 intr */ get |= 0x800; writew(get, (unsigned)cpci50401b_io.int_enb); wmb(); }}#endifstruct pci_dev *cpci50401_find_first_dev(unsigned int vendor,unsigned int device,unsigned int devfn){ struct pci_dev *dev; pci_for_each_dev(dev) { if((dev->vendor == vendor) &&(dev->device == device) &&(dev->devfn == DRIVER_NO_A)) return dev; } return NULL;}int find_cpci50401b_device(unsigned int vendor, unsigned int device){ cpci50401b_dev = NULL; if (!pci_present()) return -ENODEV; cpci50401b_dev = pci_find_device(vendor,device,cpci50401b_dev); if (!cpci50401b_dev) return -ENODEV;// printk("devfn:0x%x\n",cpci50401b_dev->devfn); pci_enable_device(cpci50401b_dev); return 0;}int allocate_cpci50401b_resource(void){ int result; unsigned char irq_no; cfg_base_address = pci_resource_start(cpci50401b_dev, CONFIG_BASE); mem_base0_address = pci_resource_start(cpci50401b_dev, MEM_BASE0); mem_base1_address = pci_resource_start(cpci50401b_dev, MEM_BASE1); // printk("<1> cpci50401b: config base address: %x\n", cfg_base_address);// printk("<1> cpci50401b: io base0 address: %x\n", mem_base0_address);// printk("<1> cpci50401b: io base1 address: %x\n", mem_base1_address); /* find the IRQ number assigned by the kernel */ result = pci_read_config_byte(cpci50401b_dev, PCI_INTERRUPT_LINE, &irq_no);// printk("<1> cpci50401b: IRQ no: %d\n", irq_no); if (result) { printk("<1>cpci50401b: read pci interrupt number error!\n"); return -EBUSY; } cpci50401b_irq = irq_no; // Map I/O Address Space if (check_mem_region(mem_base0_address, MEM_LEN)) { printk("<1>cpci50401b: io0 space already in use!\n"); return -EBUSY; } request_mem_region(mem_base0_address, MEM_LEN, CPCI50401_B); cpci50401b_io.baseaddr0 = (void *)ioremap(mem_base0_address,MEM_LEN); if (check_mem_region(mem_base1_address, MEM_LEN)) { printk("<1>cpci50401b: io1 space already in use!\n"); release_mem_region(mem_base0_address, MEM_LEN); return -EBUSY; } request_mem_region(mem_base1_address, MEM_LEN, CPCI50401_B); cpci50401b_io.baseaddr1 = (void *)ioremap(mem_base1_address,MEM_LEN); // Map Configuration Address Space if (check_mem_region(cfg_base_address, CONFIG_LEN)) { printk("<1>cpci50401b: configuration space already in use!\n"); release_mem_region(mem_base0_address, MEM_LEN); release_mem_region(mem_base1_address, MEM_LEN); return -EBUSY; } request_mem_region(cfg_base_address, CONFIG_LEN, CPCI50401_B); cpci50401b_io.int_enb = (void *)(ioremap(cfg_base_address,CONFIG_LEN) + 0x4c);#ifdef __SIM_INT_MODE /* interrupt enable: enable PCI intr & local intr1 & local intr2 */ int val; enable_pci_int(); vecq.front = vecq.rear = 0; result = request_irq(cpci50401b_irq, cpci50401b_interrupt_handler, \ SA_SHIRQ, CPCI50401_B, cpci50401b_dev); if(result) { printk("<1> cpci50401b: cannot install interrupt handler!\n"); release_mem_region(mem_base0_address, MEM_LEN); release_mem_region(mem_base1_address, MEM_LEN); release_mem_region(cfg_base_address, CONFIG_LEN); return -EBUSY; } #else /* interrupt enable: enable local intr1 & local intr2 */// writel(0xf1b, cpci50401b_io.int_enb);// wmb();#endif return 0;}int release_cpci50401b_resource(void){ release_mem_region(mem_base0_address, MEM_LEN); release_mem_region(mem_base1_address, MEM_LEN); /* interrupt disable */ disable_pci_int(); release_mem_region(cfg_base_address, CONFIG_LEN);#ifdef __SIM_INT_MODE free_irq(cpci50401b_irq, NULL);#endif return 0;}int cpci50401b_open(struct inode *inode, struct file *fp){ int ret; if (drv_file_opened != 0) { printk("<1>cpci50401b: Driver file can only be opened for 1 program!\n"); return -ENODEV; } drv_file_opened = 1;// printk("<1>cpci50401b: Driver file opened!\n"); ret = find_cpci50401b_device(VENDOR_ID, DEVICE_ID); if (ret < 0) { printk("<1>cpci50401b: find device failure!\n"); return -ENODEV; } ret = allocate_cpci50401b_resource(); if (ret < 0) { printk("<1>cpci50401b: allocate resource failure!\n"); return -ENODEV; } return 0;}int cpci50401b_release(struct inode *inode, struct file *fp){// printk("<1>cpci50401b: release called!\n"); drv_file_opened = 0; release_cpci50401b_resource(); return 0;}int cpci50401b_ioctl(struct inode *inode, struct file *fp, unsigned int cmd, unsigned long arg){ long *ptr; int ret; long data; unsigned long vector; ret = 0; data = 0; switch (cmd) { case CPCI50401_IOC_READ_BASE0: data = readw((unsigned)cpci50401b_io.baseaddr0) & 0xffff; rmb(); printk("Debug : Read from A/D base0 = %d\n",data); put_user(data,(long *)arg); break; case CPCI50401_IOC_READ_BASE1: data = readw((unsigned)cpci50401b_io.baseaddr1) & 0xffff; rmb(); printk("Debug : Read from A/D base1 = %d\n",data); put_user(data,(long *)arg); break; case CPCI50401_IOC_WRITE_BASE0: ptr = (long *)arg; ret = get_user(data,ptr); if(!ret) { writew(data&0x1f,(unsigned)cpci50401b_io.baseaddr0); wmb(); printk("Debug : Write to A/D int = %d\n",data); } else printk("Debug : arg err\n"); break; case CPCI50401_IOC_WRITE_BASE1: ptr = (long *)arg; ret = get_user(data,ptr); if(!ret) { writew(data&0xfffc,(unsigned)cpci50401b_io.baseaddr1); wmb(); printk("Debug : Write to A/D Channel No = %d\n",data); } else printk("Debug : arg err\n"); break; case CPCI50401_IOC_RESET: // printk("AD2 RESET\n"); // readw((unsigned)cpci50401b_io.baseaddr0); // rmb(); writew(0,(unsigned)cpci50401b_io.baseaddr0); wmb(); writew(0, (unsigned)cpci50401b_io.baseaddr1); wmb(); // Clear Int Queue vecq.front = vecq.rear = 0; break; case CPCI50401_IOC_SYS_GET_INT:#ifdef __SIM_INT_MODE if(0 == is_consuming){ is_consuming = 1; vecq.front = vecq.rear = 0; } if(vecq.front != vecq.rear){ if((vecq.vec[vecq.front] == 0130)) // A/D put_user(6, (long *)arg); // BR6 } else if(vecq.front == vecq.rear) put_user(0, (long *)arg);#else put_user(0, (long *)arg); //intr not actived#endif break; case CPCI50401_IOC_SYS_GET_VEC:#ifdef __SIM_INT_MODE del_vecq(&vector); put_user(vector, (long *)arg);#endif break; case CPCI50401_IOC_READ_STATUS: data = readw((unsigned)(cpci50401b_io.baseaddr1+4)) & 0xffff; rmb(); printk("Debug : Read from A/D base1+4= %d\n",data); put_user(data,(long *)arg); break; case CPCI50401_IOC_WRITE_STATUS: ptr = (long *)arg; ret = get_user(data,ptr); if(!ret) { writew(data,(unsigned)(cpci50401b_io.baseaddr1+4)); wmb(); printk("Debug : Write to A/D int base1+4= %d\n",data); } else printk("Debug : arg err\n"); break;/* case CPCI50401_IOC_DISINTR:#ifdef __SIM_INT_MODE is_consuming = 0; vecq.front = vecq.rear = 0; // interrupt disable writel(0, cpci50401b_io.int_enb); wmb();#else intr_enb = 0;#endif break; case CPCI50401_IOC_ENBINTR:#ifdef __SIM_INT_MODE // interrupt enable: enable PCI intr & local intr1 & local intr2 writel(0xf5b, cpci50401b_io.int_enb); vecq.front = vecq.rear = 0; wmb();#else intr_enb = 1;#endif break; case CPCI50401_IOC_SYS1_INTRACT: data = readl(cpci50401b_io.int_enb); if( (data & 0x4) && intr_enb ) put_user(1, (long *)arg); //intr actived else put_user(0, (long *)arg); //intr not actived break; case CPCI50401_IOC_SYS2_INTRACT: data = readl(cpci50401b_io.int_enb); if( (data & 0x20) && intr_enb ) put_user(1,(long *)arg); //intr actived else put_user(0, (long *)arg); //intr not actived break; case CPCI50401_IO_SYS1_SETGNT: data = readl(cpci50401b_io.int_enb); writel(data | 0x400, cpci50401b_io.int_enb); break; case CPCI50401_IO_SYS2_SETGNT: data = readl(cpci50401b_io.int_enb); writel(data | 0x800, cpci50401b_io.int_enb); break; case CPCI50401_IOC_STATUS: data = readb(cpci50401b_io.status); rmb(); put_user(data, (long *)arg); break; case CPCI50401_IOC_INTSTA: data = readb(cpci50401b_io.intsta); rmb(); put_user(data, (long *)arg); break; case CPCI50401_IOC_COMMAND: writel(arg, cpci50401b_io.command); wmb(); writel(0, cpci50401b_io.cmd_apply); wmb(); break;*/ default: ret = -ENOTTY; break; } return ret;}int cpci50401b_fasync(int fd, struct file *filp, int mode){ return fasync_helper(fd, filp, mode, &async_queue); return 0;}struct file_operations cpci50401b_fops = { open: cpci50401b_open, release: cpci50401b_release, ioctl: cpci50401b_ioctl, fasync: cpci50401b_fasync,};int init_module(void){ int result; SET_MODULE_OWNER(&cpci50401b_fops); result = register_chrdev(cpci50401b_major, CPCI50401_B, &cpci50401b_fops); if (result < 0) { printk(KERN_WARNING "cpci50401b_drv: can't get major no %d\n", cpci50401b_major); return result; } if (cpci50401b_major == 0) cpci50401b_major = result; printk("<1>major number = %d\n", cpci50401b_major); return 0; /* success */}void cleanup_module(void){ unregister_chrdev(cpci50401b_major, CPCI50401_B);}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -