summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bsd-core/drmP.h16
-rw-r--r--bsd-core/drm_drv.c16
-rw-r--r--bsd-core/drm_ioctl.c91
-rw-r--r--bsd-core/drm_irq.c120
-rw-r--r--bsd/drmP.h16
-rw-r--r--bsd/drm_drv.h16
-rw-r--r--bsd/drm_ioctl.h91
-rw-r--r--bsd/drm_irq.h120
-rw-r--r--linux-core/drmP.h16
-rw-r--r--linux-core/drm_drv.c17
-rw-r--r--linux-core/drm_ioctl.c174
-rw-r--r--linux-core/drm_irq.c69
-rw-r--r--linux-core/i810_dma.c2
-rw-r--r--linux-core/i830_dma.c4
-rw-r--r--linux/drmP.h16
-rw-r--r--linux/drm_drv.h17
-rw-r--r--linux/drm_ioctl.h174
-rw-r--r--linux/drm_irq.h69
-rw-r--r--linux/gamma_dma.c2
-rw-r--r--linux/i810_dma.c2
-rw-r--r--linux/i830_dma.c4
-rw-r--r--shared-core/mga_dma.c2
-rw-r--r--shared-core/r128_cce.c2
-rw-r--r--shared-core/radeon_cp.c2
-rw-r--r--shared/mga_dma.c2
-rw-r--r--shared/r128_cce.c2
-rw-r--r--shared/radeon_cp.c2
27 files changed, 511 insertions, 553 deletions
diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h
index 4b7d737b..82a226a9 100644
--- a/bsd-core/drmP.h
+++ b/bsd-core/drmP.h
@@ -118,6 +118,8 @@ typedef struct drm_file drm_file_t;
#define DRM_MIN(a,b) ((a)<(b)?(a):(b))
#define DRM_MAX(a,b) ((a)>(b)?(a):(b))
+#define DRM_IF_VERSION(maj, min) (maj << 16 | min)
+
#define DRM_GET_PRIV_SAREA(_dev, _ctx, _map) do { \
(_map) = (_dev)->context_sareas[_ctx]; \
} while(0)
@@ -316,6 +318,7 @@ struct drm_device {
device_t device; /* Device instance from newbus */
#endif
dev_t devnode; /* Device number for mknod */
+ int if_version; /* Highest interface version set */
int flags; /* Flags to open(2) */
@@ -355,14 +358,21 @@ struct drm_device {
/* Context support */
int irq; /* Interrupt used by board */
- int irqrid; /* Interrupt used by board */
+ int irq_enabled; /* True if the irq handler is enabled */
#ifdef __FreeBSD__
+ int irqrid; /* Interrupt used by board */
struct resource *irqr; /* Resource for interrupt used by board */
#elif defined(__NetBSD__)
struct pci_attach_args pa;
pci_intr_handle_t ih;
#endif
void *irqh; /* Handle from bus_setup_intr */
+
+ int pci_domain;
+ int pci_bus;
+ int pci_slot;
+ int pci_func;
+
atomic_t context_flag; /* Context swapping flag */
int last_context; /* Last current context */
#if __FreeBSD_version >= 400005
@@ -445,7 +455,7 @@ extern void DRM(reclaim_buffers)(drm_device_t *dev, DRMFILE filp);
#if __HAVE_IRQ
/* IRQ support (drm_irq.h) */
-extern int DRM(irq_install)( drm_device_t *dev, int irq );
+extern int DRM(irq_install)(drm_device_t *dev);
extern int DRM(irq_uninstall)( drm_device_t *dev );
extern irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS );
extern void DRM(driver_irq_preinstall)( drm_device_t *dev );
@@ -494,7 +504,7 @@ extern int DRM(version)( DRM_IOCTL_ARGS );
extern int DRM(setversion)( DRM_IOCTL_ARGS );
/* Misc. IOCTL support (drm_ioctl.h) */
-extern int DRM(irq_busid)(DRM_IOCTL_ARGS);
+extern int DRM(irq_by_busid)(DRM_IOCTL_ARGS);
extern int DRM(getunique)(DRM_IOCTL_ARGS);
extern int DRM(setunique)(DRM_IOCTL_ARGS);
extern int DRM(getmap)(DRM_IOCTL_ARGS);
diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c
index 0cbc1083..1083f9f9 100644
--- a/bsd-core/drm_drv.c
+++ b/bsd-core/drm_drv.c
@@ -134,7 +134,9 @@ static drm_ioctl_desc_t DRM(ioctls)[] = {
[DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 },
+#if __HAVE_IRQ
+ [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_by_busid), 0, 1 },
+#endif
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 },
@@ -477,9 +479,10 @@ static int DRM(setup)( drm_device_t *dev )
dev->lock.hw_lock = NULL;
dev->lock.lock_queue = 0;
- dev->irq = 0;
+ dev->irq_enabled = 0;
dev->context_flag = 0;
dev->last_context = 0;
+ dev->if_version = 0;
#ifdef __FreeBSD__
dev->buf_sigio = NULL;
@@ -507,7 +510,7 @@ static int DRM(takedown)( drm_device_t *dev )
DRIVER_PRETAKEDOWN();
#if __HAVE_IRQ
- if (dev->irq != 0)
+ if (dev->irq_enabled)
DRM(irq_uninstall)( dev );
#endif
@@ -644,6 +647,13 @@ static int DRM(init)( device_t nbdev )
unit = minor(dev->device.dv_unit);
#endif
+ dev->irq = pci_get_irq(dev->device);
+ /* XXX Fix domain number (alpha hoses) */
+ dev->pci_domain = 0;
+ dev->pci_bus = pci_get_bus(dev->device);
+ dev->pci_slot = pci_get_slot(dev->device);
+ dev->pci_func = pci_get_function(dev->device);
+
dev->maplist = DRM(calloc)(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
if (dev->maplist == NULL) {
retcode = ENOMEM;
diff --git a/bsd-core/drm_ioctl.c b/bsd-core/drm_ioctl.c
index 50cf937d..0952211e 100644
--- a/bsd-core/drm_ioctl.c
+++ b/bsd-core/drm_ioctl.c
@@ -32,53 +32,6 @@
#include "drmP.h"
-int DRM(irq_busid)( DRM_IOCTL_ARGS )
-{
-#ifdef __FreeBSD__
- drm_irq_busid_t id;
- devclass_t pci;
- device_t bus, dev;
- device_t *kids;
- int error, i, num_kids;
-
- DRM_COPY_FROM_USER_IOCTL( id, (drm_irq_busid_t *)data, sizeof(id) );
-
- pci = devclass_find("pci");
- if (!pci)
- return ENOENT;
- bus = devclass_get_device(pci, id.busnum);
- if (!bus)
- return ENOENT;
- error = device_get_children(bus, &kids, &num_kids);
- if (error)
- return error;
-
- dev = 0;
- for (i = 0; i < num_kids; i++) {
- dev = kids[i];
- if (pci_get_slot(dev) == id.devnum
- && pci_get_function(dev) == id.funcnum)
- break;
- }
-
- free(kids, M_TEMP);
-
- if (i != num_kids)
- id.irq = pci_get_irq(dev);
- else
- id.irq = 0;
- DRM_DEBUG("%d:%d:%d => IRQ %d\n",
- id.busnum, id.devnum, id.funcnum, id.irq);
-
- DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, id, sizeof(id) );
-
- return 0;
-#else
- /* don't support interrupt-driven drivers on Net yet */
- return ENOENT;
-#endif
-}
-
/*
* Beginning in revision 1.1 of the DRM interface, getunique will return
* a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function)
@@ -109,7 +62,8 @@ int DRM(getunique)( DRM_IOCTL_ARGS )
int DRM(setunique)( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
- drm_unique_t u;
+ drm_unique_t u;
+ int domain, bus, slot, func, ret;
if (dev->unique_len || dev->unique)
return DRM_ERR(EBUSY);
@@ -130,6 +84,21 @@ int DRM(setunique)( DRM_IOCTL_ARGS )
dev->unique[dev->unique_len] = '\0';
+ /* Return error if the busid submitted doesn't match the device's actual
+ * busid.
+ */
+ ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+ if (ret != 3)
+ return DRM_ERR(EINVAL);
+ domain = bus >> 8;
+ bus &= 0xff;
+
+ if ((domain != dev->pci_domain) ||
+ (bus != dev->pci_bus) ||
+ (slot != dev->pci_slot) ||
+ (func != dev->pci_func))
+ return DRM_ERR(EINVAL);
+
return 0;
}
@@ -146,10 +115,8 @@ DRM(set_busid)(drm_device_t *dev)
if (dev->unique == NULL)
return ENOMEM;
- /* XXX Fix domain number (alpha hoses) */
snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x",
- 0, pci_get_bus(dev->device), pci_get_slot(dev->device),
- pci_get_function(dev->device));
+ dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
return 0;
}
@@ -260,26 +227,31 @@ int DRM(getstats)( DRM_IOCTL_ARGS )
return 0;
}
+#define DRM_IF_MAJOR 1
+#define DRM_IF_MINOR 2
+
int DRM(setversion)(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_set_version_t sv;
drm_set_version_t retv;
+ int if_version;
DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof(sv));
- retv.drm_di_major = 1;
- retv.drm_di_minor = 1;
+ retv.drm_di_major = DRM_IF_MAJOR;
+ retv.drm_di_minor = DRM_IF_MINOR;
retv.drm_dd_major = DRIVER_MAJOR;
retv.drm_dd_minor = DRIVER_MINOR;
DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof(sv));
if (sv.drm_di_major != -1) {
- if (sv.drm_di_major != 1 || sv.drm_di_minor < 0)
- return EINVAL;
- if (sv.drm_di_minor > 1)
+ if (sv.drm_di_major != DRM_IF_MAJOR ||
+ sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
return EINVAL;
+ if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor);
+ dev->if_version = DRM_MAX(if_version, dev->if_version);
if (sv.drm_di_minor >= 1) {
/*
* Version 1.1 includes tying of DRM to specific device
@@ -289,12 +261,11 @@ int DRM(setversion)(DRM_IOCTL_ARGS)
}
if (sv.drm_dd_major != -1) {
- if (sv.drm_dd_major != DRIVER_MAJOR || sv.drm_dd_minor < 0)
- return EINVAL;
- if (sv.drm_dd_minor > DRIVER_MINOR)
+ if (sv.drm_dd_major != DRIVER_MAJOR ||
+ sv.drm_dd_minor < 0 || sv.drm_dd_minor > DRIVER_MINOR)
return EINVAL;
#ifdef DRIVER_SETVERSION
- DRIVER_SETVERSION(dev, sv);
+ DRIVER_SETVERSION(dev, &sv);
#endif
}
return 0;
diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c
index f984118e..1de817c3 100644
--- a/bsd-core/drm_irq.c
+++ b/bsd-core/drm_irq.c
@@ -28,6 +28,29 @@
*
*/
+int DRM(irq_by_busid)( DRM_IOCTL_ARGS )
+{
+ DRM_DEVICE;
+ drm_irq_busid_t irq;
+
+ DRM_COPY_FROM_USER_IOCTL(irq, (drm_irq_busid_t *)data, sizeof(irq));
+
+ if ((irq.busnum >> 8) != dev->pci_domain ||
+ (irq.busnum & 0xff) != dev->pci_bus ||
+ irq.devnum != dev->pci_slot ||
+ irq.funcnum != dev->pci_func)
+ return EINVAL;
+
+ irq.irq = dev->irq;
+
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+ irq.busnum, irq.devnum, irq.funcnum, irq.irq);
+
+ DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, irq, sizeof(irq) );
+
+ return 0;
+}
+
#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
static irqreturn_t
DRM(irq_handler_wrap)(DRM_IRQ_ARGS)
@@ -40,22 +63,22 @@ DRM(irq_handler_wrap)(DRM_IRQ_ARGS)
}
#endif
-int DRM(irq_install)( drm_device_t *dev, int irq )
+int DRM(irq_install)(drm_device_t *dev)
{
int retcode;
- if ( irq == 0 || dev->dev_private == NULL)
+ if (dev->irq == 0 || dev->dev_private == NULL)
return DRM_ERR(EINVAL);
DRM_LOCK();
- if ( dev->irq ) {
+ if (dev->irq_enabled) {
DRM_UNLOCK();
return DRM_ERR(EBUSY);
}
- dev->irq = irq;
+ dev->irq_enabled = 1;
DRM_UNLOCK();
- DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
+ DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
dev->context_flag = 0;
@@ -68,31 +91,18 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
DRM_SPININIT(dev->irq_lock, "DRM IRQ lock");
-#if __HAVE_VBL_IRQ && 0 /* disabled */
- TAILQ_INIT( &dev->vbl_sig_list );
-#endif
-
/* Before installing handler */
DRM(driver_irq_preinstall)( dev );
/* Install handler */
- dev->irqrid = 0;
#ifdef __FreeBSD__
+ dev->irqrid = 0;
dev->irqr = bus_alloc_resource(dev->device, SYS_RES_IRQ, &dev->irqrid,
0, ~0, 1, RF_SHAREABLE);
if (!dev->irqr) {
-#elif defined(__NetBSD__)
- if (pci_intr_map(&dev->pa, &dev->ih) != 0) {
-#endif
- DRM_LOCK();
- DRM_SPINUNINIT(dev->irq_lock);
- dev->irq = 0;
- dev->irqrid = 0;
- DRM_UNLOCK();
- return ENOENT;
+ retcode = ENOENT;
+ goto err;
}
-
-#ifdef __FreeBSD__
#if __FreeBSD_version < 500000
retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY,
DRM(irq_handler), dev, &dev->irqh);
@@ -100,45 +110,56 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE,
DRM(irq_handler_wrap), dev, &dev->irqh);
#endif
- if ( retcode ) {
+ if (retcode != 0)
+ goto err;
#elif defined(__NetBSD__)
+ if (pci_intr_map(&dev->pa, &dev->ih) != 0) {
+ retcode = ENOENT;
+ goto err;
+ }
dev->irqh = pci_intr_establish(&dev->pa.pa_pc, dev->ih, IPL_TTY,
(irqreturn_t (*)(DRM_IRQ_ARGS))DRM(irq_handler), dev);
- if ( !dev->irqh ) {
-#endif
- DRM_LOCK();
-#ifdef __FreeBSD__
- bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid, dev->irqr);
-#endif
- DRM_SPINUNINIT(dev->irq_lock);
- dev->irq = 0;
- dev->irqrid = 0;
- DRM_UNLOCK();
- return retcode;
+ if (!dev->irqh) {
+ retcode = ENOENT;
+ goto err;
}
+#endif
/* After installing handler */
DRM(driver_irq_postinstall)( dev );
return 0;
+err:
+ DRM_LOCK();
+ dev->irq_enabled = 0;
+#ifdef ___FreeBSD__
+ if (dev->irqrid != 0) {
+ bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid,
+ dev->irqr);
+ dev->irqrid = 0;
+ }
+#endif
+ DRM_SPINUNINIT(dev->irq_lock);
+ DRM_UNLOCK();
+ return retcode;
}
+/* XXX: This function needs to be called with the device lock held. In some
+ * cases it isn't, so far.
+ */
int DRM(irq_uninstall)( drm_device_t *dev )
{
- int irq;
+ int irq_enabled;
int irqrid;
-
- DRM_LOCK();
- irq = dev->irq;
- irqrid = dev->irqrid;
- dev->irq = 0;
- dev->irqrid = 0;
- DRM_UNLOCK();
- if ( !irq )
+ if (!dev->irq_enabled)
return DRM_ERR(EINVAL);
- DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
+ dev->irq_enabled = 0;
+ irqrid = dev->irqrid;
+ dev->irqrid = 0;
+
+ DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
DRM(driver_irq_uninstall)( dev );
@@ -157,14 +178,21 @@ int DRM(control)( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_control_t ctl;
+ int err;
DRM_COPY_FROM_USER_IOCTL( ctl, (drm_control_t *) data, sizeof(ctl) );
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 DRM_ERR(EINVAL);
+ return DRM(irq_install)(dev);
case DRM_UNINST_HANDLER:
- return DRM(irq_uninstall)( dev );
+ DRM_LOCK();
+ err = DRM(irq_uninstall)( dev );
+ DRM_UNLOCK();
+ return err;
default:
return DRM_ERR(EINVAL);
}
@@ -178,7 +206,7 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS )
struct timeval now;
int ret;
- if (!dev->irq)
+ if (!dev->irq_enabled)
return DRM_ERR(EINVAL);
DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
diff --git a/bsd/drmP.h b/bsd/drmP.h
index 4b7d737b..82a226a9 100644
--- a/bsd/drmP.h
+++ b/bsd/drmP.h
@@ -118,6 +118,8 @@ typedef struct drm_file drm_file_t;
#define DRM_MIN(a,b) ((a)<(b)?(a):(b))
#define DRM_MAX(a,b) ((a)>(b)?(a):(b))
+#define DRM_IF_VERSION(maj, min) (maj << 16 | min)
+
#define DRM_GET_PRIV_SAREA(_dev, _ctx, _map) do { \
(_map) = (_dev)->context_sareas[_ctx]; \
} while(0)
@@ -316,6 +318,7 @@ struct drm_device {
device_t device; /* Device instance from newbus */
#endif
dev_t devnode; /* Device number for mknod */
+ int if_version; /* Highest interface version set */
int flags; /* Flags to open(2) */
@@ -355,14 +358,21 @@ struct drm_device {
/* Context support */
int irq; /* Interrupt used by board */
- int irqrid; /* Interrupt used by board */
+ int irq_enabled; /* True if the irq handler is enabled */
#ifdef __FreeBSD__
+ int irqrid; /* Interrupt used by board */
struct resource *irqr; /* Resource for interrupt used by board */
#elif defined(__NetBSD__)
struct pci_attach_args pa;
pci_intr_handle_t ih;
#endif
void *irqh; /* Handle from bus_setup_intr */
+
+ int pci_domain;
+ int pci_bus;
+ int pci_slot;
+ int pci_func;
+
atomic_t context_flag; /* Context swapping flag */
int last_context; /* Last current context */
#if __FreeBSD_version >= 400005
@@ -445,7 +455,7 @@ extern void DRM(reclaim_buffers)(drm_device_t *dev, DRMFILE filp);
#if __HAVE_IRQ
/* IRQ support (drm_irq.h) */
-extern int DRM(irq_install)( drm_device_t *dev, int irq );
+extern int DRM(irq_install)(drm_device_t *dev);
extern int DRM(irq_uninstall)( drm_device_t *dev );
extern irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS );
extern void DRM(driver_irq_preinstall)( drm_device_t *dev );
@@ -494,7 +504,7 @@ extern int DRM(version)( DRM_IOCTL_ARGS );
extern int DRM(setversion)( DRM_IOCTL_ARGS );
/* Misc. IOCTL support (drm_ioctl.h) */
-extern int DRM(irq_busid)(DRM_IOCTL_ARGS);
+extern int DRM(irq_by_busid)(DRM_IOCTL_ARGS);
extern int DRM(getunique)(DRM_IOCTL_ARGS);
extern int DRM(setunique)(DRM_IOCTL_ARGS);
extern int DRM(getmap)(DRM_IOCTL_ARGS);
diff --git a/bsd/drm_drv.h b/bsd/drm_drv.h
index 0cbc1083..1083f9f9 100644
--- a/bsd/drm_drv.h
+++ b/bsd/drm_drv.h
@@ -134,7 +134,9 @@ static drm_ioctl_desc_t DRM(ioctls)[] = {
[DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 },
+#if __HAVE_IRQ
+ [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_by_busid), 0, 1 },
+#endif
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 },
@@ -477,9 +479,10 @@ static int DRM(setup)( drm_device_t *dev )
dev->lock.hw_lock = NULL;
dev->lock.lock_queue = 0;
- dev->irq = 0;
+ dev->irq_enabled = 0;
dev->context_flag = 0;
dev->last_context = 0;
+ dev->if_version = 0;
#ifdef __FreeBSD__
dev->buf_sigio = NULL;
@@ -507,7 +510,7 @@ static int DRM(takedown)( drm_device_t *dev )
DRIVER_PRETAKEDOWN();
#if __HAVE_IRQ
- if (dev->irq != 0)
+ if (dev->irq_enabled)
DRM(irq_uninstall)( dev );
#endif
@@ -644,6 +647,13 @@ static int DRM(init)( device_t nbdev )
unit = minor(dev->device.dv_unit);
#endif
+ dev->irq = pci_get_irq(dev->device);
+ /* XXX Fix domain number (alpha hoses) */
+ dev->pci_domain = 0;
+ dev->pci_bus = pci_get_bus(dev->device);
+ dev->pci_slot = pci_get_slot(dev->device);
+ dev->pci_func = pci_get_function(dev->device);
+
dev->maplist = DRM(calloc)(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
if (dev->maplist == NULL) {
retcode = ENOMEM;
diff --git a/bsd/drm_ioctl.h b/bsd/drm_ioctl.h
index 50cf937d..0952211e 100644
--- a/bsd/drm_ioctl.h
+++ b/bsd/drm_ioctl.h
@@ -32,53 +32,6 @@
#include "drmP.h"
-int DRM(irq_busid)( DRM_IOCTL_ARGS )
-{
-#ifdef __FreeBSD__
- drm_irq_busid_t id;
- devclass_t pci;
- device_t bus, dev;
- device_t *kids;
- int error, i, num_kids;
-
- DRM_COPY_FROM_USER_IOCTL( id, (drm_irq_busid_t *)data, sizeof(id) );
-
- pci = devclass_find("pci");
- if (!pci)
- return ENOENT;
- bus = devclass_get_device(pci, id.busnum);
- if (!bus)
- return ENOENT;
- error = device_get_children(bus, &kids, &num_kids);
- if (error)
- return error;
-
- dev = 0;
- for (i = 0; i < num_kids; i++) {
- dev = kids[i];
- if (pci_get_slot(dev) == id.devnum
- && pci_get_function(dev) == id.funcnum)
- break;
- }
-
- free(kids, M_TEMP);
-
- if (i != num_kids)
- id.irq = pci_get_irq(dev);
- else
- id.irq = 0;
- DRM_DEBUG("%d:%d:%d => IRQ %d\n",
- id.busnum, id.devnum, id.funcnum, id.irq);
-
- DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, id, sizeof(id) );
-
- return 0;
-#else
- /* don't support interrupt-driven drivers on Net yet */
- return ENOENT;
-#endif
-}
-
/*
* Beginning in revision 1.1 of the DRM interface, getunique will return
* a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function)
@@ -109,7 +62,8 @@ int DRM(getunique)( DRM_IOCTL_ARGS )
int DRM(setunique)( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
- drm_unique_t u;
+ drm_unique_t u;
+ int domain, bus, slot, func, ret;
if (dev->unique_len || dev->unique)
return DRM_ERR(EBUSY);
@@ -130,6 +84,21 @@ int DRM(setunique)( DRM_IOCTL_ARGS )
dev->unique[dev->unique_len] = '\0';
+ /* Return error if the busid submitted doesn't match the device's actual
+ * busid.
+ */
+ ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+ if (ret != 3)
+ return DRM_ERR(EINVAL);
+ domain = bus >> 8;
+ bus &= 0xff;
+
+ if ((domain != dev->pci_domain) ||
+ (bus != dev->pci_bus) ||
+ (slot != dev->pci_slot) ||
+ (func != dev->pci_func))
+ return DRM_ERR(EINVAL);
+
return 0;
}
@@ -146,10 +115,8 @@ DRM(set_busid)(drm_device_t *dev)
if (dev->unique == NULL)
return ENOMEM;
- /* XXX Fix domain number (alpha hoses) */
snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x",
- 0, pci_get_bus(dev->device), pci_get_slot(dev->device),
- pci_get_function(dev->device));
+ dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
return 0;
}
@@ -260,26 +227,31 @@ int DRM(getstats)( DRM_IOCTL_ARGS )
return 0;
}
+#define DRM_IF_MAJOR 1
+#define DRM_IF_MINOR 2
+
int DRM(setversion)(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_set_version_t sv;
drm_set_version_t retv;
+ int if_version;
DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof(sv));
- retv.drm_di_major = 1;
- retv.drm_di_minor = 1;
+ retv.drm_di_major = DRM_IF_MAJOR;
+ retv.drm_di_minor = DRM_IF_MINOR;
retv.drm_dd_major = DRIVER_MAJOR;
retv.drm_dd_minor = DRIVER_MINOR;
DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof(sv));
if (sv.drm_di_major != -1) {
- if (sv.drm_di_major != 1 || sv.drm_di_minor < 0)
- return EINVAL;
- if (sv.drm_di_minor > 1)
+ if (sv.drm_di_major != DRM_IF_MAJOR ||
+ sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
return EINVAL;
+ if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor);
+ dev->if_version = DRM_MAX(if_version, dev->if_version);
if (sv.drm_di_minor >= 1) {
/*
* Version 1.1 includes tying of DRM to specific device
@@ -289,12 +261,11 @@ int DRM(setversion)(DRM_IOCTL_ARGS)
}
if (sv.drm_dd_major != -1) {
- if (sv.drm_dd_major != DRIVER_MAJOR || sv.drm_dd_minor < 0)
- return EINVAL;
- if (sv.drm_dd_minor > DRIVER_MINOR)
+ if (sv.drm_dd_major != DRIVER_MAJOR ||
+ sv.drm_dd_minor < 0 || sv.drm_dd_minor > DRIVER_MINOR)
return EINVAL;
#ifdef DRIVER_SETVERSION
- DRIVER_SETVERSION(dev, sv);
+ DRIVER_SETVERSION(dev, &sv);
#endif
}
return 0;
diff --git a/bsd/drm_irq.h b/bsd/drm_irq.h
index f984118e..1de817c3 100644
--- a/bsd/drm_irq.h
+++ b/bsd/drm_irq.h
@@ -28,6 +28,29 @@
*
*/
+int DRM(irq_by_busid)( DRM_IOCTL_ARGS )
+{
+ DRM_DEVICE;
+ drm_irq_busid_t irq;
+
+ DRM_COPY_FROM_USER_IOCTL(irq, (drm_irq_busid_t *)data, sizeof(irq));
+
+ if ((irq.busnum >> 8) != dev->pci_domain ||
+ (irq.busnum & 0xff) != dev->pci_bus ||
+ irq.devnum != dev->pci_slot ||
+ irq.funcnum != dev->pci_func)
+ return EINVAL;
+
+ irq.irq = dev->irq;
+
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+ irq.busnum, irq.devnum, irq.funcnum, irq.irq);
+
+ DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, irq, sizeof(irq) );
+
+ return 0;
+}
+
#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
static irqreturn_t
DRM(irq_handler_wrap)(DRM_IRQ_ARGS)
@@ -40,22 +63,22 @@ DRM(irq_handler_wrap)(DRM_IRQ_ARGS)
}
#endif
-int DRM(irq_install)( drm_device_t *dev, int irq )
+int DRM(irq_install)(drm_device_t *dev)
{
int retcode;
- if ( irq == 0 || dev->dev_private == NULL)
+ if (dev->irq == 0 || dev->dev_private == NULL)
return DRM_ERR(EINVAL);
DRM_LOCK();
- if ( dev->irq ) {
+ if (dev->irq_enabled) {
DRM_UNLOCK();
return DRM_ERR(EBUSY);
}
- dev->irq = irq;
+ dev->irq_enabled = 1;
DRM_UNLOCK();
- DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
+ DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
dev->context_flag = 0;
@@ -68,31 +91,18 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
DRM_SPININIT(dev->irq_lock, "DRM IRQ lock");
-#if __HAVE_VBL_IRQ && 0 /* disabled */
- TAILQ_INIT( &dev->vbl_sig_list );
-#endif
-
/* Before installing handler */
DRM(driver_irq_preinstall)( dev );
/* Install handler */
- dev->irqrid = 0;
#ifdef __FreeBSD__
+ dev->irqrid = 0;
dev->irqr = bus_alloc_resource(dev->device, SYS_RES_IRQ, &dev->irqrid,
0, ~0, 1, RF_SHAREABLE);
if (!dev->irqr) {
-#elif defined(__NetBSD__)
- if (pci_intr_map(&dev->pa, &dev->ih) != 0) {
-#endif
- DRM_LOCK();
- DRM_SPINUNINIT(dev->irq_lock);
- dev->irq = 0;
- dev->irqrid = 0;
- DRM_UNLOCK();
- return ENOENT;
+ retcode = ENOENT;
+ goto err;
}
-
-#ifdef __FreeBSD__
#if __FreeBSD_version < 500000
retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY,
DRM(irq_handler), dev, &dev->irqh);
@@ -100,45 +110,56 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE,
DRM(irq_handler_wrap), dev, &dev->irqh);
#endif
- if ( retcode ) {
+ if (retcode != 0)
+ goto err;
#elif defined(__NetBSD__)
+ if (pci_intr_map(&dev->pa, &dev->ih) != 0) {
+ retcode = ENOENT;
+ goto err;
+ }
dev->irqh = pci_intr_establish(&dev->pa.pa_pc, dev->ih, IPL_TTY,
(irqreturn_t (*)(DRM_IRQ_ARGS))DRM(irq_handler), dev);
- if ( !dev->irqh ) {
-#endif
- DRM_LOCK();
-#ifdef __FreeBSD__
- bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid, dev->irqr);
-#endif
- DRM_SPINUNINIT(dev->irq_lock);
- dev->irq = 0;
- dev->irqrid = 0;
- DRM_UNLOCK();
- return retcode;
+ if (!dev->irqh) {
+ retcode = ENOENT;
+ goto err;
}
+#endif
/* After installing handler */
DRM(driver_irq_postinstall)( dev );
return 0;
+err:
+ DRM_LOCK();
+ dev->irq_enabled = 0;
+#ifdef ___FreeBSD__
+ if (dev->irqrid != 0) {
+ bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid,
+ dev->irqr);
+ dev->irqrid = 0;
+ }
+#endif
+ DRM_SPINUNINIT(dev->irq_lock);
+ DRM_UNLOCK();
+ return retcode;
}
+/* XXX: This function needs to be called with the device lock held. In some
+ * cases it isn't, so far.
+ */
int DRM(irq_uninstall)( drm_device_t *dev )
{
- int irq;
+ int irq_enabled;
int irqrid;
-
- DRM_LOCK();
- irq = dev->irq;
- irqrid = dev->irqrid;
- dev->irq = 0;
- dev->irqrid = 0;
- DRM_UNLOCK();
- if ( !irq )
+ if (!dev->irq_enabled)
return DRM_ERR(EINVAL);
- DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
+ dev->irq_enabled = 0;
+ irqrid = dev->irqrid;
+ dev->irqrid = 0;
+
+ DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
DRM(driver_irq_uninstall)( dev );
@@ -157,14 +178,21 @@ int DRM(control)( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_control_t ctl;
+ int err;
DRM_COPY_FROM_USER_IOCTL( ctl, (drm_control_t *) data, sizeof(ctl) );
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 DRM_ERR(EINVAL);
+ return DRM(irq_install)(dev);
case DRM_UNINST_HANDLER:
- return DRM(irq_uninstall)( dev );
+ DRM_LOCK();
+ err = DRM(irq_uninstall)( dev );
+ DRM_UNLOCK();
+ return err;
default:
return DRM_ERR(EINVAL);
}
@@ -178,7 +206,7 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS )
struct timeval now;
int ret;
- if (!dev->irq)
+ if (!dev->irq_enabled)
return DRM_ERR(EINVAL);
DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index f0fc64d4..1fe9c72c 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -353,6 +353,7 @@ do { \
#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist)
+#define DRM_IF_VERSION(maj, min) (maj << 16 | min)
/**
* Get the private SAREA mapping.
*
@@ -658,6 +659,7 @@ typedef struct drm_device {
dev_t device; /**< Device number for mknod */
char *devname; /**< For /proc/interrupts */
int minor; /**< Minor device number */
+ int if_version; /**< Highest interface version set */
int blocked; /**< Blocked due to VC switch? */
struct proc_dir_entry *root; /**< Root for this device's entries */
@@ -715,6 +717,7 @@ typedef struct drm_device {
/** \name Context support */
/*@{*/
int irq; /**< Interrupt used by board */
+ int irq_enabled; /**< True if irq handler is enabled */
__volatile__ long context_flag; /**< Context swapping flag */
__volatile__ long interrupt_flag; /**< Interruption handler flag */
__volatile__ long dma_flag; /**< DMA dispatch flag */
@@ -754,7 +757,12 @@ typedef struct drm_device {
#if __REALLY_HAVE_AGP
drm_agp_head_t *agp; /**< AGP data */
#endif
- struct pci_dev *pdev; /**< PCI device structure */
+
+ struct pci_dev *pdev; /**< PCI device structure */
+ int pci_domain; /**< PCI bus domain number */
+ int pci_bus; /**< PCI bus number */
+ int pci_slot; /**< PCI slot number */
+ int pci_func; /**< PCI function number */
#ifdef __alpha__
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
struct pci_controler *hose;
@@ -844,8 +852,8 @@ extern int DRM(unbind_agp)(DRM_AGP_MEM *handle);
#endif
/* Misc. IOCTL support (drm_ioctl.h) */
-extern int DRM(irq_busid)(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int DRM(irq_by_busid)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
extern int DRM(getunique)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int DRM(setunique)(struct inode *inode, struct file *filp,
@@ -950,7 +958,7 @@ extern int DRM(control)( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg );
#endif
#if __HAVE_IRQ
-extern int DRM(irq_install)( drm_device_t *dev, int irq );
+extern int DRM(irq_install)( drm_device_t *dev );
extern int DRM(irq_uninstall)( drm_device_t *dev );
extern irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS );
extern void DRM(driver_irq_preinstall)( drm_device_t *dev );
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index e472dc33..d0dceaab 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -173,7 +173,9 @@ static drm_ioctl_desc_t DRM(ioctls)[] = {
[DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 },
+#if __HAVE_IRQ
+ [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_by_busid), 0, 1 },
+#endif
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 },
@@ -334,7 +336,7 @@ static int DRM(setup)( drm_device_t *dev )
dev->queue_reserved = 0;
dev->queue_slots = 0;
dev->queuelist = NULL;
- dev->irq = 0;
+ dev->irq_enabled = 0;
dev->context_flag = 0;
dev->interrupt_flag = 0;
dev->dma_flag = 0;
@@ -342,6 +344,7 @@ static int DRM(setup)( drm_device_t *dev )
dev->last_switch = 0;
dev->last_checked = 0;
init_waitqueue_head( &dev->context_wait );
+ dev->if_version = 0;
dev->ctx_start = 0;
dev->lck_start = 0;
@@ -389,7 +392,7 @@ static int DRM(takedown)( drm_device_t *dev )
DRIVER_PRETAKEDOWN();
#if __HAVE_IRQ
- if ( dev->irq ) DRM(irq_uninstall)( dev );
+ if ( dev->irq_enabled ) DRM(irq_uninstall)( dev );
#endif
down( &dev->struct_sem );
@@ -569,10 +572,18 @@ static int DRM(probe)(struct pci_dev *pdev)
return -EPERM;
dev->device = MKDEV(DRM_MAJOR, dev->minor );
dev->name = DRIVER_NAME;
+
dev->pdev = pdev;
#ifdef __alpha__
dev->hose = pdev->sysdata;
+ dev->pci_domain = dev->hose->bus->number;
+#else
+ dev->pci_domain = 0;
#endif
+ dev->pci_bus = pdev->bus->number;
+ dev->pci_slot = PCI_SLOT(pdev->devfn);
+ dev->pci_func = PCI_FUNC(pdev->devfn);
+ dev->irq = pdev->irq;
DRIVER_PREINIT();
diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c
index ac54cae9..f6dea331 100644
--- a/linux-core/drm_ioctl.c
+++ b/linux-core/drm_ioctl.c
@@ -39,69 +39,6 @@
#include "linux/pci.h"
/**
- * 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.
- */
-int DRM(irq_busid)(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- drm_irq_busid_t p;
- struct pci_dev *dev;
-
- if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
- return -EFAULT;
-#ifdef __alpha__
- {
- int domain = p.busnum >> 8;
- p.busnum &= 0xff;
-
- /*
- * Find the hose the device is on (the domain number is the
- * hose index) and offset the bus by the root bus of that
- * hose.
- */
- for(dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
- dev;
- dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,dev)) {
- struct pci_controller *hose = dev->sysdata;
-
- if (hose->index == domain) {
- p.busnum += hose->bus->number;
- break;
- }
- }
- }
-#endif
- dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
- if (!dev) {
- DRM_ERROR("pci_find_slot failed for %d:%d:%d\n",
- p.busnum, p.devnum, p.funcnum);
- p.irq = 0;
- goto out;
- }
- if (pci_enable_device(dev) != 0) {
- DRM_ERROR("pci_enable_device failed for %d:%d:%d\n",
- p.busnum, p.devnum, p.funcnum);
- p.irq = 0;
- goto out;
- }
- p.irq = dev->irq;
- out:
- 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;
-}
-
-/**
* Get the bus id.
*
* \param inode device inode.
@@ -140,9 +77,9 @@ int DRM(getunique)(struct inode *inode, struct file *filp,
* \param arg user argument, pointing to a drm_unique structure.
* \return zero on success or a negative number on failure.
*
- * Copies the bus id from userspace into drm_device::unique, and searches for
- * the respective PCI device, updating drm_device::pdev. Deprecated in
- * interface version 1.1 and will return EBUSY when setversion has requested
+ * Copies the bus id from userspace into drm_device::unique, and verifies that
+ * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated
+ * in interface version 1.1 and will return EBUSY when setversion has requested
* version 1.1 or greater.
*/
int DRM(setunique)(struct inode *inode, struct file *filp,
@@ -151,6 +88,7 @@ int DRM(setunique)(struct inode *inode, struct file *filp,
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
drm_unique_t u;
+ int domain, bus, slot, func, ret;
if (dev->unique_len || dev->unique) return -EBUSY;
@@ -168,55 +106,25 @@ int DRM(setunique)(struct inode *inode, struct file *filp,
dev->devname = DRM(alloc)(strlen(dev->name) + strlen(dev->unique) + 2,
DRM_MEM_DRIVER);
- if(!dev->devname) {
- DRM(free)(dev->devname, sizeof(*dev->devname), DRM_MEM_DRIVER);
+ if (!dev->devname)
return -ENOMEM;
- }
- sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
- do {
- struct pci_dev *pci_dev;
- int domain, b, d, f;
- char *p;
-
- for(p = dev->unique; p && *p && *p != ':'; p++);
- if (!p || !*p) break;
- b = (int)simple_strtoul(p+1, &p, 10);
- if (*p != ':') break;
- d = (int)simple_strtoul(p+1, &p, 10);
- if (*p != ':') break;
- f = (int)simple_strtoul(p+1, &p, 10);
- if (*p) break;
-
- domain = b >> 8;
- b &= 0xff;
-
-#ifdef __alpha__
- /*
- * Find the hose the device is on (the domain number is the
- * hose index) and offset the bus by the root bus of that
- * hose.
- */
- for(pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
- pci_dev;
- pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,pci_dev)) {
- struct pci_controller *hose = pci_dev->sysdata;
-
- if (hose->index == domain) {
- b += hose->bus->number;
- break;
- }
- }
-#endif
+ sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
- pci_dev = pci_find_slot(b, PCI_DEVFN(d,f));
- if (pci_dev) {
- dev->pdev = pci_dev;
-#ifdef __alpha__
- dev->hose = pci_dev->sysdata;
-#endif
- }
- } while(0);
+ /* Return error if the busid submitted doesn't match the device's actual
+ * busid.
+ */
+ ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+ if (ret != 3)
+ return DRM_ERR(EINVAL);
+ domain = bus >> 8;
+ bus &= 0xff;
+
+ if ((domain != dev->pci_domain) ||
+ (bus != dev->pci_bus) ||
+ (slot != dev->pci_slot) ||
+ (func != dev->pci_func))
+ return -EINVAL;
return 0;
}
@@ -232,21 +140,8 @@ DRM(set_busid)(drm_device_t *dev)
if (dev->unique == NULL)
return ENOMEM;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)
- snprintf(dev->unique, dev->unique_len, "pci:%s", pci_name(dev->pdev));
-#else
- {
- int domain = 0;
-#ifdef __alpha__
- struct pci_controller *hose = pci_dev->sysdata;
-
- domain = hose->bus->number;
-#endif
- snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
- domain, dev->pdev->bus->number,
- PCI_SLOT(dev->pdev->devfn), PCI_FUNC(dev->pdev->devfn));
- }
-#endif
+ snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
+ dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
return 0;
}
@@ -398,26 +293,31 @@ int DRM(getstats)( struct inode *inode, struct file *filp,
return 0;
}
+#define DRM_IF_MAJOR 1
+#define DRM_IF_MINOR 2
+
int DRM(setversion)(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_set_version_t sv;
drm_set_version_t retv;
+ int if_version;
DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof(sv));
- retv.drm_di_major = 1;
- retv.drm_di_minor = 1;
+ retv.drm_di_major = DRM_IF_MAJOR;
+ retv.drm_di_minor = DRM_IF_MINOR;
retv.drm_dd_major = DRIVER_MAJOR;
retv.drm_dd_minor = DRIVER_MINOR;
-
+
DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof(sv));
if (sv.drm_di_major != -1) {
- if (sv.drm_di_major != 1 || sv.drm_di_minor < 0)
- return EINVAL;
- if (sv.drm_di_minor > 1)
+ if (sv.drm_di_major != DRM_IF_MAJOR ||
+ sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
return EINVAL;
+ if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor);
+ dev->if_version = DRM_MAX(if_version, dev->if_version);
if (sv.drm_di_minor >= 1) {
/*
* Version 1.1 includes tying of DRM to specific device
@@ -427,13 +327,13 @@ int DRM(setversion)(DRM_IOCTL_ARGS)
}
if (sv.drm_dd_major != -1) {
- if (sv.drm_dd_major != DRIVER_MAJOR || sv.drm_dd_minor < 0)
- return EINVAL;
- if (sv.drm_dd_minor > DRIVER_MINOR)
+ if (sv.drm_dd_major != DRIVER_MAJOR ||
+ sv.drm_dd_minor < 0 || sv.drm_dd_minor > DRIVER_MINOR)
return EINVAL;
#ifdef DRIVER_SETVERSION
- DRIVER_SETVERSION(dev, sv);
+ DRIVER_SETVERSION(dev, &sv);
#endif
}
return 0;
}
+
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:
diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c
index 1eeb4a3f..b46c3a39 100644
--- a/linux-core/i810_dma.c
+++ b/linux-core/i810_dma.c
@@ -244,7 +244,7 @@ int i810_dma_cleanup(drm_device_t *dev)
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if (dev->irq) DRM(irq_uninstall)(dev);
+ if (dev->irq_enabled) DRM(irq_uninstall)(dev);
#endif
if (dev->dev_private) {
diff --git a/linux-core/i830_dma.c b/linux-core/i830_dma.c
index 422f3ad5..626f84be 100644
--- a/linux-core/i830_dma.c
+++ b/linux-core/i830_dma.c
@@ -243,7 +243,7 @@ int i830_dma_cleanup(drm_device_t *dev)
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if (dev->irq) DRM(irq_uninstall)(dev);
+ if (dev->irq_enabled) DRM(irq_uninstall)(dev);
#endif
if (dev->dev_private) {
@@ -1546,7 +1546,7 @@ int i830_getparam( struct inode *inode, struct file *filp, unsigned int cmd,
switch( param.param ) {
case I830_PARAM_IRQ_ACTIVE:
- value = dev->irq ? 1 : 0;
+ value = dev->irq_enabled;
break;
default:
return -EINVAL;
diff --git a/linux/drmP.h b/linux/drmP.h
index f0fc64d4..1fe9c72c 100644
--- a/linux/drmP.h
+++ b/linux/drmP.h
@@ -353,6 +353,7 @@ do { \
#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist)
+#define DRM_IF_VERSION(maj, min) (maj << 16 | min)
/**
* Get the private SAREA mapping.
*
@@ -658,6 +659,7 @@ typedef struct drm_device {
dev_t device; /**< Device number for mknod */
char *devname; /**< For /proc/interrupts */
int minor; /**< Minor device number */
+ int if_version; /**< Highest interface version set */
int blocked; /**< Blocked due to VC switch? */
struct proc_dir_entry *root; /**< Root for this device's entries */
@@ -715,6 +717,7 @@ typedef struct drm_device {
/** \name Context support */
/*@{*/
int irq; /**< Interrupt used by board */
+ int irq_enabled; /**< True if irq handler is enabled */
__volatile__ long context_flag; /**< Context swapping flag */
__volatile__ long interrupt_flag; /**< Interruption handler flag */
__volatile__ long dma_flag; /**< DMA dispatch flag */
@@ -754,7 +757,12 @@ typedef struct drm_device {
#if __REALLY_HAVE_AGP
drm_agp_head_t *agp; /**< AGP data */
#endif
- struct pci_dev *pdev; /**< PCI device structure */
+
+ struct pci_dev *pdev; /**< PCI device structure */
+ int pci_domain; /**< PCI bus domain number */
+ int pci_bus; /**< PCI bus number */
+ int pci_slot; /**< PCI slot number */
+ int pci_func; /**< PCI function number */
#ifdef __alpha__
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
struct pci_controler *hose;
@@ -844,8 +852,8 @@ extern int DRM(unbind_agp)(DRM_AGP_MEM *handle);
#endif
/* Misc. IOCTL support (drm_ioctl.h) */
-extern int DRM(irq_busid)(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int DRM(irq_by_busid)(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
extern int DRM(getunique)(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int DRM(setunique)(struct inode *inode, struct file *filp,
@@ -950,7 +958,7 @@ extern int DRM(control)( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg );
#endif
#if __HAVE_IRQ
-extern int DRM(irq_install)( drm_device_t *dev, int irq );
+extern int DRM(irq_install)( drm_device_t *dev );
extern int DRM(irq_uninstall)( drm_device_t *dev );
extern irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS );
extern void DRM(driver_irq_preinstall)( drm_device_t *dev );
diff --git a/linux/drm_drv.h b/linux/drm_drv.h
index e472dc33..d0dceaab 100644
--- a/linux/drm_drv.h
+++ b/linux/drm_drv.h
@@ -173,7 +173,9 @@ static drm_ioctl_desc_t DRM(ioctls)[] = {
[DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 },
- [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 },
+#if __HAVE_IRQ
+ [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_by_busid), 0, 1 },
+#endif
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 },
@@ -334,7 +336,7 @@ static int DRM(setup)( drm_device_t *dev )
dev->queue_reserved = 0;
dev->queue_slots = 0;
dev->queuelist = NULL;
- dev->irq = 0;
+ dev->irq_enabled = 0;
dev->context_flag = 0;
dev->interrupt_flag = 0;
dev->dma_flag = 0;
@@ -342,6 +344,7 @@ static int DRM(setup)( drm_device_t *dev )
dev->last_switch = 0;
dev->last_checked = 0;
init_waitqueue_head( &dev->context_wait );
+ dev->if_version = 0;
dev->ctx_start = 0;
dev->lck_start = 0;
@@ -389,7 +392,7 @@ static int DRM(takedown)( drm_device_t *dev )
DRIVER_PRETAKEDOWN();
#if __HAVE_IRQ
- if ( dev->irq ) DRM(irq_uninstall)( dev );
+ if ( dev->irq_enabled ) DRM(irq_uninstall)( dev );
#endif
down( &dev->struct_sem );
@@ -569,10 +572,18 @@ static int DRM(probe)(struct pci_dev *pdev)
return -EPERM;
dev->device = MKDEV(DRM_MAJOR, dev->minor );
dev->name = DRIVER_NAME;
+
dev->pdev = pdev;
#ifdef __alpha__
dev->hose = pdev->sysdata;
+ dev->pci_domain = dev->hose->bus->number;
+#else
+ dev->pci_domain = 0;
#endif
+ dev->pci_bus = pdev->bus->number;
+ dev->pci_slot = PCI_SLOT(pdev->devfn);
+ dev->pci_func = PCI_FUNC(pdev->devfn);
+ dev->irq = pdev->irq;
DRIVER_PREINIT();
diff --git a/linux/drm_ioctl.h b/linux/drm_ioctl.h
index ac54cae9..f6dea331 100644
--- a/linux/drm_ioctl.h
+++ b/linux/drm_ioctl.h
@@ -39,69 +39,6 @@
#include "linux/pci.h"
/**
- * 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.
- */
-int DRM(irq_busid)(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- drm_irq_busid_t p;
- struct pci_dev *dev;
-
- if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
- return -EFAULT;
-#ifdef __alpha__
- {
- int domain = p.busnum >> 8;
- p.busnum &= 0xff;
-
- /*
- * Find the hose the device is on (the domain number is the
- * hose index) and offset the bus by the root bus of that
- * hose.
- */
- for(dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
- dev;
- dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,dev)) {
- struct pci_controller *hose = dev->sysdata;
-
- if (hose->index == domain) {
- p.busnum += hose->bus->number;
- break;
- }
- }
- }
-#endif
- dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
- if (!dev) {
- DRM_ERROR("pci_find_slot failed for %d:%d:%d\n",
- p.busnum, p.devnum, p.funcnum);
- p.irq = 0;
- goto out;
- }
- if (pci_enable_device(dev) != 0) {
- DRM_ERROR("pci_enable_device failed for %d:%d:%d\n",
- p.busnum, p.devnum, p.funcnum);
- p.irq = 0;
- goto out;
- }
- p.irq = dev->irq;
- out:
- 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;
-}
-
-/**
* Get the bus id.
*
* \param inode device inode.
@@ -140,9 +77,9 @@ int DRM(getunique)(struct inode *inode, struct file *filp,
* \param arg user argument, pointing to a drm_unique structure.
* \return zero on success or a negative number on failure.
*
- * Copies the bus id from userspace into drm_device::unique, and searches for
- * the respective PCI device, updating drm_device::pdev. Deprecated in
- * interface version 1.1 and will return EBUSY when setversion has requested
+ * Copies the bus id from userspace into drm_device::unique, and verifies that
+ * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated
+ * in interface version 1.1 and will return EBUSY when setversion has requested
* version 1.1 or greater.
*/
int DRM(setunique)(struct inode *inode, struct file *filp,
@@ -151,6 +88,7 @@ int DRM(setunique)(struct inode *inode, struct file *filp,
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
drm_unique_t u;
+ int domain, bus, slot, func, ret;
if (dev->unique_len || dev->unique) return -EBUSY;
@@ -168,55 +106,25 @@ int DRM(setunique)(struct inode *inode, struct file *filp,
dev->devname = DRM(alloc)(strlen(dev->name) + strlen(dev->unique) + 2,
DRM_MEM_DRIVER);
- if(!dev->devname) {
- DRM(free)(dev->devname, sizeof(*dev->devname), DRM_MEM_DRIVER);
+ if (!dev->devname)
return -ENOMEM;
- }
- sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
- do {
- struct pci_dev *pci_dev;
- int domain, b, d, f;
- char *p;
-
- for(p = dev->unique; p && *p && *p != ':'; p++);
- if (!p || !*p) break;
- b = (int)simple_strtoul(p+1, &p, 10);
- if (*p != ':') break;
- d = (int)simple_strtoul(p+1, &p, 10);
- if (*p != ':') break;
- f = (int)simple_strtoul(p+1, &p, 10);
- if (*p) break;
-
- domain = b >> 8;
- b &= 0xff;
-
-#ifdef __alpha__
- /*
- * Find the hose the device is on (the domain number is the
- * hose index) and offset the bus by the root bus of that
- * hose.
- */
- for(pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL);
- pci_dev;
- pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,pci_dev)) {
- struct pci_controller *hose = pci_dev->sysdata;
-
- if (hose->index == domain) {
- b += hose->bus->number;
- break;
- }
- }
-#endif
+ sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
- pci_dev = pci_find_slot(b, PCI_DEVFN(d,f));
- if (pci_dev) {
- dev->pdev = pci_dev;
-#ifdef __alpha__
- dev->hose = pci_dev->sysdata;
-#endif
- }
- } while(0);
+ /* Return error if the busid submitted doesn't match the device's actual
+ * busid.
+ */
+ ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+ if (ret != 3)
+ return DRM_ERR(EINVAL);
+ domain = bus >> 8;
+ bus &= 0xff;
+
+ if ((domain != dev->pci_domain) ||
+ (bus != dev->pci_bus) ||
+ (slot != dev->pci_slot) ||
+ (func != dev->pci_func))
+ return -EINVAL;
return 0;
}
@@ -232,21 +140,8 @@ DRM(set_busid)(drm_device_t *dev)
if (dev->unique == NULL)
return ENOMEM;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)
- snprintf(dev->unique, dev->unique_len, "pci:%s", pci_name(dev->pdev));
-#else
- {
- int domain = 0;
-#ifdef __alpha__
- struct pci_controller *hose = pci_dev->sysdata;
-
- domain = hose->bus->number;
-#endif
- snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
- domain, dev->pdev->bus->number,
- PCI_SLOT(dev->pdev->devfn), PCI_FUNC(dev->pdev->devfn));
- }
-#endif
+ snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
+ dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
return 0;
}
@@ -398,26 +293,31 @@ int DRM(getstats)( struct inode *inode, struct file *filp,
return 0;
}
+#define DRM_IF_MAJOR 1
+#define DRM_IF_MINOR 2
+
int DRM(setversion)(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_set_version_t sv;
drm_set_version_t retv;
+ int if_version;
DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof(sv));
- retv.drm_di_major = 1;
- retv.drm_di_minor = 1;
+ retv.drm_di_major = DRM_IF_MAJOR;
+ retv.drm_di_minor = DRM_IF_MINOR;
retv.drm_dd_major = DRIVER_MAJOR;
retv.drm_dd_minor = DRIVER_MINOR;
-
+
DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof(sv));
if (sv.drm_di_major != -1) {
- if (sv.drm_di_major != 1 || sv.drm_di_minor < 0)
- return EINVAL;
- if (sv.drm_di_minor > 1)
+ if (sv.drm_di_major != DRM_IF_MAJOR ||
+ sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
return EINVAL;
+ if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor);
+ dev->if_version = DRM_MAX(if_version, dev->if_version);
if (sv.drm_di_minor >= 1) {
/*
* Version 1.1 includes tying of DRM to specific device
@@ -427,13 +327,13 @@ int DRM(setversion)(DRM_IOCTL_ARGS)
}
if (sv.drm_dd_major != -1) {
- if (sv.drm_dd_major != DRIVER_MAJOR || sv.drm_dd_minor < 0)
- return EINVAL;
- if (sv.drm_dd_minor > DRIVER_MINOR)
+ if (sv.drm_dd_major != DRIVER_MAJOR ||
+ sv.drm_dd_minor < 0 || sv.drm_dd_minor > DRIVER_MINOR)
return EINVAL;
#ifdef DRIVER_SETVERSION
- DRIVER_SETVERSION(dev, sv);
+ DRIVER_SETVERSION(dev, &sv);
#endif
}
return 0;
}
+
diff --git a/linux/drm_irq.h b/linux/drm_irq.h
index 322e5717..837e6951 100644
--- a/linux/drm_irq.h
+++ b/linux/drm_irq.h
@@ -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:
diff --git a/linux/gamma_dma.c b/linux/gamma_dma.c
index bae19bbe..41592a5d 100644
--- a/linux/gamma_dma.c
+++ b/linux/gamma_dma.c
@@ -652,7 +652,7 @@ int gamma_do_cleanup_dma( drm_device_t *dev )
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if ( dev->irq ) DRM(irq_uninstall)(dev);
+ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
#endif
if ( dev->dev_private ) {
diff --git a/linux/i810_dma.c b/linux/i810_dma.c
index 1eeb4a3f..b46c3a39 100644
--- a/linux/i810_dma.c
+++ b/linux/i810_dma.c
@@ -244,7 +244,7 @@ int i810_dma_cleanup(drm_device_t *dev)
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if (dev->irq) DRM(irq_uninstall)(dev);
+ if (dev->irq_enabled) DRM(irq_uninstall)(dev);
#endif
if (dev->dev_private) {
diff --git a/linux/i830_dma.c b/linux/i830_dma.c
index 422f3ad5..626f84be 100644
--- a/linux/i830_dma.c
+++ b/linux/i830_dma.c
@@ -243,7 +243,7 @@ int i830_dma_cleanup(drm_device_t *dev)
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if (dev->irq) DRM(irq_uninstall)(dev);
+ if (dev->irq_enabled) DRM(irq_uninstall)(dev);
#endif
if (dev->dev_private) {
@@ -1546,7 +1546,7 @@ int i830_getparam( struct inode *inode, struct file *filp, unsigned int cmd,
switch( param.param ) {
case I830_PARAM_IRQ_ACTIVE:
- value = dev->irq ? 1 : 0;
+ value = dev->irq_enabled;
break;
default:
return -EINVAL;
diff --git a/shared-core/mga_dma.c b/shared-core/mga_dma.c
index f2d92f15..19bc9e32 100644
--- a/shared-core/mga_dma.c
+++ b/shared-core/mga_dma.c
@@ -644,7 +644,7 @@ int mga_do_cleanup_dma( drm_device_t *dev )
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if ( dev->irq ) DRM(irq_uninstall)(dev);
+ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
#endif
if ( dev->dev_private ) {
diff --git a/shared-core/r128_cce.c b/shared-core/r128_cce.c
index fdf220bd..abf05c17 100644
--- a/shared-core/r128_cce.c
+++ b/shared-core/r128_cce.c
@@ -599,7 +599,7 @@ int r128_do_cleanup_cce( drm_device_t *dev )
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if ( dev->irq ) DRM(irq_uninstall)(dev);
+ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
#endif
if ( dev->dev_private ) {
diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c
index 87aef010..4cacef5c 100644
--- a/shared-core/radeon_cp.c
+++ b/shared-core/radeon_cp.c
@@ -1287,7 +1287,7 @@ int radeon_do_cleanup_cp( drm_device_t *dev )
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if ( dev->irq ) DRM(irq_uninstall)(dev);
+ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
#endif
if ( dev->dev_private ) {
diff --git a/shared/mga_dma.c b/shared/mga_dma.c
index f2d92f15..19bc9e32 100644
--- a/shared/mga_dma.c
+++ b/shared/mga_dma.c
@@ -644,7 +644,7 @@ int mga_do_cleanup_dma( drm_device_t *dev )
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if ( dev->irq ) DRM(irq_uninstall)(dev);
+ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
#endif
if ( dev->dev_private ) {
diff --git a/shared/r128_cce.c b/shared/r128_cce.c
index fdf220bd..abf05c17 100644
--- a/shared/r128_cce.c
+++ b/shared/r128_cce.c
@@ -599,7 +599,7 @@ int r128_do_cleanup_cce( drm_device_t *dev )
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if ( dev->irq ) DRM(irq_uninstall)(dev);
+ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
#endif
if ( dev->dev_private ) {
diff --git a/shared/radeon_cp.c b/shared/radeon_cp.c
index 87aef010..4cacef5c 100644
--- a/shared/radeon_cp.c
+++ b/shared/radeon_cp.c
@@ -1287,7 +1287,7 @@ int radeon_do_cleanup_cp( drm_device_t *dev )
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
- if ( dev->irq ) DRM(irq_uninstall)(dev);
+ if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
#endif
if ( dev->dev_private ) {