xref: /linux/drivers/comedi/comedi_pci.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
18ffdff6aSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
28ffdff6aSGreg Kroah-Hartman /*
38ffdff6aSGreg Kroah-Hartman  * comedi_pci.c
48ffdff6aSGreg Kroah-Hartman  * Comedi PCI driver specific functions.
58ffdff6aSGreg Kroah-Hartman  *
68ffdff6aSGreg Kroah-Hartman  * COMEDI - Linux Control and Measurement Device Interface
78ffdff6aSGreg Kroah-Hartman  * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
88ffdff6aSGreg Kroah-Hartman  */
98ffdff6aSGreg Kroah-Hartman 
108ffdff6aSGreg Kroah-Hartman #include <linux/module.h>
118ffdff6aSGreg Kroah-Hartman #include <linux/interrupt.h>
12*df0e68c1SIan Abbott #include <linux/comedi/comedi_pci.h>
138ffdff6aSGreg Kroah-Hartman 
148ffdff6aSGreg Kroah-Hartman /**
158ffdff6aSGreg Kroah-Hartman  * comedi_to_pci_dev() - Return PCI device attached to COMEDI device
168ffdff6aSGreg Kroah-Hartman  * @dev: COMEDI device.
178ffdff6aSGreg Kroah-Hartman  *
188ffdff6aSGreg Kroah-Hartman  * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a
198ffdff6aSGreg Kroah-Hartman  * a &struct device embedded in a &struct pci_dev.
208ffdff6aSGreg Kroah-Hartman  *
218ffdff6aSGreg Kroah-Hartman  * Return: Attached PCI device if @dev->hw_dev is non-%NULL.
228ffdff6aSGreg Kroah-Hartman  * Return %NULL if @dev->hw_dev is %NULL.
238ffdff6aSGreg Kroah-Hartman  */
comedi_to_pci_dev(struct comedi_device * dev)248ffdff6aSGreg Kroah-Hartman struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev)
258ffdff6aSGreg Kroah-Hartman {
268ffdff6aSGreg Kroah-Hartman 	return dev->hw_dev ? to_pci_dev(dev->hw_dev) : NULL;
278ffdff6aSGreg Kroah-Hartman }
288ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_to_pci_dev);
298ffdff6aSGreg Kroah-Hartman 
308ffdff6aSGreg Kroah-Hartman /**
318ffdff6aSGreg Kroah-Hartman  * comedi_pci_enable() - Enable the PCI device and request the regions
328ffdff6aSGreg Kroah-Hartman  * @dev: COMEDI device.
338ffdff6aSGreg Kroah-Hartman  *
348ffdff6aSGreg Kroah-Hartman  * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a
358ffdff6aSGreg Kroah-Hartman  * a &struct device embedded in a &struct pci_dev.  Enable the PCI device
368ffdff6aSGreg Kroah-Hartman  * and request its regions.  Set @dev->ioenabled to %true if successful,
378ffdff6aSGreg Kroah-Hartman  * otherwise undo what was done.
388ffdff6aSGreg Kroah-Hartman  *
398ffdff6aSGreg Kroah-Hartman  * Calls to comedi_pci_enable() and comedi_pci_disable() cannot be nested.
408ffdff6aSGreg Kroah-Hartman  *
418ffdff6aSGreg Kroah-Hartman  * Return:
428ffdff6aSGreg Kroah-Hartman  *	0 on success,
438ffdff6aSGreg Kroah-Hartman  *	-%ENODEV if @dev->hw_dev is %NULL,
448ffdff6aSGreg Kroah-Hartman  *	-%EBUSY if regions busy,
458ffdff6aSGreg Kroah-Hartman  *	or some negative error number if failed to enable PCI device.
468ffdff6aSGreg Kroah-Hartman  *
478ffdff6aSGreg Kroah-Hartman  */
comedi_pci_enable(struct comedi_device * dev)488ffdff6aSGreg Kroah-Hartman int comedi_pci_enable(struct comedi_device *dev)
498ffdff6aSGreg Kroah-Hartman {
508ffdff6aSGreg Kroah-Hartman 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
518ffdff6aSGreg Kroah-Hartman 	int rc;
528ffdff6aSGreg Kroah-Hartman 
538ffdff6aSGreg Kroah-Hartman 	if (!pcidev)
548ffdff6aSGreg Kroah-Hartman 		return -ENODEV;
558ffdff6aSGreg Kroah-Hartman 
568ffdff6aSGreg Kroah-Hartman 	rc = pci_enable_device(pcidev);
578ffdff6aSGreg Kroah-Hartman 	if (rc < 0)
588ffdff6aSGreg Kroah-Hartman 		return rc;
598ffdff6aSGreg Kroah-Hartman 
608ffdff6aSGreg Kroah-Hartman 	rc = pci_request_regions(pcidev, dev->board_name);
618ffdff6aSGreg Kroah-Hartman 	if (rc < 0)
628ffdff6aSGreg Kroah-Hartman 		pci_disable_device(pcidev);
638ffdff6aSGreg Kroah-Hartman 	else
648ffdff6aSGreg Kroah-Hartman 		dev->ioenabled = true;
658ffdff6aSGreg Kroah-Hartman 
668ffdff6aSGreg Kroah-Hartman 	return rc;
678ffdff6aSGreg Kroah-Hartman }
688ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pci_enable);
698ffdff6aSGreg Kroah-Hartman 
708ffdff6aSGreg Kroah-Hartman /**
718ffdff6aSGreg Kroah-Hartman  * comedi_pci_disable() - Release the regions and disable the PCI device
728ffdff6aSGreg Kroah-Hartman  * @dev: COMEDI device.
738ffdff6aSGreg Kroah-Hartman  *
748ffdff6aSGreg Kroah-Hartman  * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a
758ffdff6aSGreg Kroah-Hartman  * a &struct device embedded in a &struct pci_dev.  If the earlier call
768ffdff6aSGreg Kroah-Hartman  * to comedi_pci_enable() was successful, release the PCI device's regions
778ffdff6aSGreg Kroah-Hartman  * and disable it.  Reset @dev->ioenabled back to %false.
788ffdff6aSGreg Kroah-Hartman  */
comedi_pci_disable(struct comedi_device * dev)798ffdff6aSGreg Kroah-Hartman void comedi_pci_disable(struct comedi_device *dev)
808ffdff6aSGreg Kroah-Hartman {
818ffdff6aSGreg Kroah-Hartman 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
828ffdff6aSGreg Kroah-Hartman 
838ffdff6aSGreg Kroah-Hartman 	if (pcidev && dev->ioenabled) {
848ffdff6aSGreg Kroah-Hartman 		pci_release_regions(pcidev);
858ffdff6aSGreg Kroah-Hartman 		pci_disable_device(pcidev);
868ffdff6aSGreg Kroah-Hartman 	}
878ffdff6aSGreg Kroah-Hartman 	dev->ioenabled = false;
888ffdff6aSGreg Kroah-Hartman }
898ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pci_disable);
908ffdff6aSGreg Kroah-Hartman 
918ffdff6aSGreg Kroah-Hartman /**
928ffdff6aSGreg Kroah-Hartman  * comedi_pci_detach() - A generic "detach" handler for PCI COMEDI drivers
938ffdff6aSGreg Kroah-Hartman  * @dev: COMEDI device.
948ffdff6aSGreg Kroah-Hartman  *
958ffdff6aSGreg Kroah-Hartman  * COMEDI drivers for PCI devices that need no special clean-up of private data
968ffdff6aSGreg Kroah-Hartman  * and have no ioremapped regions other than that pointed to by @dev->mmio may
978ffdff6aSGreg Kroah-Hartman  * use this function as its "detach" handler called by the COMEDI core when a
988ffdff6aSGreg Kroah-Hartman  * COMEDI device is being detached from the low-level driver.  It may be also
998ffdff6aSGreg Kroah-Hartman  * called from a more specific "detach" handler that does additional clean-up.
1008ffdff6aSGreg Kroah-Hartman  *
1018ffdff6aSGreg Kroah-Hartman  * Free the IRQ if @dev->irq is non-zero, iounmap @dev->mmio if it is
1028ffdff6aSGreg Kroah-Hartman  * non-%NULL, and call comedi_pci_disable() to release the PCI device's regions
1038ffdff6aSGreg Kroah-Hartman  * and disable it.
1048ffdff6aSGreg Kroah-Hartman  */
comedi_pci_detach(struct comedi_device * dev)1058ffdff6aSGreg Kroah-Hartman void comedi_pci_detach(struct comedi_device *dev)
1068ffdff6aSGreg Kroah-Hartman {
1078ffdff6aSGreg Kroah-Hartman 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
1088ffdff6aSGreg Kroah-Hartman 
1098ffdff6aSGreg Kroah-Hartman 	if (!pcidev || !dev->ioenabled)
1108ffdff6aSGreg Kroah-Hartman 		return;
1118ffdff6aSGreg Kroah-Hartman 
1128ffdff6aSGreg Kroah-Hartman 	if (dev->irq) {
1138ffdff6aSGreg Kroah-Hartman 		free_irq(dev->irq, dev);
1148ffdff6aSGreg Kroah-Hartman 		dev->irq = 0;
1158ffdff6aSGreg Kroah-Hartman 	}
1168ffdff6aSGreg Kroah-Hartman 	if (dev->mmio) {
1178ffdff6aSGreg Kroah-Hartman 		iounmap(dev->mmio);
1188ffdff6aSGreg Kroah-Hartman 		dev->mmio = NULL;
1198ffdff6aSGreg Kroah-Hartman 	}
1208ffdff6aSGreg Kroah-Hartman 	comedi_pci_disable(dev);
1218ffdff6aSGreg Kroah-Hartman }
1228ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pci_detach);
1238ffdff6aSGreg Kroah-Hartman 
1248ffdff6aSGreg Kroah-Hartman /**
1258ffdff6aSGreg Kroah-Hartman  * comedi_pci_auto_config() - Configure/probe a PCI COMEDI device
1268ffdff6aSGreg Kroah-Hartman  * @pcidev: PCI device.
1278ffdff6aSGreg Kroah-Hartman  * @driver: Registered COMEDI driver.
1288ffdff6aSGreg Kroah-Hartman  * @context: Driver specific data, passed to comedi_auto_config().
1298ffdff6aSGreg Kroah-Hartman  *
1308ffdff6aSGreg Kroah-Hartman  * Typically called from the pci_driver (*probe) function.  Auto-configure
1318ffdff6aSGreg Kroah-Hartman  * a COMEDI device, using the &struct device embedded in *@pcidev as the
1328ffdff6aSGreg Kroah-Hartman  * hardware device.  The @context value gets passed through to @driver's
1338ffdff6aSGreg Kroah-Hartman  * "auto_attach" handler.  The "auto_attach" handler may call
1348ffdff6aSGreg Kroah-Hartman  * comedi_to_pci_dev() on the passed in COMEDI device to recover @pcidev.
1358ffdff6aSGreg Kroah-Hartman  *
1368ffdff6aSGreg Kroah-Hartman  * Return: The result of calling comedi_auto_config() (0 on success, or
1378ffdff6aSGreg Kroah-Hartman  * a negative error number on failure).
1388ffdff6aSGreg Kroah-Hartman  */
comedi_pci_auto_config(struct pci_dev * pcidev,struct comedi_driver * driver,unsigned long context)1398ffdff6aSGreg Kroah-Hartman int comedi_pci_auto_config(struct pci_dev *pcidev,
1408ffdff6aSGreg Kroah-Hartman 			   struct comedi_driver *driver,
1418ffdff6aSGreg Kroah-Hartman 			   unsigned long context)
1428ffdff6aSGreg Kroah-Hartman {
1438ffdff6aSGreg Kroah-Hartman 	return comedi_auto_config(&pcidev->dev, driver, context);
1448ffdff6aSGreg Kroah-Hartman }
1458ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
1468ffdff6aSGreg Kroah-Hartman 
1478ffdff6aSGreg Kroah-Hartman /**
1488ffdff6aSGreg Kroah-Hartman  * comedi_pci_auto_unconfig() - Unconfigure/remove a PCI COMEDI device
1498ffdff6aSGreg Kroah-Hartman  * @pcidev: PCI device.
1508ffdff6aSGreg Kroah-Hartman  *
1518ffdff6aSGreg Kroah-Hartman  * Typically called from the pci_driver (*remove) function.  Auto-unconfigure
1528ffdff6aSGreg Kroah-Hartman  * a COMEDI device attached to this PCI device, using a pointer to the
1538ffdff6aSGreg Kroah-Hartman  * &struct device embedded in *@pcidev as the hardware device.  The COMEDI
1548ffdff6aSGreg Kroah-Hartman  * driver's "detach" handler will be called during unconfiguration of the
1558ffdff6aSGreg Kroah-Hartman  * COMEDI device.
1568ffdff6aSGreg Kroah-Hartman  *
1578ffdff6aSGreg Kroah-Hartman  * Note that the COMEDI device may have already been unconfigured using the
1588ffdff6aSGreg Kroah-Hartman  * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it
1598ffdff6aSGreg Kroah-Hartman  * again should be ignored.
1608ffdff6aSGreg Kroah-Hartman  */
comedi_pci_auto_unconfig(struct pci_dev * pcidev)1618ffdff6aSGreg Kroah-Hartman void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
1628ffdff6aSGreg Kroah-Hartman {
1638ffdff6aSGreg Kroah-Hartman 	comedi_auto_unconfig(&pcidev->dev);
1648ffdff6aSGreg Kroah-Hartman }
1658ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig);
1668ffdff6aSGreg Kroah-Hartman 
1678ffdff6aSGreg Kroah-Hartman /**
1688ffdff6aSGreg Kroah-Hartman  * comedi_pci_driver_register() - Register a PCI COMEDI driver
1698ffdff6aSGreg Kroah-Hartman  * @comedi_driver: COMEDI driver to be registered.
1708ffdff6aSGreg Kroah-Hartman  * @pci_driver: PCI driver to be registered.
1718ffdff6aSGreg Kroah-Hartman  *
1728ffdff6aSGreg Kroah-Hartman  * This function is called from the module_init() of PCI COMEDI driver modules
1738ffdff6aSGreg Kroah-Hartman  * to register the COMEDI driver and the PCI driver.  Do not call it directly,
1748ffdff6aSGreg Kroah-Hartman  * use the module_comedi_pci_driver() helper macro instead.
1758ffdff6aSGreg Kroah-Hartman  *
1768ffdff6aSGreg Kroah-Hartman  * Return: 0 on success, or a negative error number on failure.
1778ffdff6aSGreg Kroah-Hartman  */
comedi_pci_driver_register(struct comedi_driver * comedi_driver,struct pci_driver * pci_driver)1788ffdff6aSGreg Kroah-Hartman int comedi_pci_driver_register(struct comedi_driver *comedi_driver,
1798ffdff6aSGreg Kroah-Hartman 			       struct pci_driver *pci_driver)
1808ffdff6aSGreg Kroah-Hartman {
1818ffdff6aSGreg Kroah-Hartman 	int ret;
1828ffdff6aSGreg Kroah-Hartman 
1838ffdff6aSGreg Kroah-Hartman 	ret = comedi_driver_register(comedi_driver);
1848ffdff6aSGreg Kroah-Hartman 	if (ret < 0)
1858ffdff6aSGreg Kroah-Hartman 		return ret;
1868ffdff6aSGreg Kroah-Hartman 
1878ffdff6aSGreg Kroah-Hartman 	ret = pci_register_driver(pci_driver);
1888ffdff6aSGreg Kroah-Hartman 	if (ret < 0) {
1898ffdff6aSGreg Kroah-Hartman 		comedi_driver_unregister(comedi_driver);
1908ffdff6aSGreg Kroah-Hartman 		return ret;
1918ffdff6aSGreg Kroah-Hartman 	}
1928ffdff6aSGreg Kroah-Hartman 
1938ffdff6aSGreg Kroah-Hartman 	return 0;
1948ffdff6aSGreg Kroah-Hartman }
1958ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pci_driver_register);
1968ffdff6aSGreg Kroah-Hartman 
1978ffdff6aSGreg Kroah-Hartman /**
1988ffdff6aSGreg Kroah-Hartman  * comedi_pci_driver_unregister() - Unregister a PCI COMEDI driver
1998ffdff6aSGreg Kroah-Hartman  * @comedi_driver: COMEDI driver to be unregistered.
2008ffdff6aSGreg Kroah-Hartman  * @pci_driver: PCI driver to be unregistered.
2018ffdff6aSGreg Kroah-Hartman  *
2028ffdff6aSGreg Kroah-Hartman  * This function is called from the module_exit() of PCI COMEDI driver modules
2038ffdff6aSGreg Kroah-Hartman  * to unregister the PCI driver and the COMEDI driver.  Do not call it
2048ffdff6aSGreg Kroah-Hartman  * directly, use the module_comedi_pci_driver() helper macro instead.
2058ffdff6aSGreg Kroah-Hartman  */
comedi_pci_driver_unregister(struct comedi_driver * comedi_driver,struct pci_driver * pci_driver)2068ffdff6aSGreg Kroah-Hartman void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver,
2078ffdff6aSGreg Kroah-Hartman 				  struct pci_driver *pci_driver)
2088ffdff6aSGreg Kroah-Hartman {
2098ffdff6aSGreg Kroah-Hartman 	pci_unregister_driver(pci_driver);
2108ffdff6aSGreg Kroah-Hartman 	comedi_driver_unregister(comedi_driver);
2118ffdff6aSGreg Kroah-Hartman }
2128ffdff6aSGreg Kroah-Hartman EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister);
2138ffdff6aSGreg Kroah-Hartman 
comedi_pci_init(void)2148ffdff6aSGreg Kroah-Hartman static int __init comedi_pci_init(void)
2158ffdff6aSGreg Kroah-Hartman {
2168ffdff6aSGreg Kroah-Hartman 	return 0;
2178ffdff6aSGreg Kroah-Hartman }
2188ffdff6aSGreg Kroah-Hartman module_init(comedi_pci_init);
2198ffdff6aSGreg Kroah-Hartman 
comedi_pci_exit(void)2208ffdff6aSGreg Kroah-Hartman static void __exit comedi_pci_exit(void)
2218ffdff6aSGreg Kroah-Hartman {
2228ffdff6aSGreg Kroah-Hartman }
2238ffdff6aSGreg Kroah-Hartman module_exit(comedi_pci_exit);
2248ffdff6aSGreg Kroah-Hartman 
2258ffdff6aSGreg Kroah-Hartman MODULE_AUTHOR("https://www.comedi.org");
2268ffdff6aSGreg Kroah-Hartman MODULE_DESCRIPTION("Comedi PCI interface module");
2278ffdff6aSGreg Kroah-Hartman MODULE_LICENSE("GPL");
228