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

📄 cpci50401b.c

📁 一个基于PCI卡数据采集卡的驱动程序,分别有内存影射和IO 影射的方式
💻 C
字号:
#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;static 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 data,chnl;		int i,j;		for(i = 0;i<500;i++)			for(j=0;j<100;j++);//		data = readw((unsigned)cpci50401b_io.baseaddr0);//		rmb();//		chnl = readw((unsigned)cpci50401b_io.baseaddr1);//		rmb();//		if(co++>1000)//		{	//			printk("channel %d data : 0x%x\n",chnl,data);//			co = 0;//		}		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");		}		/* clear local1 intr */		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		get |= 0x800;		writew(get, (unsigned)cpci50401b_io.int_enb);		wmb();		}		}#endifstruct pci_dev *cpci50401_find_second_dev(unsigned int vendor,unsigned int device,unsigned int devfn){	struct pci_dev *dev;	pci_for_each_dev(dev) {                 printk("<1>info:%x,%x,%X\n",dev->vendor,dev->device,dev->devfn);		if((dev->vendor == vendor)		   &&(dev->device == device)		   &&(dev->devfn == DRIVER_NO_B))			return dev;	}	return NULL;}int find_cpci50401b_device(unsigned int vendor, unsigned int device){	cpci50401b_dev = NULL;	if (!pci_present())		return -ENODEV;	cpci50401b_dev = cpci50401_find_second_dev(vendor,device,DRIVER_NO_B);	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	/*  register interrupt handler */	/* interrupt enable: enable PCI intr & local intr1 & local intr2 */	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;	}	/* interrupt enable: enable PCI intr & local intr1 & local intr2 *///	enable_pci_int();#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);}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>module init!\n");//	printk("<1>major number = %d\n", cpci50401b_major);	return 0; /* success */}void cleanup_module(void){	unregister_chrdev(cpci50401b_major, CPCI50401_B);	printk("<1>module cleanup!\n");}

⌨️ 快捷键说明

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