1ccb86a69SMichael S. Tsirkin /* uio_pci_generic - generic UIO driver for PCI 2.3 devices 2ccb86a69SMichael S. Tsirkin * 3ccb86a69SMichael S. Tsirkin * Copyright (C) 2009 Red Hat, Inc. 4ccb86a69SMichael S. Tsirkin * Author: Michael S. Tsirkin <mst@redhat.com> 5ccb86a69SMichael S. Tsirkin * 6ccb86a69SMichael S. Tsirkin * This work is licensed under the terms of the GNU GPL, version 2. 7ccb86a69SMichael S. Tsirkin * 8ccb86a69SMichael S. Tsirkin * Since the driver does not declare any device ids, you must allocate 9ccb86a69SMichael S. Tsirkin * id and bind the device to the driver yourself. For example: 10ccb86a69SMichael S. Tsirkin * 11ccb86a69SMichael S. Tsirkin * # echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id 12ccb86a69SMichael S. Tsirkin * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind 13ccb86a69SMichael S. Tsirkin * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind 14ccb86a69SMichael S. Tsirkin * # ls -l /sys/bus/pci/devices/0000:00:19.0/driver 15ccb86a69SMichael S. Tsirkin * .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic 16ccb86a69SMichael S. Tsirkin * 17ccb86a69SMichael S. Tsirkin * Driver won't bind to devices which do not support the Interrupt Disable Bit 18ccb86a69SMichael S. Tsirkin * in the command register. All devices compliant to PCI 2.3 (circa 2002) and 19ccb86a69SMichael S. Tsirkin * all compliant PCI Express devices should support this bit. 20ccb86a69SMichael S. Tsirkin */ 21ccb86a69SMichael S. Tsirkin 22ccb86a69SMichael S. Tsirkin #include <linux/device.h> 23ccb86a69SMichael S. Tsirkin #include <linux/module.h> 24ccb86a69SMichael S. Tsirkin #include <linux/pci.h> 255a0e3ad6STejun Heo #include <linux/slab.h> 26ccb86a69SMichael S. Tsirkin #include <linux/uio_driver.h> 27ccb86a69SMichael S. Tsirkin 28ccb86a69SMichael S. Tsirkin #define DRIVER_VERSION "0.01.0" 29ccb86a69SMichael S. Tsirkin #define DRIVER_AUTHOR "Michael S. Tsirkin <mst@redhat.com>" 30ccb86a69SMichael S. Tsirkin #define DRIVER_DESC "Generic UIO driver for PCI 2.3 devices" 31ccb86a69SMichael S. Tsirkin 32ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev { 33ccb86a69SMichael S. Tsirkin struct uio_info info; 34ccb86a69SMichael S. Tsirkin struct pci_dev *pdev; 35ccb86a69SMichael S. Tsirkin }; 36ccb86a69SMichael S. Tsirkin 37ccb86a69SMichael S. Tsirkin static inline struct uio_pci_generic_dev * 38ccb86a69SMichael S. Tsirkin to_uio_pci_generic_dev(struct uio_info *info) 39ccb86a69SMichael S. Tsirkin { 40ccb86a69SMichael S. Tsirkin return container_of(info, struct uio_pci_generic_dev, info); 41ccb86a69SMichael S. Tsirkin } 42ccb86a69SMichael S. Tsirkin 43ccb86a69SMichael S. Tsirkin /* Interrupt handler. Read/modify/write the command register to disable 44ccb86a69SMichael S. Tsirkin * the interrupt. */ 45ccb86a69SMichael S. Tsirkin static irqreturn_t irqhandler(int irq, struct uio_info *info) 46ccb86a69SMichael S. Tsirkin { 47ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info); 48ccb86a69SMichael S. Tsirkin 49*2502dbdfSJan Kiszka if (!pci_check_and_mask_intx(gdev->pdev)) 50*2502dbdfSJan Kiszka return IRQ_NONE; 51ccb86a69SMichael S. Tsirkin 52ccb86a69SMichael S. Tsirkin /* UIO core will signal the user process. */ 53*2502dbdfSJan Kiszka return IRQ_HANDLED; 54ccb86a69SMichael S. Tsirkin } 55ccb86a69SMichael S. Tsirkin 56ccb86a69SMichael S. Tsirkin static int __devinit probe(struct pci_dev *pdev, 57ccb86a69SMichael S. Tsirkin const struct pci_device_id *id) 58ccb86a69SMichael S. Tsirkin { 59ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev *gdev; 60ccb86a69SMichael S. Tsirkin int err; 61ccb86a69SMichael S. Tsirkin 62ccb86a69SMichael S. Tsirkin err = pci_enable_device(pdev); 63ccb86a69SMichael S. Tsirkin if (err) { 64ccb86a69SMichael S. Tsirkin dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n", 65ccb86a69SMichael S. Tsirkin __func__, err); 66ccb86a69SMichael S. Tsirkin return err; 67ccb86a69SMichael S. Tsirkin } 68ccb86a69SMichael S. Tsirkin 691037246cSKulikov Vasiliy if (!pdev->irq) { 701037246cSKulikov Vasiliy dev_warn(&pdev->dev, "No IRQ assigned to device: " 711037246cSKulikov Vasiliy "no support for interrupts?\n"); 721037246cSKulikov Vasiliy pci_disable_device(pdev); 731037246cSKulikov Vasiliy return -ENODEV; 741037246cSKulikov Vasiliy } 751037246cSKulikov Vasiliy 76*2502dbdfSJan Kiszka if (!pci_intx_mask_supported(pdev)) { 77*2502dbdfSJan Kiszka err = -ENODEV; 78ccb86a69SMichael S. Tsirkin goto err_verify; 79*2502dbdfSJan Kiszka } 80ccb86a69SMichael S. Tsirkin 81ccb86a69SMichael S. Tsirkin gdev = kzalloc(sizeof(struct uio_pci_generic_dev), GFP_KERNEL); 82ccb86a69SMichael S. Tsirkin if (!gdev) { 83ccb86a69SMichael S. Tsirkin err = -ENOMEM; 84ccb86a69SMichael S. Tsirkin goto err_alloc; 85ccb86a69SMichael S. Tsirkin } 86ccb86a69SMichael S. Tsirkin 87ccb86a69SMichael S. Tsirkin gdev->info.name = "uio_pci_generic"; 88ccb86a69SMichael S. Tsirkin gdev->info.version = DRIVER_VERSION; 89ccb86a69SMichael S. Tsirkin gdev->info.irq = pdev->irq; 90ccb86a69SMichael S. Tsirkin gdev->info.irq_flags = IRQF_SHARED; 91ccb86a69SMichael S. Tsirkin gdev->info.handler = irqhandler; 92ccb86a69SMichael S. Tsirkin gdev->pdev = pdev; 93ccb86a69SMichael S. Tsirkin 94ccb86a69SMichael S. Tsirkin if (uio_register_device(&pdev->dev, &gdev->info)) 95ccb86a69SMichael S. Tsirkin goto err_register; 96ccb86a69SMichael S. Tsirkin pci_set_drvdata(pdev, gdev); 97ccb86a69SMichael S. Tsirkin 98ccb86a69SMichael S. Tsirkin return 0; 99ccb86a69SMichael S. Tsirkin err_register: 100ccb86a69SMichael S. Tsirkin kfree(gdev); 101ccb86a69SMichael S. Tsirkin err_alloc: 102ccb86a69SMichael S. Tsirkin err_verify: 103ccb86a69SMichael S. Tsirkin pci_disable_device(pdev); 104ccb86a69SMichael S. Tsirkin return err; 105ccb86a69SMichael S. Tsirkin } 106ccb86a69SMichael S. Tsirkin 107ccb86a69SMichael S. Tsirkin static void remove(struct pci_dev *pdev) 108ccb86a69SMichael S. Tsirkin { 109ccb86a69SMichael S. Tsirkin struct uio_pci_generic_dev *gdev = pci_get_drvdata(pdev); 110ccb86a69SMichael S. Tsirkin 111ccb86a69SMichael S. Tsirkin uio_unregister_device(&gdev->info); 112ccb86a69SMichael S. Tsirkin pci_disable_device(pdev); 113ccb86a69SMichael S. Tsirkin kfree(gdev); 114ccb86a69SMichael S. Tsirkin } 115ccb86a69SMichael S. Tsirkin 116ccb86a69SMichael S. Tsirkin static struct pci_driver driver = { 117ccb86a69SMichael S. Tsirkin .name = "uio_pci_generic", 118ccb86a69SMichael S. Tsirkin .id_table = NULL, /* only dynamic id's */ 119ccb86a69SMichael S. Tsirkin .probe = probe, 120ccb86a69SMichael S. Tsirkin .remove = remove, 121ccb86a69SMichael S. Tsirkin }; 122ccb86a69SMichael S. Tsirkin 123ccb86a69SMichael S. Tsirkin static int __init init(void) 124ccb86a69SMichael S. Tsirkin { 125ccb86a69SMichael S. Tsirkin pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); 126ccb86a69SMichael S. Tsirkin return pci_register_driver(&driver); 127ccb86a69SMichael S. Tsirkin } 128ccb86a69SMichael S. Tsirkin 129ccb86a69SMichael S. Tsirkin static void __exit cleanup(void) 130ccb86a69SMichael S. Tsirkin { 131ccb86a69SMichael S. Tsirkin pci_unregister_driver(&driver); 132ccb86a69SMichael S. Tsirkin } 133ccb86a69SMichael S. Tsirkin 134ccb86a69SMichael S. Tsirkin module_init(init); 135ccb86a69SMichael S. Tsirkin module_exit(cleanup); 136ccb86a69SMichael S. Tsirkin 137ccb86a69SMichael S. Tsirkin MODULE_VERSION(DRIVER_VERSION); 138ccb86a69SMichael S. Tsirkin MODULE_LICENSE("GPL v2"); 139ccb86a69SMichael S. Tsirkin MODULE_AUTHOR(DRIVER_AUTHOR); 140ccb86a69SMichael S. Tsirkin MODULE_DESCRIPTION(DRIVER_DESC); 141