diff options
Diffstat (limited to 'drivers/uio')
-rw-r--r-- | drivers/uio/Kconfig | 21 | ||||
-rw-r--r-- | drivers/uio/Makefile | 2 | ||||
-rw-r--r-- | drivers/uio/uio.c | 40 | ||||
-rw-r--r-- | drivers/uio/uio_dmem_genirq.c | 2 | ||||
-rw-r--r-- | drivers/uio/uio_mf624.c | 247 | ||||
-rw-r--r-- | drivers/uio/uio_pdrv.c | 113 | ||||
-rw-r--r-- | drivers/uio/uio_pdrv_genirq.c | 2 | ||||
-rw-r--r-- | drivers/uio/uio_pruss.c | 3 |
8 files changed, 281 insertions, 149 deletions
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 5295be0..5a90914 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -1,5 +1,6 @@ menuconfig UIO tristate "Userspace I/O drivers" + depends on MMU help Enable this to allow the userspace driver core code to be built. This code allows userspace programs easy access to @@ -23,13 +24,6 @@ config UIO_CIF To compile this driver as a module, choose M here: the module will be called uio_cif. -config UIO_PDRV - tristate "Userspace I/O platform driver" - help - Generic platform driver for Userspace I/O devices. - - If you don't know what to do here, say N. - config UIO_PDRV_GENIRQ tristate "Userspace I/O platform driver with generic IRQ handling" help @@ -128,4 +122,17 @@ config UIO_PRUSS To compile this driver as a module, choose M here: the module will be called uio_pruss. +config UIO_MF624 + tristate "Humusoft MF624 DAQ PCI card driver" + depends on PCI + help + Userspace I/O interface for the Humusoft MF624 PCI card. + A sample userspace application using this driver is available + (among other MF624 related information and software components) + for download in a git repository: + + git clone git://rtime.felk.cvut.cz/mf6xx.git + + If you compile this as a module, it will be called uio_mf624. + endif diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index b354c53..d3218bd 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -1,6 +1,5 @@ obj-$(CONFIG_UIO) += uio.o obj-$(CONFIG_UIO_CIF) += uio_cif.o -obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o obj-$(CONFIG_UIO_DMEM_GENIRQ) += uio_dmem_genirq.o obj-$(CONFIG_UIO_AEC) += uio_aec.o @@ -8,3 +7,4 @@ obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o obj-$(CONFIG_UIO_NETX) += uio_netx.o obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o +obj-$(CONFIG_UIO_MF624) += uio_mf624.o diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 170a178..ba47563 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -35,7 +35,6 @@ struct uio_device { atomic_t event; struct fasync_struct *async_queue; wait_queue_head_t wait; - int vma_count; struct uio_info *info; struct kobject *map_dir; struct kobject *portio_dir; @@ -597,18 +596,6 @@ static int uio_find_mem_index(struct vm_area_struct *vma) return -1; } -static void uio_vma_open(struct vm_area_struct *vma) -{ - struct uio_device *idev = vma->vm_private_data; - idev->vma_count++; -} - -static void uio_vma_close(struct vm_area_struct *vma) -{ - struct uio_device *idev = vma->vm_private_data; - idev->vma_count--; -} - static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct uio_device *idev = vma->vm_private_data; @@ -634,12 +621,23 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return 0; } -static const struct vm_operations_struct uio_vm_ops = { - .open = uio_vma_open, - .close = uio_vma_close, +static const struct vm_operations_struct uio_logical_vm_ops = { .fault = uio_vma_fault, }; +static int uio_mmap_logical(struct vm_area_struct *vma) +{ + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = &uio_logical_vm_ops; + return 0; +} + +static const struct vm_operations_struct uio_physical_vm_ops = { +#ifdef CONFIG_HAVE_IOREMAP_PROT + .access = generic_access_phys, +#endif +}; + static int uio_mmap_physical(struct vm_area_struct *vma) { struct uio_device *idev = vma->vm_private_data; @@ -647,6 +645,8 @@ static int uio_mmap_physical(struct vm_area_struct *vma) if (mi < 0) return -EINVAL; + vma->vm_ops = &uio_physical_vm_ops; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); return remap_pfn_range(vma, @@ -656,14 +656,6 @@ static int uio_mmap_physical(struct vm_area_struct *vma) vma->vm_page_prot); } -static int uio_mmap_logical(struct vm_area_struct *vma) -{ - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = &uio_vm_ops; - uio_vma_open(vma); - return 0; -} - static int uio_mmap(struct file *filep, struct vm_area_struct *vma) { struct uio_listener *listener = filep->private_data; diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index 125d0e5..1270f3b 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -146,7 +146,7 @@ static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) static int uio_dmem_genirq_probe(struct platform_device *pdev) { - struct uio_dmem_genirq_pdata *pdata = pdev->dev.platform_data; + struct uio_dmem_genirq_pdata *pdata = dev_get_platdata(&pdev->dev); struct uio_info *uioinfo = &pdata->uioinfo; struct uio_dmem_genirq_platdata *priv; struct uio_mem *uiomem; diff --git a/drivers/uio/uio_mf624.c b/drivers/uio/uio_mf624.c new file mode 100644 index 0000000..a1768b2 --- /dev/null +++ b/drivers/uio/uio_mf624.c @@ -0,0 +1,247 @@ +/* + * UIO driver fo Humusoft MF624 DAQ card. + * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>, + * Czech Technical University in Prague + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/uio_driver.h> + +#define PCI_VENDOR_ID_HUMUSOFT 0x186c +#define PCI_DEVICE_ID_MF624 0x0624 +#define PCI_SUBVENDOR_ID_HUMUSOFT 0x186c +#define PCI_SUBDEVICE_DEVICE 0x0624 + +/* BAR0 Interrupt control/status register */ +#define INTCSR 0x4C +#define INTCSR_ADINT_ENABLE (1 << 0) +#define INTCSR_CTR4INT_ENABLE (1 << 3) +#define INTCSR_PCIINT_ENABLE (1 << 6) +#define INTCSR_ADINT_STATUS (1 << 2) +#define INTCSR_CTR4INT_STATUS (1 << 5) + +enum mf624_interrupt_source {ADC, CTR4, ALL}; + +void mf624_disable_interrupt(enum mf624_interrupt_source source, + struct uio_info *info) +{ + void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR; + + switch (source) { + case ADC: + iowrite32(ioread32(INTCSR_reg) + & ~(INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE), + INTCSR_reg); + break; + + case CTR4: + iowrite32(ioread32(INTCSR_reg) + & ~(INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE), + INTCSR_reg); + break; + + case ALL: + default: + iowrite32(ioread32(INTCSR_reg) + & ~(INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE + | INTCSR_PCIINT_ENABLE), + INTCSR_reg); + break; + } +} + +void mf624_enable_interrupt(enum mf624_interrupt_source source, + struct uio_info *info) +{ + void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR; + + switch (source) { + case ADC: + iowrite32(ioread32(INTCSR_reg) + | INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE, + INTCSR_reg); + break; + + case CTR4: + iowrite32(ioread32(INTCSR_reg) + | INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE, + INTCSR_reg); + break; + + case ALL: + default: + iowrite32(ioread32(INTCSR_reg) + | INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE + | INTCSR_PCIINT_ENABLE, + INTCSR_reg); + break; + } +} + +static irqreturn_t mf624_irq_handler(int irq, struct uio_info *info) +{ + void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR; + + if ((ioread32(INTCSR_reg) & INTCSR_ADINT_ENABLE) + && (ioread32(INTCSR_reg) & INTCSR_ADINT_STATUS)) { + mf624_disable_interrupt(ADC, info); + return IRQ_HANDLED; + } + + if ((ioread32(INTCSR_reg) & INTCSR_CTR4INT_ENABLE) + && (ioread32(INTCSR_reg) & INTCSR_CTR4INT_STATUS)) { + mf624_disable_interrupt(CTR4, info); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int mf624_irqcontrol(struct uio_info *info, s32 irq_on) +{ + if (irq_on == 0) + mf624_disable_interrupt(ALL, info); + else if (irq_on == 1) + mf624_enable_interrupt(ALL, info); + + return 0; +} + +static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct uio_info *info; + + info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + if (pci_enable_device(dev)) + goto out_free; + + if (pci_request_regions(dev, "mf624")) + goto out_disable; + + info->name = "mf624"; + info->version = "0.0.1"; + + /* Note: Datasheet says device uses BAR0, BAR1, BAR2 -- do not trust it */ + + /* BAR0 */ + info->mem[0].name = "PCI chipset, interrupts, status " + "bits, special functions"; + info->mem[0].addr = pci_resource_start(dev, 0); + if (!info->mem[0].addr) + goto out_release; + info->mem[0].size = pci_resource_len(dev, 0); + info->mem[0].memtype = UIO_MEM_PHYS; + info->mem[0].internal_addr = pci_ioremap_bar(dev, 0); + if (!info->mem[0].internal_addr) + goto out_release; + + /* BAR2 */ + info->mem[1].name = "ADC, DAC, DIO"; + info->mem[1].addr = pci_resource_start(dev, 2); + if (!info->mem[1].addr) + goto out_unmap0; + info->mem[1].size = pci_resource_len(dev, 2); + info->mem[1].memtype = UIO_MEM_PHYS; + info->mem[1].internal_addr = pci_ioremap_bar(dev, 2); + if (!info->mem[1].internal_addr) + goto out_unmap0; + + /* BAR4 */ + info->mem[2].name = "Counter/timer chip"; + info->mem[2].addr = pci_resource_start(dev, 4); + if (!info->mem[2].addr) + goto out_unmap1; + info->mem[2].size = pci_resource_len(dev, 4); + info->mem[2].memtype = UIO_MEM_PHYS; + info->mem[2].internal_addr = pci_ioremap_bar(dev, 4); + if (!info->mem[2].internal_addr) + goto out_unmap1; + + info->irq = dev->irq; + info->irq_flags = IRQF_SHARED; + info->handler = mf624_irq_handler; + + info->irqcontrol = mf624_irqcontrol; + + if (uio_register_device(&dev->dev, info)) + goto out_unmap2; + + pci_set_drvdata(dev, info); + + return 0; + +out_unmap2: + iounmap(info->mem[2].internal_addr); +out_unmap1: + iounmap(info->mem[1].internal_addr); +out_unmap0: + iounmap(info->mem[0].internal_addr); + +out_release: + pci_release_regions(dev); + +out_disable: + pci_disable_device(dev); + +out_free: + kfree(info); + return -ENODEV; +} + +static void mf624_pci_remove(struct pci_dev *dev) +{ + struct uio_info *info = pci_get_drvdata(dev); + + mf624_disable_interrupt(ALL, info); + + uio_unregister_device(info); + pci_release_regions(dev); + pci_disable_device(dev); + pci_set_drvdata(dev, NULL); + + iounmap(info->mem[0].internal_addr); + iounmap(info->mem[1].internal_addr); + iounmap(info->mem[2].internal_addr); + + kfree(info); +} + +static DEFINE_PCI_DEVICE_TABLE(mf624_pci_id) = { + { PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) }, + { 0, } +}; + +static struct pci_driver mf624_pci_driver = { + .name = "mf624", + .id_table = mf624_pci_id, + .probe = mf624_pci_probe, + .remove = mf624_pci_remove, +}; +MODULE_DEVICE_TABLE(pci, mf624_pci_id); + +module_pci_driver(mf624_pci_driver); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>"); diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c deleted file mode 100644 index 39be9e0..0000000 --- a/drivers/uio/uio_pdrv.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * drivers/uio/uio_pdrv.c - * - * Copyright (C) 2008 by Digi International Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ -#include <linux/platform_device.h> -#include <linux/uio_driver.h> -#include <linux/stringify.h> -#include <linux/module.h> -#include <linux/slab.h> - -#define DRIVER_NAME "uio_pdrv" - -struct uio_platdata { - struct uio_info *uioinfo; -}; - -static int uio_pdrv_probe(struct platform_device *pdev) -{ - struct uio_info *uioinfo = pdev->dev.platform_data; - struct uio_platdata *pdata; - struct uio_mem *uiomem; - int ret = -ENODEV; - int i; - - if (!uioinfo || !uioinfo->name || !uioinfo->version) { - dev_dbg(&pdev->dev, "%s: err_uioinfo\n", __func__); - goto err_uioinfo; - } - - pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - ret = -ENOMEM; - dev_dbg(&pdev->dev, "%s: err_alloc_pdata\n", __func__); - goto err_alloc_pdata; - } - - pdata->uioinfo = uioinfo; - - uiomem = &uioinfo->mem[0]; - - for (i = 0; i < pdev->num_resources; ++i) { - struct resource *r = &pdev->resource[i]; - - if (r->flags != IORESOURCE_MEM) - continue; - - if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { - dev_warn(&pdev->dev, "device has more than " - __stringify(MAX_UIO_MAPS) - " I/O memory resources.\n"); - break; - } - - uiomem->memtype = UIO_MEM_PHYS; - uiomem->addr = r->start; - uiomem->size = resource_size(r); - uiomem->name = r->name; - ++uiomem; - } - - while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) { - uiomem->size = 0; - ++uiomem; - } - - pdata->uioinfo->priv = pdata; - - ret = uio_register_device(&pdev->dev, pdata->uioinfo); - - if (ret) { - kfree(pdata); -err_alloc_pdata: -err_uioinfo: - return ret; - } - - platform_set_drvdata(pdev, pdata); - - return 0; -} - -static int uio_pdrv_remove(struct platform_device *pdev) -{ - struct uio_platdata *pdata = platform_get_drvdata(pdev); - - uio_unregister_device(pdata->uioinfo); - - kfree(pdata); - - return 0; -} - -static struct platform_driver uio_pdrv = { - .probe = uio_pdrv_probe, - .remove = uio_pdrv_remove, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(uio_pdrv); - -MODULE_AUTHOR("Uwe Kleine-Koenig"); -MODULE_DESCRIPTION("Userspace I/O platform driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 4eb8eaf..90ff17a 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -104,7 +104,7 @@ static int uio_pdrv_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) static int uio_pdrv_genirq_probe(struct platform_device *pdev) { - struct uio_info *uioinfo = pdev->dev.platform_data; + struct uio_info *uioinfo = dev_get_platdata(&pdev->dev); struct uio_pdrv_genirq_platdata *priv; struct uio_mem *uiomem; int ret = -EINVAL; diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index 21f7a72..f519da9 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -121,7 +121,7 @@ static int pruss_probe(struct platform_device *dev) struct uio_pruss_dev *gdev; struct resource *regs_prussio; int ret = -ENODEV, cnt = 0, len; - struct uio_pruss_pdata *pdata = dev->dev.platform_data; + struct uio_pruss_pdata *pdata = dev_get_platdata(&dev->dev); gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL); if (!gdev) @@ -224,7 +224,6 @@ static int pruss_remove(struct platform_device *dev) struct uio_pruss_dev *gdev = platform_get_drvdata(dev); pruss_cleanup(dev, gdev); - platform_set_drvdata(dev, NULL); return 0; } |