// SPDX-License-Identifier: GPL-2.0 /* sercos3: UIO driver for the Automata Sercos III PCI card Copyright (C) 2008 Linutronix GmbH Author: John Ogness <[email protected]> This is a straight-forward UIO driver, where interrupts are disabled by the interrupt handler and re-enabled via a write to the UIO device by the userspace-part. The only part that may seem odd is the use of a logical OR when storing and restoring enabled interrupts. This is done because the userspace-part could directly modify the Interrupt Enable Register at any time. To reduce possible conflicts, the kernel driver uses a logical OR to make more controlled changes (rather than blindly overwriting previous values). Race conditions exist if the userspace-part directly modifies the Interrupt Enable Register while in operation. The consequences are that certain interrupts would fail to be enabled or disabled. For this reason, the userspace-part should only directly modify the Interrupt Enable Register at the beginning (to get things going). The userspace-part can safely disable interrupts at any time using a write to the UIO device. */ #include <linux/device.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/uio_driver.h> #include <linux/io.h> #include <linux/slab.h> /* ID's for SERCOS III PCI card (PLX 9030) */ #define SERCOS_SUB_VENDOR_ID … #define SERCOS_SUB_SYSID_3530 … #define SERCOS_SUB_SYSID_3535 … #define SERCOS_SUB_SYSID_3780 … /* Interrupt Enable Register */ #define IER0_OFFSET … /* Interrupt Status Register */ #define ISR0_OFFSET … struct sercos3_priv { … }; /* this function assumes ier0_cache_lock is locked! */ static void sercos3_disable_interrupts(struct uio_info *info, struct sercos3_priv *priv) { … } /* this function assumes ier0_cache_lock is locked! */ static void sercos3_enable_interrupts(struct uio_info *info, struct sercos3_priv *priv) { … } static irqreturn_t sercos3_handler(int irq, struct uio_info *info) { … } static int sercos3_irqcontrol(struct uio_info *info, s32 irq_on) { … } static int sercos3_setup_iomem(struct pci_dev *dev, struct uio_info *info, int n, int pci_bar) { … } static int sercos3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { … } static void sercos3_pci_remove(struct pci_dev *dev) { … } static struct pci_device_id sercos3_pci_ids[] = …; static struct pci_driver sercos3_pci_driver = …; module_pci_driver(…) …; MODULE_DESCRIPTION(…) …; MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …;