0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #include <linux/device.h>
0022 #include <linux/module.h>
0023 #include <linux/pci.h>
0024 #include <linux/slab.h>
0025 #include <linux/uio_driver.h>
0026
0027 #define DRIVER_VERSION "0.01.0"
0028 #define DRIVER_AUTHOR "Michael S. Tsirkin <mst@redhat.com>"
0029 #define DRIVER_DESC "Generic UIO driver for PCI 2.3 devices"
0030
0031 struct uio_pci_generic_dev {
0032 struct uio_info info;
0033 struct pci_dev *pdev;
0034 };
0035
0036 static inline struct uio_pci_generic_dev *
0037 to_uio_pci_generic_dev(struct uio_info *info)
0038 {
0039 return container_of(info, struct uio_pci_generic_dev, info);
0040 }
0041
0042 static int release(struct uio_info *info, struct inode *inode)
0043 {
0044 struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info);
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 pci_clear_master(gdev->pdev);
0055 return 0;
0056 }
0057
0058
0059
0060 static irqreturn_t irqhandler(int irq, struct uio_info *info)
0061 {
0062 struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info);
0063
0064 if (!pci_check_and_mask_intx(gdev->pdev))
0065 return IRQ_NONE;
0066
0067
0068 return IRQ_HANDLED;
0069 }
0070
0071 static int probe(struct pci_dev *pdev,
0072 const struct pci_device_id *id)
0073 {
0074 struct uio_pci_generic_dev *gdev;
0075 struct uio_mem *uiomem;
0076 int err;
0077 int i;
0078
0079 err = pcim_enable_device(pdev);
0080 if (err) {
0081 dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n",
0082 __func__, err);
0083 return err;
0084 }
0085
0086 if (pdev->irq && !pci_intx_mask_supported(pdev))
0087 return -ENODEV;
0088
0089 gdev = devm_kzalloc(&pdev->dev, sizeof(struct uio_pci_generic_dev), GFP_KERNEL);
0090 if (!gdev)
0091 return -ENOMEM;
0092
0093 gdev->info.name = "uio_pci_generic";
0094 gdev->info.version = DRIVER_VERSION;
0095 gdev->info.release = release;
0096 gdev->pdev = pdev;
0097 if (pdev->irq && (pdev->irq != IRQ_NOTCONNECTED)) {
0098 gdev->info.irq = pdev->irq;
0099 gdev->info.irq_flags = IRQF_SHARED;
0100 gdev->info.handler = irqhandler;
0101 } else {
0102 dev_warn(&pdev->dev, "No IRQ assigned to device: "
0103 "no support for interrupts?\n");
0104 }
0105
0106 uiomem = &gdev->info.mem[0];
0107 for (i = 0; i < MAX_UIO_MAPS; ++i) {
0108 struct resource *r = &pdev->resource[i];
0109
0110 if (r->flags != (IORESOURCE_SIZEALIGN | IORESOURCE_MEM))
0111 continue;
0112
0113 if (uiomem >= &gdev->info.mem[MAX_UIO_MAPS]) {
0114 dev_warn(
0115 &pdev->dev,
0116 "device has more than " __stringify(
0117 MAX_UIO_MAPS) " I/O memory resources.\n");
0118 break;
0119 }
0120
0121 uiomem->memtype = UIO_MEM_PHYS;
0122 uiomem->addr = r->start & PAGE_MASK;
0123 uiomem->offs = r->start & ~PAGE_MASK;
0124 uiomem->size =
0125 (uiomem->offs + resource_size(r) + PAGE_SIZE - 1) &
0126 PAGE_MASK;
0127 uiomem->name = r->name;
0128 ++uiomem;
0129 }
0130
0131 while (uiomem < &gdev->info.mem[MAX_UIO_MAPS]) {
0132 uiomem->size = 0;
0133 ++uiomem;
0134 }
0135
0136 return devm_uio_register_device(&pdev->dev, &gdev->info);
0137 }
0138
0139 static struct pci_driver uio_pci_driver = {
0140 .name = "uio_pci_generic",
0141 .id_table = NULL,
0142 .probe = probe,
0143 };
0144
0145 module_pci_driver(uio_pci_driver);
0146 MODULE_VERSION(DRIVER_VERSION);
0147 MODULE_LICENSE("GPL v2");
0148 MODULE_AUTHOR(DRIVER_AUTHOR);
0149 MODULE_DESCRIPTION(DRIVER_DESC);