diff options
| -rw-r--r-- | bsd-core/drmP.h | 16 | ||||
| -rw-r--r-- | bsd-core/drm_drv.c | 16 | ||||
| -rw-r--r-- | bsd-core/drm_ioctl.c | 91 | ||||
| -rw-r--r-- | bsd-core/drm_irq.c | 120 | ||||
| -rw-r--r-- | bsd/drmP.h | 16 | ||||
| -rw-r--r-- | bsd/drm_drv.h | 16 | ||||
| -rw-r--r-- | bsd/drm_ioctl.h | 91 | ||||
| -rw-r--r-- | bsd/drm_irq.h | 120 | ||||
| -rw-r--r-- | linux-core/drmP.h | 16 | ||||
| -rw-r--r-- | linux-core/drm_drv.c | 17 | ||||
| -rw-r--r-- | linux-core/drm_ioctl.c | 174 | ||||
| -rw-r--r-- | linux-core/drm_irq.c | 69 | ||||
| -rw-r--r-- | linux-core/i810_dma.c | 2 | ||||
| -rw-r--r-- | linux-core/i830_dma.c | 4 | ||||
| -rw-r--r-- | linux/drmP.h | 16 | ||||
| -rw-r--r-- | linux/drm_drv.h | 17 | ||||
| -rw-r--r-- | linux/drm_ioctl.h | 174 | ||||
| -rw-r--r-- | linux/drm_irq.h | 69 | ||||
| -rw-r--r-- | linux/gamma_dma.c | 2 | ||||
| -rw-r--r-- | linux/i810_dma.c | 2 | ||||
| -rw-r--r-- | linux/i830_dma.c | 4 | ||||
| -rw-r--r-- | shared-core/mga_dma.c | 2 | ||||
| -rw-r--r-- | shared-core/r128_cce.c | 2 | ||||
| -rw-r--r-- | shared-core/radeon_cp.c | 2 | ||||
| -rw-r--r-- | shared/mga_dma.c | 2 | ||||
| -rw-r--r-- | shared/r128_cce.c | 2 | ||||
| -rw-r--r-- | shared/radeon_cp.c | 2 | 
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, @@ -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 ) {  | 
