summaryrefslogtreecommitdiff
path: root/linux-core/drm_irq.c
diff options
context:
space:
mode:
authorEric Anholt <anholt@freebsd.org>2003-11-05 08:13:52 +0000
committerEric Anholt <anholt@freebsd.org>2003-11-05 08:13:52 +0000
commit66c9e3053f857df340a982edaa8ea57b229efeed (patch)
treef1ba7392f422b2687952f0242c6916d1ac766fea /linux-core/drm_irq.c
parent19ee64add26773f4436440f8fa405a1011eea4c4 (diff)
- Tie the DRM to a specific device: setunique no longer succeeds when given
a busid that doesn't correspond to the device the DRM is attached to. This is a breaking of backwards-compatibility only for the multiple-DRI-head case with X Servers that don't use interface 1.1. - Move irq_busid to drm_irq.h and make it only return the IRQ for the current device. Retains compatibility with previous X Servers, cleans up unnecessary code. This means no irq_busid on !__HAVE_IRQ, but can be changed if necessary. - Bump interface version to 1.2. This version when set signifies that the control ioctl should ignore the irq number passed in and enable the interrupt handler for the attached device. Otherwise it errors out when the passed-in irq is not equal to the device's. - Store the highest version the interface has been set to in the device. - Fix a recursion on DRM_LOCK in irq_uninstall on FreeBSD. This leaves irq_uninstall being done without the lock in some cases, but it was racey anyways.
Diffstat (limited to 'linux-core/drm_irq.c')
-rw-r--r--linux-core/drm_irq.c69
1 files changed, 55 insertions, 14 deletions
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c
index 322e5717..837e6951 100644
--- a/linux-core/drm_irq.c
+++ b/linux-core/drm_irq.c
@@ -48,6 +48,44 @@
#define DRM_IRQ_TYPE 0
#endif
+/**
+ * Get interrupt from bus id.
+ *
+ * \param inode device inode.
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument, pointing to a drm_irq_busid structure.
+ * \return zero on success or a negative number on failure.
+ *
+ * Finds the PCI device with the specified bus id and gets its IRQ number.
+ * This IOCTL is deprecated, and will now return EINVAL for any busid not equal
+ * to that of the device that this DRM instance attached to.
+ */
+int DRM(irq_by_busid)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_irq_busid_t p;
+
+ if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
+ return -EFAULT;
+
+ if ((p.busnum >> 8) != dev->pci_domain ||
+ (p.busnum & 0xff) != dev->pci_bus ||
+ p.devnum != dev->pci_slot ||
+ p.funcnum != dev->pci_func)
+ return -EINVAL;
+
+ p.irq = dev->irq;
+
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+ p.busnum, p.devnum, p.funcnum, p.irq);
+ if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
+ return -EFAULT;
+ return 0;
+}
+
#if __HAVE_IRQ
/**
@@ -60,11 +98,11 @@
* \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions
* before and after the installation.
*/
-int DRM(irq_install)( drm_device_t *dev, int irq )
+int DRM(irq_install)( drm_device_t *dev )
{
int ret;
-
- if ( !irq )
+
+ if ( dev->irq == 0 )
return -EINVAL;
down( &dev->struct_sem );
@@ -75,14 +113,14 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
return -EINVAL;
}
- if ( dev->irq ) {
+ if ( dev->irq_enabled ) {
up( &dev->struct_sem );
return -EBUSY;
}
- dev->irq = irq;
+ dev->irq_enabled = 1;
up( &dev->struct_sem );
- DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
+ DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
dev->context_flag = 0;
dev->interrupt_flag = 0;
@@ -121,7 +159,7 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
DRM_IRQ_TYPE, dev->devname, dev );
if ( ret < 0 ) {
down( &dev->struct_sem );
- dev->irq = 0;
+ dev->irq_enabled = 0;
up( &dev->struct_sem );
return ret;
}
@@ -141,21 +179,21 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
*/
int DRM(irq_uninstall)( drm_device_t *dev )
{
- int irq;
+ int irq_enabled;
down( &dev->struct_sem );
- irq = dev->irq;
- dev->irq = 0;
+ irq_enabled = dev->irq_enabled;
+ dev->irq_enabled = 0;
up( &dev->struct_sem );
- if ( !irq )
+ if ( !irq_enabled )
return -EINVAL;
- DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
+ DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
DRM(driver_irq_uninstall)( dev );
- free_irq( irq, dev );
+ free_irq( dev->irq, dev );
return 0;
}
@@ -183,7 +221,10 @@ int DRM(control)( struct inode *inode, struct file *filp,
switch ( ctl.func ) {
case DRM_INST_HANDLER:
- return DRM(irq_install)( dev, ctl.irq );
+ if (dev->if_version < DRM_IF_VERSION(1, 2) &&
+ ctl.irq != dev->irq)
+ return -EINVAL;
+ return DRM(irq_install)( dev );
case DRM_UNINST_HANDLER:
return DRM(irq_uninstall)( dev );
default: