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

📄 pci9054.c

📁 plx9054图像卡驱动程序
💻 C
字号:
#define DRV_NAME	"pci_9054"#define DRV_VERSION	"0.1"#ifndef CONFIG_PCI#define CONFIG_PCI#endif#ifndef CONFIG_PROC_FS#define CONFIG_PROC_FS#endif#include <linux/pci.h>#include <linux/module.h>//#include <asm/uaccess.h>#include <linux/interrupt.h>#include <linux/config.h>#include <linux/ioctl.h>#include <linux/poll.h>#include <asm/dma.h>#include "myvalues.h"// GLOBAL DEFINITIONSstruct pci_dev *pdev = NULL;unsigned long ulPciRegister = 0;unsigned long ulPciRegLen = 0;unsigned long ulFpgaRegister = 0;unsigned long ulFpgaRegLen = 0;void __iomem *fpgaMem = NULL;void __iomem *pciMem = NULL;unsigned char bufFlag = 0;		// 0 for send, 1 for receiveunsigned char sendHappened = 0;		// to represent that send interrupt has occuredunsigned char recvHappened = 0;		// to represent that receive interrupt has occuredstatic DECLARE_WAIT_QUEUE_HEAD(pci9054_wqs);static DECLARE_WAIT_QUEUE_HEAD(pci9054_wqr);void *kernBuffer = NULL;int order = 0;dma_addr_t dmaSendAddr = NULL;dma_addr_t dmaRecvAddr = NULL;unsigned long ulSendSize = 0x200000;	// 2Munsigned long ulRecvSize = 0x100000 / 2;// 512Kstatic const struct pci_device_id pci9054_ids[] = {	{ PCI_DEVICE(VENDORID, DEVICEID) },	{ /* end: all zeroes */ },};MODULE_DEVICE_TABLE(pci, pci9054_ids);/****************************************\|*     Driver "pci9054.o"`s entries      *|\****************************************/voidpci9054_do_tasklet(unsigned long unused){	if (bufFlag == 0)	{		sendHappened = 1;		wake_up_interruptible(&pci9054_wqs);		printk(KERN_INFO "Send Over!\n");	}	else		if (bufFlag == 1)		{			recvHappened = 1;			wake_up_interruptible(&pci9054_wqr);			printk(KERN_INFO "Receive Over!\n");		}		else			return;}DECLARE_TASKLET(pci9054_tasklet, pci9054_do_tasklet, 0);irqreturn_t pci9054_Isr(int irqn, void *dev_id, struct pt_regs *regs){	u32 intcsr;	u8 dmacsr;		intcsr = readl(pciMem + 0x0068);	if (! intcsr & (1 << 21) )		return IRQ_NONE;	printk(KERN_INFO "DMA CH0 Interrupt\n");		// Disable PCI interrupt	intcsr = readl(pciMem + 0x0068);	intcsr &= ~(1 << 8);	writel(intcsr, pciMem + 0x0068);	//Clear DMA CH0 interrupt	dmacsr = readb(pciMem + 0x00A8);	dmacsr |= 1 << 3;	writeb(dmacsr, pciMem + 0x00A8);	// CH0 stop and disable	dmacsr = readb(pciMem + 0x00A8);	dmacsr &= ~( (1 << 1) |  (1 << 0) );	writeb(dmacsr, pciMem + 0x00A8);	if (bufFlag == 0)	{		dma_unmap_single(&pdev->dev, dmaSendAddr, ulSendSize, DMA_TO_DEVICE);		dmaSendAddr = NULL;	}	else		if (bufFlag == 1)		{			dma_unmap_single(&pdev->dev, dmaRecvAddr, ulRecvSize, DMA_FROM_DEVICE);			dmaRecvAddr = NULL;		}			// request dpc...that's tasklet under linux	tasklet_schedule(&pci9054_tasklet);	// Enable PCI Interrupt	intcsr = readl(pciMem + 0x0068);	intcsr |= (1 << 8);	writel(intcsr, pciMem + 0x0068);			return IRQ_HANDLED;}int pci9054_probe(struct pci_dev *dev, const struct pci_device_id *id){	int status = -1;	status = pci_enable_device(dev);	//pci_set_master(dev);	pdev = dev;	// save it for later use  	return status;}voidpci9054_remove(struct pci_dev *dev){	pci_disable_device(dev);	return;}/* device module information */static struct pci_driver pci9054_driver = {	.name = DRV_NAME,	.id_table = pci9054_ids,	.probe = pci9054_probe,	.remove = pci9054_remove,};int pci9054_open(struct inode *inode, struct file *filp){	// setup the irq interrupt handler	request_irq(pdev->irq, pci9054_Isr, SA_SHIRQ, "pci9054", pci9054_ids);	return 0;}int pci9054_release(struct inode *inode, struct file *filp){	free_irq(pdev->irq, pci9054_ids);    		return 0;}int pci9054_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){	struct FpgaRegister *preg = (struct FpgaRegister *)arg;		u32 lregvalue;	u8 bregvalue;	u32 dmasize;    	switch (cmd)    	{		case WR_FPGA_REGISTER:			writel(preg->value, fpgaMem);		    	break;	    	case RD_FPGA_REGISTER:		    	preg->value = readl(fpgaMem + preg->offset);		    	break;		case DMA_CH0_SEND_CTRL:			// map the kernBuffer into dma address			dmaSendAddr = dma_map_single(&pdev->dev, kernBuffer, ulSendSize, DMA_TO_DEVICE);			bufFlag = 0;			writel(0x00023DC1, pciMem + 0x0080);  // demand mode enable			// DMA CH0 descriptor			writel(0x00000000, pciMem + 0x0090);  // bit 3: From PCI to local bus			//Set pointer to the right array address before the first transfer			writel(dmaSendAddr, pciMem + 0x0084);	  // CH0 PCI address			// CH0 local address offset			writel(0x00000000, pciMem + 0x0088);			// Enable CH0			bregvalue = readb(pciMem + 0x00A8);			bregvalue |= 1 << 0;			writeb(bregvalue, pciMem + 0x00A8);			// Start DMA CH0 (Demand mode)			bregvalue = readb(pciMem + 0x00A8);			bregvalue |= 1 << 1;			writeb(bregvalue, pciMem + 0x00A8);			break;		case DMA_CH0_RECV_CTRL:			// map the kernBuffer into dma address			dmaRecvAddr = dma_map_single(&pdev->dev, kernBuffer, ulRecvSize, DMA_FROM_DEVICE);			bufFlag = 1;			writel(0x00023DC3, pciMem + 0x0080);    // demand mode enable			// DMA CH0 descriptor			writel(0x00000008, pciMem + 0x0090);    // bit 3: local bus to pci			//Set pointer to the right array address before the first transfer			writel(dmaRecvAddr, pciMem + 0x0084);   // CH0 PCI address			// CH0 local address offset			writel(ulSendSize, pciMem + 0x0088);			// Enable CH0			bregvalue = readb(pciMem + 0x00A8);			bregvalue |= 1 << 0;			writeb(bregvalue, pciMem + 0x00A8);			// Start DMA CH0 (Demand mode)			bregvalue = readb(pciMem + 0x00A8);			bregvalue |= 1 << 1;			writeb(bregvalue, pciMem + 0x00A8);			break;		case SET_DMA_CH0_SIZE:			dmasize = *((u32 *)arg);			writel(dmasize, pciMem + 0x008C);			break;	    	default:		    	return -EINVAL;    	}        	return 0;}static int pci9054_mmap(struct file *filp, struct vm_area_struct *vma){	unsigned long page, pos;	unsigned long start = (unsigned long)vma->vm_start;	unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start);	// if userspace tries to mmap beyond end of our buffer, fail	if (size > MMT_BUF_SIZE)		return -EINVAL;	// start off at the start of the buffer	pos = (unsigned long)kernBuffer;		//vma->vm_flags |= VM_LOCKED;	page = virt_to_phys((void *)pos);	if (remap_page_range(vma, start, page, size, PAGE_SHARED))		return -EAGAIN;	return 0;}/* now poll... */static unsigned intpci9054_poll(struct file *file, poll_table *wait){	unsigned int mask = 0;	poll_wait(file, &pci9054_wqs, wait);	poll_wait(file, &pci9054_wqr, wait);	if (sendHappened == 1)	{		mask |= POLLIN | POLLRDNORM;		sendHappened = 0;	}	if (recvHappened == 1)	{		mask |= POLLOUT | POLLWRNORM;		recvHappened = 0;	}	return mask;}ssize_tpci9054_read(struct file *file, char *buf, size_t len, loff_t *pos){	wait_event_interruptible(pci9054_wqs, sendHappened == 1);	return 0;}ssize_tpci9054_write(struct file *file, char *buf, size_t len, loff_t *pos){	wait_event_interruptible(pci9054_wqr, recvHappened == 1);	return 0;}/* device file operations interface */struct file_operations pci9054_fops = {    owner:	THIS_MODULE,    poll:	pci9054_poll,    read:	pci9054_read,    write:	pci9054_write,    ioctl:      pci9054_ioctl,    mmap:	pci9054_mmap,    open:       pci9054_open,    release:    pci9054_release,};/*****************************************\|*        Self-defined Functions         *|\*****************************************/voidinitDevice(void){	ulPciRegister = pci_resource_start(pdev, 0);	ulPciRegLen = pci_resource_len(pdev, 0);	ulFpgaRegister = pci_resource_start(pdev, 3);	ulFpgaRegLen = pci_resource_len(pdev, 3);		(void) pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &pdev->irq);		fpgaMem = ioremap(ulFpgaRegister, 256);	pciMem = ioremap(ulPciRegister, 256);}voidstartDevice(void){	int status = -1;	unsigned long intcsr, pcicr, cntrl;	struct page *page;		// Disable PCI interrupt	intcsr = readl(pciMem + 0x0068);	intcsr &= ~( (1<<19) | (1<<18) | (1<<16) | (1<<11) | (1<<8) );	writel(intcsr, pciMem + 0x0068);	// Allocate memory	order = get_order(MMT_BUF_SIZE);	kernBuffer = __get_free_pages(GFP_DMA, order);	if (kernBuffer == NULL)	{		printk(KERN_ALERT "Buffer allocation failure\n");		return;	}	// Lock these pages into memory	for (page = virt_to_page(kernBuffer); page < virt_to_page(kernBuffer + MMT_BUF_SIZE); page++)		SetPageReserved(page);		// PCI command	pcicr = readw(pciMem + 0x0004);	pcicr |= (1<<4) | (1<<2) | (1<<1) | (1<<0);	writew(pcicr, pciMem + 0x0004);	//Set PCI Write Command Code for DMA to "Write and Invalid"	cntrl = readl(pciMem + 0x006C);	cntrl |= 0x000000F0;	writel(cntrl, pciMem + 0x006C);	// Interrupt enable	intcsr = readl(pciMem + 0x0068);	intcsr |= (1<<18) | (1<<8);	writel(intcsr, pciMem + 0x0068);	printk(KERN_ALERT "device started \n");		        }int init_module(void){	unsigned char isr;	int err, status;    	status = pci_register_driver(&pci9054_driver);		register_chrdev(187, "pci9054", &pci9054_fops);        	//pdev = pci_find_device(VENDORID, DEVICEID, NULL);    	if (pdev == NULL)    	{        	printk(KERN_EMERG "no pci card specified\n");	        return -PCIBIOS_DEVICE_NOT_FOUND;    	}        	// init the device	initDevice();    	startDevice();        	return status;}void cleanup_module(void){	struct page *page;	for (page = virt_to_page(kernBuffer); page < virt_to_page(kernBuffer + MMT_BUF_SIZE); page++)		ClearPageReserved(page);    	pci_unregister_driver(&pci9054_driver);	unregister_chrdev(187, "pci9054");	free_pages(kernBuffer, order);	    	printk(KERN_INFO "Goodbye, pci9054...\n");}MODULE_LICENSE("GPL");MODULE_AUTHOR("Ziqian Lu");

⌨️ 快捷键说明

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