Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | // SPDX-License-Identifier: GPL-2.0+ /* * comedi_pci.c * Comedi PCI driver specific functions. * * COMEDI - Linux Control and Measurement Device Interface * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> */ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/comedi/comedi_pci.h> /** * comedi_to_pci_dev() - Return PCI device attached to COMEDI device * @dev: COMEDI device. * * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a * a &struct device embedded in a &struct pci_dev. * * Return: Attached PCI device if @dev->hw_dev is non-%NULL. * Return %NULL if @dev->hw_dev is %NULL. */ struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) { return dev->hw_dev ? to_pci_dev(dev->hw_dev) : NULL; } EXPORT_SYMBOL_GPL(comedi_to_pci_dev); /** * comedi_pci_enable() - Enable the PCI device and request the regions * @dev: COMEDI device. * * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a * a &struct device embedded in a &struct pci_dev. Enable the PCI device * and request its regions. Set @dev->ioenabled to %true if successful, * otherwise undo what was done. * * Calls to comedi_pci_enable() and comedi_pci_disable() cannot be nested. * * Return: * 0 on success, * -%ENODEV if @dev->hw_dev is %NULL, * -%EBUSY if regions busy, * or some negative error number if failed to enable PCI device. * */ int comedi_pci_enable(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); int rc; if (!pcidev) return -ENODEV; rc = pci_enable_device(pcidev); if (rc < 0) return rc; rc = pci_request_regions(pcidev, dev->board_name); if (rc < 0) pci_disable_device(pcidev); else dev->ioenabled = true; return rc; } EXPORT_SYMBOL_GPL(comedi_pci_enable); /** * comedi_pci_disable() - Release the regions and disable the PCI device * @dev: COMEDI device. * * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a * a &struct device embedded in a &struct pci_dev. If the earlier call * to comedi_pci_enable() was successful, release the PCI device's regions * and disable it. Reset @dev->ioenabled back to %false. */ void comedi_pci_disable(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); if (pcidev && dev->ioenabled) { pci_release_regions(pcidev); pci_disable_device(pcidev); } dev->ioenabled = false; } EXPORT_SYMBOL_GPL(comedi_pci_disable); /** * comedi_pci_detach() - A generic "detach" handler for PCI COMEDI drivers * @dev: COMEDI device. * * COMEDI drivers for PCI devices that need no special clean-up of private data * and have no ioremapped regions other than that pointed to by @dev->mmio may * use this function as its "detach" handler called by the COMEDI core when a * COMEDI device is being detached from the low-level driver. It may be also * called from a more specific "detach" handler that does additional clean-up. * * Free the IRQ if @dev->irq is non-zero, iounmap @dev->mmio if it is * non-%NULL, and call comedi_pci_disable() to release the PCI device's regions * and disable it. */ void comedi_pci_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); if (!pcidev || !dev->ioenabled) return; if (dev->irq) { free_irq(dev->irq, dev); dev->irq = 0; } if (dev->mmio) { iounmap(dev->mmio); dev->mmio = NULL; } comedi_pci_disable(dev); } EXPORT_SYMBOL_GPL(comedi_pci_detach); /** * comedi_pci_auto_config() - Configure/probe a PCI COMEDI device * @pcidev: PCI device. * @driver: Registered COMEDI driver. * @context: Driver specific data, passed to comedi_auto_config(). * * Typically called from the pci_driver (*probe) function. Auto-configure * a COMEDI device, using the &struct device embedded in *@pcidev as the * hardware device. The @context value gets passed through to @driver's * "auto_attach" handler. The "auto_attach" handler may call * comedi_to_pci_dev() on the passed in COMEDI device to recover @pcidev. * * Return: The result of calling comedi_auto_config() (0 on success, or * a negative error number on failure). */ int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver, unsigned long context) { return comedi_auto_config(&pcidev->dev, driver, context); } EXPORT_SYMBOL_GPL(comedi_pci_auto_config); /** * comedi_pci_auto_unconfig() - Unconfigure/remove a PCI COMEDI device * @pcidev: PCI device. * * Typically called from the pci_driver (*remove) function. Auto-unconfigure * a COMEDI device attached to this PCI device, using a pointer to the * &struct device embedded in *@pcidev as the hardware device. The COMEDI * driver's "detach" handler will be called during unconfiguration of the * COMEDI device. * * Note that the COMEDI device may have already been unconfigured using the * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it * again should be ignored. */ void comedi_pci_auto_unconfig(struct pci_dev *pcidev) { comedi_auto_unconfig(&pcidev->dev); } EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); /** * comedi_pci_driver_register() - Register a PCI COMEDI driver * @comedi_driver: COMEDI driver to be registered. * @pci_driver: PCI driver to be registered. * * This function is called from the module_init() of PCI COMEDI driver modules * to register the COMEDI driver and the PCI driver. Do not call it directly, * use the module_comedi_pci_driver() helper macro instead. * * Return: 0 on success, or a negative error number on failure. */ int comedi_pci_driver_register(struct comedi_driver *comedi_driver, struct pci_driver *pci_driver) { int ret; ret = comedi_driver_register(comedi_driver); if (ret < 0) return ret; ret = pci_register_driver(pci_driver); if (ret < 0) { comedi_driver_unregister(comedi_driver); return ret; } return 0; } EXPORT_SYMBOL_GPL(comedi_pci_driver_register); /** * comedi_pci_driver_unregister() - Unregister a PCI COMEDI driver * @comedi_driver: COMEDI driver to be unregistered. * @pci_driver: PCI driver to be unregistered. * * This function is called from the module_exit() of PCI COMEDI driver modules * to unregister the PCI driver and the COMEDI driver. Do not call it * directly, use the module_comedi_pci_driver() helper macro instead. */ void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver, struct pci_driver *pci_driver) { pci_unregister_driver(pci_driver); comedi_driver_unregister(comedi_driver); } EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister); static int __init comedi_pci_init(void) { return 0; } module_init(comedi_pci_init); static void __exit comedi_pci_exit(void) { } module_exit(comedi_pci_exit); MODULE_AUTHOR("https://www.comedi.org"); MODULE_DESCRIPTION("Comedi PCI interface module"); MODULE_LICENSE("GPL"); |