📄 pci550x.c
字号:
/* * ADAC/5500 Series Device Driver */#include <linux/module.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/uaccess.h>#include <linux/proc_fs.h>#include "pci550x.h"MODULE_AUTHOR("Boca Microsystems Incorporated");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("ADAC/5500 Series Device Driver");#ifndef CONFIG_PCI#error "This driver requires that PCI support be configured in the Kernel"#endif/* GLOBAL DATA */static struct file_operations pci550x_fops = { owner: THIS_MODULE, read: pci550x_read, readv: pci550x_readv, write: pci550x_write, writev: pci550x_writev, ioctl: pci550x_ioctl, open: pci550x_open, release: pci550x_release,};static const char *driver_name = "pci550x";static unsigned int pci550x_major = PCI550X_MAJOR;static unsigned int minor = 0;#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry *pci550x_proc_dir_entry = NULL;static const char* proc_dir_entry = "driver/pci550x";#endifunion { u_int32_t bus_addressf; u_int16_t bus_addressh[2];} dma;/* * pci550x_interrupt - interrupt handler */void pci550x_interrupt(int irq, void *dev_id, struct pt_regs *regs) { pci550x_dib *dib; pci550x_hwregs *REGS; u_int32_t int_status; /* if it's not our interrupt,...ignore it */ dib = (pci550x_dib *)dev_id; REGS = (pci550x_hwregs *)dib->membase; INT_STATUS_R(int_status); if (!(int_status & INTMASK)) return; /* process ADC interrupt */ if ( (dib->int_status = int_status) & INT_STATUS_ADINT) { AD_STATUS_R(dib->adc_status); if (dib->adc_status & AD_STATUS_ERROR) { if (dib->adc_status & AD_STATUS_MERR0) dib->adc_stats.merr0++; else if (dib->adc_status & AD_STATUS_MERR1) dib->adc_stats.merr1++; else if (dib->adc_status & AD_STATUS_FOVR) dib->adc_stats.fovr++; else if (dib->adc_status & AD_STATUS_FUNDR) dib->adc_stats.fundr++; else if (dib->adc_status & AD_STATUS_CERR) dib->adc_stats.cerr++; else if (dib->adc_status & AD_STATUS_BERR) dib->adc_stats.berr++; AD_STATUS_W(dib->adc_status); } if (!(list_empty(&dib->adc_wq.task_list))) { wake_up_interruptible_sync(&dib->adc_wq); } } /* process DAC0 interrupt */ if ((dib->int_status = int_status) & INT_STATUS_DA0INT) { DA0_STATUS_R(dib->dac0_status); if (dib->dac0_status & DA0_STATUS_ERROR) { if (dib->dac0_status & DA0_STATUS_MERR0) dib->dac0_stats.merr0++; else if (dib->dac0_status & DA0_STATUS_MERR1) dib->dac0_stats.merr1++; else if (dib->dac0_status & DA0_STATUS_FOVR) dib->dac0_stats.fovr++; else if (dib->adc_status & DA0_STATUS_DERR) dib->dac0_stats.derr++; else if (dib->dac0_status & DA0_STATUS_CERR) dib->adc_stats.cerr++; DA0_STATUS_W(dib->dac0_status); } if (!(list_empty(&dib->dac0_wq.task_list))) { wake_up_interruptible_sync(&dib->dac0_wq); } } /* process DAC1 interrupt */ if ((dib->int_status = int_status) & INT_STATUS_DA1INT) { DA1_STATUS_R(dib->dac1_status); if (dib->dac1_status & DA1_STATUS_ERROR) { if (dib->dac1_status & DA1_STATUS_MERR0) dib->dac1_stats.merr0++; else if (dib->dac1_status & DA1_STATUS_MERR1) dib->dac1_stats.merr1++; else if (dib->dac1_status & DA1_STATUS_FOVR) dib->dac1_stats.fovr++; else if (dib->adc_status & DA1_STATUS_DERR) dib->dac1_stats.derr++; else if (dib->dac1_status & DA1_STATUS_CERR) dib->adc_stats.cerr++; DA1_STATUS_W(dib->dac1_status); } if (!(list_empty(&dib->dac1_wq.task_list))) { wake_up_interruptible_sync(&dib->dac1_wq); } } /* reset the interrupt */ INT_STATUS_W(int_status);}/* * pci550x_open - open method */static int pci550x_open(struct inode* inode, struct file* filp){ struct pci_dev *pdev = NULL; pci550x_dib *dib; pci550x_hwregs *REGS; int ret = 0; int i; /* by device minor number */ while( (pdev=pci_find_device(PCI_VENDOR_ID_ADAC, PCI_ANY_ID, pdev))) { if ( (dib = (pci550x_dib *)pci_get_drvdata(pdev) ) && (MINOR(inode->i_rdev) == dib->minor) ) break; } if(!pdev) return(-ENODEV); REGS = (pci550x_hwregs *)dib->membase; /* if WRONLY we must have a board with DAC channels */ if ( ((filp->f_flags & O_ACCMODE) == O_WRONLY) && (dib->pdev->subsystem_device != PCI_SUBSYSTEM_ID_B) ) { return(-ENODEV); } /* open access control - SMP safe */ if ((filp->f_flags & O_ACCMODE) == O_RDONLY) { spin_lock(&dib->adc_lock); if (dib->adc_opened) { spin_unlock(&dib->adc_lock); return(-EBUSY); /* already opened */ } dib->adc_opened++; spin_unlock(&dib->adc_lock); } else if ((filp->f_flags & O_ACCMODE) == O_WRONLY) { spin_lock(&dib->dac_lock); if (dib->dac_opened) { spin_unlock(&dib->dac_lock); return(-EBUSY); /* already opened */ } dib->dac_opened++; spin_unlock(&dib->dac_lock); } /* calculate page order for ADC DMA buffer allocation */ if ((filp->f_flags & O_ACCMODE) == O_RDONLY) { if (PCI550X_DMA_PAGES == 1) dib->adc_dma_page_order = 0; else { dib->adc_dma_page_order = 1; for (i = 2; i < PCI550X_DMA_PAGES; i*=2, dib->adc_dma_page_order++); } /* allocate ADC DMA buffers */ dib->adc_dma_buf0 = (u_int32_t *)__get_free_pages(GFP_KERNEL | __GFP_DMA, dib->adc_dma_page_order); if (!dib->adc_dma_buf0) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "__get_free_pages() failure -" " kernel memory unavailable.\n"); dib->adc_opened--; return(-ENOMEM); } dib->adc_dma_buf1 = (u_int32_t *)__get_free_pages(GFP_KERNEL | __GFP_DMA, dib->adc_dma_page_order); if (!dib->adc_dma_buf1) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "__get_free_pages() failure -" " kernel memory unavailable.\n"); free_pages((unsigned long)dib->adc_dma_buf0, dib->adc_dma_page_order); dib->adc_dma_buf0 = (unsigned long)NULL; dib->adc_opened--; return(-ENOMEM); } /* setup the streaming DMA mappings */ dib->adc_dma_handle0 = pci_map_single(dib->pdev, (void *)dib->adc_dma_buf0, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_FROMDEVICE); if(!(dib->adc_dma_handle0)) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "pci_map_single() failure -" " DMA mapping failed.\n"); free_pages((unsigned long)dib->adc_dma_buf0, dib->adc_dma_page_order); dib->adc_dma_buf0 = (unsigned long)NULL; free_pages((unsigned long)dib->adc_dma_buf1, dib->adc_dma_page_order); dib->adc_dma_buf1 = (unsigned long)NULL; dib->adc_opened--; return(-ENOMEM); } dib->adc_dma_handle1 = pci_map_single(dib->pdev, (void *)dib->adc_dma_buf1, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_FROMDEVICE); if(!(dib->adc_dma_handle1)) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "pci_map_single() failure -" " DMA mapping failed.\n"); pci_unmap_single(dib->pdev, dib->adc_dma_handle0, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_FROMDEVICE); dib->adc_dma_handle0 = (dma_addr_t)NULL; free_pages((unsigned long)dib->adc_dma_buf0, dib->adc_dma_page_order); dib->adc_dma_buf0 = (unsigned long)NULL; free_pages((unsigned long)dib->adc_dma_buf1, dib->adc_dma_page_order); dib->adc_dma_buf1 = (unsigned long)NULL; dib->adc_opened--; return(-ENOMEM); } } else if ((filp->f_flags & O_ACCMODE) == O_WRONLY) { if (PCI550X_DMA_PAGES == 1) dib->dac0_dma_page_order = 0; else { dib->dac0_dma_page_order = 1; for (i = 2; i < PCI550X_DMA_PAGES; i*=2, dib->dac0_dma_page_order++); } /* allocate DAC0 DMA buffers */ dib->dac0_dma_buf0 = (u_int32_t *)__get_free_pages(GFP_KERNEL | __GFP_DMA, dib->dac0_dma_page_order); if (!dib->dac0_dma_buf0) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "__get_free_pages() failure -" " kernel memory unavailable.\n"); dib->dac_opened--; return(-ENOMEM); } dib->dac0_dma_buf1 = (u_int32_t *)__get_free_pages(GFP_KERNEL | __GFP_DMA, dib->dac0_dma_page_order); if (!dib->dac0_dma_buf1) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "__get_free_pages() failure -" " kernel memory unavailable.\n"); free_pages((unsigned long)dib->dac0_dma_buf0, dib->dac0_dma_page_order); dib->dac0_dma_buf0 = (unsigned long)NULL; pci550x_free_dac0_buffs(dib); dib->dac_opened--; return(-ENOMEM); } /* setup the streaming DMA mappings */ dib->dac0_dma_handle0 = pci_map_single(dib->pdev, (void *)dib->dac0_dma_buf0, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); if(!(dib->dac0_dma_handle0)) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "pci_map_single() failure -" " DMA mapping failed.\n"); free_pages((unsigned long)dib->dac0_dma_buf0, dib->dac0_dma_page_order); dib->dac0_dma_buf0 = (unsigned long)NULL; free_pages((unsigned long)dib->dac0_dma_buf1, dib->dac0_dma_page_order); dib->dac0_dma_buf1 = (unsigned long)NULL; pci550x_free_dac0_buffs(dib); dib->dac_opened--; return(-ENOMEM); } dib->dac0_dma_handle1 = pci_map_single(dib->pdev, (void *)dib->dac0_dma_buf1, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); if(!(dib->dac0_dma_handle1)) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "pci_map_single() failure -" " DMA mapping failed.\n"); pci_unmap_single(dib->pdev, dib->dac0_dma_handle0, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); dib->dac0_dma_handle0 = (dma_addr_t)NULL; free_pages((unsigned long)dib->dac0_dma_buf0, dib->dac0_dma_page_order); dib->dac0_dma_buf0 = (unsigned long)NULL; free_pages((unsigned long)dib->dac0_dma_buf1, dib->dac0_dma_page_order); dib->dac0_dma_buf1 = (unsigned long)NULL; pci550x_free_dac0_buffs(dib); dib->dac_opened--; return(-ENOMEM); } /* calculate page order for DAC1 DMA buffer allocation */ if (PCI550X_DMA_PAGES == 1) dib->dac1_dma_page_order = 0; else { dib->dac1_dma_page_order = 1; for (i = 2; i < PCI550X_DMA_PAGES; i*=2, dib->dac1_dma_page_order++); } /* allocate DAC1 DMA buffers */ dib->dac1_dma_buf0 = (u_int32_t *)__get_free_pages(GFP_KERNEL | __GFP_DMA, dib->dac1_dma_page_order); if (!dib->dac1_dma_buf0) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "__get_free_pages() failure -" " kernel memory unavailable.\n"); pci550x_free_dac0_buffs(dib); dib->dac_opened--; return(-ENOMEM); } dib->dac1_dma_buf1 = (u_int32_t *)__get_free_pages(GFP_KERNEL | __GFP_DMA, dib->dac1_dma_page_order); if (!dib->dac1_dma_buf1) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "__get_free_pages() failure -" " kernel memory unavailable.\n"); free_pages((unsigned long)dib->dac1_dma_buf0, dib->dac1_dma_page_order); dib->dac1_dma_buf0 = (unsigned long)NULL; pci550x_free_dac0_buffs(dib); pci550x_free_dac1_buffs(dib); dib->dac_opened--; return(-ENOMEM); } /* setup the streaming DMA mappings */ dib->dac1_dma_handle0 = pci_map_single(dib->pdev, (void *)dib->dac1_dma_buf0, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); if(!(dib->dac1_dma_handle0)) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "pci_map_single() failure -" " DMA mapping failed.\n"); free_pages((unsigned long)dib->dac1_dma_buf0, dib->dac1_dma_page_order); dib->dac1_dma_buf0 = (unsigned long)NULL; free_pages((unsigned long)dib->dac1_dma_buf1, dib->dac1_dma_page_order); dib->dac1_dma_buf1 = (unsigned long)NULL; pci550x_free_dac0_buffs(dib); pci550x_free_dac1_buffs(dib); dib->dac_opened--; return(-ENOMEM); } dib->dac1_dma_handle1 = pci_map_single(dib->pdev, (void *)dib->dac1_dma_buf1, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); if(!(dib->dac1_dma_handle1)) { printk(KERN_ERR PCI550X_PFX "In function pci550x_open:\n" "pci_map_single() failure -" " DMA mapping failed.\n"); pci_unmap_single(dib->pdev, dib->dac1_dma_handle0, PAGE_SIZE * PCI550X_DMA_PAGES, PCI_DMA_TODEVICE); dib->dac1_dma_handle0 = (dma_addr_t)NULL; free_pages((unsigned long)dib->dac1_dma_buf0, dib->dac1_dma_page_order); dib->dac1_dma_buf0 = (unsigned long)NULL; free_pages((unsigned long)dib->dac1_dma_buf1, dib->dac1_dma_page_order); dib->dac1_dma_buf1 = (unsigned long)NULL; pci550x_free_dac0_buffs(dib); pci550x_free_dac1_buffs(dib); dib->dac_opened--; return(-ENOMEM); } } /* end O_RDONLY/O_WRONLY check */ /* reset the board and request the interrupt on first open */ spin_lock(&dib->open_lock); if (dib->opened == 0) { pci550x_adc_reset(dib); if (dib->pdev->subsystem_device == PCI_SUBSYSTEM_ID_B) { pci550x_dac0_reset(dib); pci550x_dac1_reset(dib); } ret = request_irq(dib->irq, &pci550x_interrupt, SA_SHIRQ | SA_INTERRUPT, driver_name, (void *)dib); if (ret) { if (dib->adc_opened) { pci550x_free_adc_buffs(dib); dib->adc_opened--; } else if (dib->dac_opened) { pci550x_free_dac0_buffs(dib); pci550x_free_dac1_buffs(dib); dib->dac_opened--; } printk(KERN_ERR PCI550X_PFX "IRQ %d is not free.\n", dib->irq); spin_unlock(&dib->open_lock); return(ret); } } /* init the wait QUEUEs used for blocking I/O */ init_waitqueue_head(&dib->adc_wq); init_waitqueue_head(&dib->dac0_wq); init_waitqueue_head(&dib->dac1_wq); filp->private_data = (void *)dib; dib->opened++; spin_unlock(&dib->open_lock); return(ret);}/* * pci550x_release - release method */static int pci550x_release(struct inode* inode, struct file* filp){ pci550x_dib *dib = (pci550x_dib *)filp->private_data; /* * free the interrupt on final release */ spin_lock(&dib->open_lock); if (dib->opened == 1) free_irq(dib->irq, (void *)dib); /* free DMA buffers */ if (dib->adc_opened) { pci550x_free_adc_buffs(dib); dib->adc_opened--; } else if (dib->dac_opened) { pci550x_free_dac0_buffs(dib); pci550x_free_dac1_buffs(dib); dib->dac_opened--; } filp->private_data = NULL; dib->opened--; spin_unlock(&dib->open_lock); return(0); /* success */}/* * pci550x_read - read method (ADC Ping-Pong DMA) */static ssize_t pci550x_read(struct file* filp, char *buff, size_t count, loff_t *offp){ pci550x_dib *dib = (pci550x_dib *)filp->private_data; pci550x_hwregs *REGS = (pci550x_hwregs *)dib->membase; unsigned long bytes; long timeout; /* can't read more than one buffer at a time */ if (count > ((dib->adc_dma_bytes) - *offp)) return(-EINVAL); /* wait for the next ADC buffer */ AD_CTRL_R(dib->adc_ctrl); if (!(dib->adc_ctrl & AD_CTRL_CVEN)) return(0); /* EOF */ else if ( (dib->adc_status & AD_STATUS_MPRF0) && (dib->adc_status & AD_STATUS_MPRF1) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -