Signed-off-by: Vlad Zolotarov <vl...@cloudius-systems.com>
---
 drivers/uio/uio_pci_generic.c | 89 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c
index d0b508b..2c6e2b1 100644
--- a/drivers/uio/uio_pci_generic.c
+++ b/drivers/uio/uio_pci_generic.c
@@ -40,6 +40,75 @@ to_uio_pci_generic_dev(struct uio_info *info)
        return container_of(info, struct uio_pci_generic_dev, info);
 }
 
+/* Unmap previously ioremap'd resources */
+static void release_iomaps(struct uio_pci_generic_dev *gdev)
+{
+       int i;
+       struct uio_mem *mem = gdev->info.mem;
+
+       for (i = 0; i < MAX_UIO_MAPS; i++, mem++) {
+               if (mem->internal_addr) {
+                       iounmap(mem->internal_addr);
+                       mem->internal_addr = NULL;
+               }
+       }
+}
+
+static int setup_maps(struct pci_dev *pdev, struct uio_info *info)
+{
+       int i, m = 0, p = 0, err;
+       static const char * const bar_names[] = {
+               "BAR0", "BAR1", "BAR2", "BAR3", "BAR4", "BAR5",
+       };
+
+       for (i = 0; i < ARRAY_SIZE(bar_names); i++) {
+               unsigned long start = pci_resource_start(pdev, i);
+               unsigned long flags = pci_resource_flags(pdev, i);
+               unsigned long len = pci_resource_len(pdev, i);
+
+               if (start == 0 || len == 0)
+                       continue;
+
+               if (flags & IORESOURCE_MEM) {
+                       void __iomem *addr;
+
+                       if (m >= MAX_UIO_MAPS)
+                               continue;
+
+                       addr = ioremap(start, len);
+                       if (addr == NULL) {
+                               err = -EINVAL;
+                               goto fail;
+                       }
+
+                       info->mem[m].name = bar_names[i];
+                       info->mem[m].addr = start;
+                       info->mem[m].internal_addr = addr;
+                       info->mem[m].size = len;
+                       info->mem[m].memtype = UIO_MEM_PHYS;
+                       ++m;
+               } else if (flags & IORESOURCE_IO) {
+                       if (p >= MAX_UIO_PORT_REGIONS)
+                               continue;
+
+                       info->port[p].name = bar_names[i];
+                       info->port[p].start = start;
+                       info->port[p].size = len;
+                       info->port[p].porttype = UIO_PORT_X86;
+                       ++p;
+               }
+       }
+
+       return 0;
+fail:
+       for (i = 0; i < m; i++) {
+               iounmap(info->mem[i].internal_addr);
+               info->mem[i].internal_addr = NULL;
+       }
+
+       return err;
+}
+
 /* Interrupt handler. Read/modify/write the command register to disable
  * the interrupt. */
 static irqreturn_t irqhandler(int irq, struct uio_info *info)
@@ -86,18 +155,35 @@ static int probe(struct pci_dev *pdev,
 
        gdev->info.name = "uio_pci_generic";
        gdev->info.version = DRIVER_VERSION;
+
+       err = pci_request_regions(pdev, "uio_pci_generic");
+       if (err != 0) {
+               dev_err(&pdev->dev, "Cannot request regions\n");
+               goto err_request_regions;
+       }
+
        gdev->info.irq = pdev->irq;
        gdev->info.irq_flags = IRQF_SHARED;
        gdev->info.handler = irqhandler;
        gdev->pdev = pdev;
 
+       /* remap resources */
+       err = setup_maps(pdev, &gdev->info);
+       if (err)
+               goto err_maps;
+
        err = uio_register_device(&pdev->dev, &gdev->info);
        if (err)
                goto err_register;
        pci_set_drvdata(pdev, gdev);
 
        return 0;
+
 err_register:
+       release_iomaps(gdev);
+err_maps:
+       pci_release_regions(pdev);
+err_request_regions:
        kfree(gdev);
 err_alloc:
 err_verify:
@@ -110,8 +196,11 @@ static void remove(struct pci_dev *pdev)
        struct uio_pci_generic_dev *gdev = pci_get_drvdata(pdev);
 
        uio_unregister_device(&gdev->info);
+       release_iomaps(gdev);
+       pci_release_regions(pdev);
        pci_disable_device(pdev);
        kfree(gdev);
+       pci_set_drvdata(pdev, NULL);
 }
 
 static struct pci_driver uio_pci_driver = {
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to