The Flexcard PCI BAR0 contain registers for configuration but also for informational purpose like error counter, statistical information and some timestamps. The read-only mmap of the misc device offers the userspace a fast access to these registers. Signed-off-by: Benedikt Spranger <b.spranger@xxxxxxxxxxxxx> Signed-off-by: Holger Dengler <dengler@xxxxxxxxxxxxx> cc: Arnd Bergmann <arnd@xxxxxxxx> cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/mfd/Kconfig | 1 + drivers/misc/Kconfig | 6 ++ drivers/misc/Makefile | 1 + drivers/misc/flexcard_misc.c | 165 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) create mode 100644 drivers/misc/flexcard_misc.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 85fedf6..580f521 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -303,6 +303,7 @@ config MFD_FLEXCARD tristate "Eberspaecher Flexcard PMC II Carrier Board" select MFD_CORE select IRQ_DOMAIN + select FLEXCARD_MISC depends on PCI help This is the core driver for the Eberspaecher Flexcard diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 64971ba..3f54b58 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -766,6 +766,12 @@ config PANEL_BOOT_MESSAGE An empty message will only clear the display at driver init time. Any other printf()-formatted message is valid with newline and escape codes. +config FLEXCARD_MISC + tristate "Flexcard Misc Device driver" + depends on MFD_FLEXCARD + help + Misc driver for Flexcard PMC II. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 3198336..08a1729 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_PANEL) += panel.o +obj-$(CONFIG_FLEXCARD_MISC) += flexcard_misc.o lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o diff --git a/drivers/misc/flexcard_misc.c b/drivers/misc/flexcard_misc.c new file mode 100644 index 0000000..93c951c --- /dev/null +++ b/drivers/misc/flexcard_misc.c @@ -0,0 +1,165 @@ +/* + * Eberspächer Flexcard PMC II Misc Device + * + * Copyright (c) 2014 - 2016, Linutronix GmbH + * Author: Benedikt Spranger <b.spranger@xxxxxxxxxxxxx> + * Holger Dengler <dengler@xxxxxxxxxxxxx> + * + * 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/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/kref.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> + +#include <linux/mfd/flexcard.h> + +#define FLEXCARD_MAX_NAME 16 + +struct flexcard_misc { + char name[FLEXCARD_MAX_NAME]; + struct miscdevice dev; + struct platform_device *pdev; + struct fc_bar0_conf __iomem *conf; + struct fc_bar0_nf __iomem *nf; +}; + +static int flexcard_misc_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long offset, vsize, psize, addr; + struct flexcard_misc *priv; + struct resource *res; + + priv = container_of(filp->private_data, struct flexcard_misc, dev); + if (!priv) + return -EINVAL; + + if (vma->vm_flags & (VM_WRITE | VM_EXEC)) + return -EPERM; + + res = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); + offset = vma->vm_pgoff << PAGE_SHIFT; + if (offset > resource_size(res)) { + dev_err(&priv->pdev->dev, + "mmap offset out of resource range\n"); + return -EINVAL; + } + + vsize = vma->vm_end - vma->vm_start; + psize = round_up(resource_size(res) - offset, PAGE_SIZE); + addr = (res->start + offset) >> PAGE_SHIFT; + if (vsize > psize) { + dev_err(&priv->pdev->dev, + "requested mmap mapping too large\n"); + return -EINVAL; + } + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + return io_remap_pfn_range(vma, vma->vm_start, addr, vsize, + vma->vm_page_prot); +} + +static const struct file_operations flexcard_misc_fops = { + .owner = THIS_MODULE, + .open = nonseekable_open, + .mmap = flexcard_misc_mmap, + .llseek = no_llseek, +}; + +static int flexcard_misc_iomap(struct platform_device *pdev) +{ + struct flexcard_misc *priv = platform_get_drvdata(pdev); + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + priv->conf = ioremap_nocache(res->start, resource_size(res)); + if (!priv->conf) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + ret = -ENXIO; + goto out; + } + + priv->nf = ioremap_nocache(res->start, resource_size(res)); + if (!priv->nf) { + ret = -ENOMEM; + goto out; + } + + return 0; +out: + iounmap(priv->conf); + return ret; +} + +static int flexcard_misc_probe(struct platform_device *pdev) +{ + struct flexcard_misc *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + ret = flexcard_misc_iomap(pdev); + if (ret) { + dev_err(&pdev->dev, "failed to map resource: %d\n", ret); + return ret; + } + + snprintf(priv->name, sizeof(priv->name), + "flexcard%d", pdev->id); + priv->dev.name = priv->name; + priv->dev.minor = MISC_DYNAMIC_MINOR; + priv->dev.fops = &flexcard_misc_fops; + priv->dev.parent = &pdev->dev; + priv->pdev = pdev; + + ret = misc_register(&priv->dev); + if (ret) { + dev_err(&pdev->dev, "unable to register miscdevice: %d\n", ret); + return ret; + } + + return 0; +} + +static int flexcard_misc_remove(struct platform_device *pdev) +{ + struct flexcard_misc *priv = platform_get_drvdata(pdev); + + misc_deregister(&priv->dev); + + return 0; +} + +static struct platform_driver flexcard_misc_driver = { + .probe = flexcard_misc_probe, + .remove = flexcard_misc_remove, + .driver = { + .name = "flexcard-misc", + }, +}; + +module_platform_driver(flexcard_misc_driver); + +MODULE_AUTHOR("Holger Dengler <dengler@xxxxxxxxxxxxx>"); +MODULE_AUTHOR("Benedikt Spranger <b.spranger@xxxxxxxxxxxxx>"); +MODULE_DESCRIPTION("Eberspaecher Flexcard PMC II Misc Driver"); +MODULE_LICENSE("GPL v2"); -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe dmaengine" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html