New version of dyn-minor patch. Basically the same code but I added
two new entry points for get/put of secondary minor numbers for
multi-head cards. I tested those with code that is not in the patch,
it will come in a later one.

Dave, if this looks ok can we check it in? My goal is not to change
any DRM behavior with this patch. It's starting to get harder keeping
this patch in sync with the tree since I'm fixing the same bugs in
both pieces of code and that generates lots of merge conflicts.

Please give it a little testing to make sure I did everything ok. I'm
getting lazy about retesting it after every merge.

-- 
Jon Smirl
[EMAIL PROTECTED]
===== linux/drmP.h 1.11 vs edited =====
--- 1.11/linux/drmP.h	Sun Sep  5 21:22:06 2004
+++ edited/linux/drmP.h	Sun Sep 12 19:42:43 2004
@@ -56,6 +56,7 @@
 #include <linux/smp_lock.h>	/* For (un)lock_kernel */
 #include <linux/mm.h>
 #include <linux/pagemap.h>
+#include <linux/cdev.h>
 #if defined(__alpha__) || defined(__powerpc__)
 #include <asm/pgtable.h> /* For pte_wrprotect */
 #endif
@@ -554,7 +555,6 @@
 	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 */
 
 	/** \name Locks */
 	/[EMAIL PROTECTED]/
@@ -673,12 +673,33 @@
 	sigset_t          sigmask;
 	
 	int               need_reset;	/**< secondary device needing reset */
+
+	struct file_operations *fops;	/**< file operations */
+
 	struct drm_driver_fn fn_tbl;
 	drm_local_map_t   *agp_buffer_map;
 	int               dev_priv_size;
 	u32               driver_features;
 } drm_device_t;
 
+typedef struct drm_minor {
+	enum {
+		DRM_MINOR_FREE = 0,
+		DRM_MINOR_PRIMARY,
+		DRM_MINOR_SECONDARY,
+	} class;
+	drm_device_t *dev;
+	struct proc_dir_entry  *dev_root; /**< proc directory entry */
+} drm_minor_t;
+
+typedef struct drm_global {
+	unsigned int cards_limit;
+	drm_minor_t *minors;
+	struct class_simple *drm_class;
+	struct proc_dir_entry *proc_root;
+	struct cdev drm_cdev;
+} drm_global_t;
+
 static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature)
 {
 	return ((dev->driver_features & feature) ? 1 : 0);
@@ -904,10 +925,11 @@
 extern int            DRM(agp_unbind_memory)(DRM_AGP_MEM *handle);
 
 				/* Stub support (drm_stub.h) */
-int                   DRM(stub_register)(const char *name,
-					 struct file_operations *fops,
-					 drm_device_t *dev);
-int                   DRM(stub_unregister)(int minor);
+extern int 	      DRM(probe)(struct pci_dev *pdev, const struct pci_device_id *ent);
+extern int 	      DRM(put_minor)(drm_device_t *dev);
+extern int	      DRM(get_secondary_minor)(drm_device_t *dev, drm_minor_t **sec_minor);
+extern int	      DRM(put_secondary_minor)(drm_minor_t *sec_minor);
+extern drm_global_t   *DRM(global);
 
 				/* Proc support (drm_proc.h) */
 extern int 	      DRM(proc_init)(drm_device_t *dev,
===== linux/drm_drv.h 1.16 vs edited =====
--- 1.16/linux/drm_drv.h	Sun Sep 12 15:34:31 2004
+++ edited/linux/drm_drv.h	Sun Sep 12 19:42:43 2004
@@ -62,17 +62,6 @@
 
 static void __exit drm_cleanup( drm_device_t *dev );
 
-/** Stub information */
-struct drm_stub_info {
-	int (*info_register)(const char *name, struct file_operations *fops,
-			     drm_device_t *dev);
-	int (*info_unregister)(int minor);
-	struct class_simple *drm_class;
-	int *info_count;
-	struct proc_dir_entry *proc_root;
-};
-extern struct drm_stub_info DRM(stub_info);
-
 #ifndef MODULE
 /** Use an additional macro to avoid preprocessor troubles */
 #define DRM_OPTIONS_FUNC DRM(options)
@@ -91,9 +80,6 @@
 #undef DRM_OPTIONS_FUNC
 #endif
 
-#define MAX_DEVICES 4
-drm_device_t            DRM(device)[MAX_DEVICES];
-int DRM(numdevs) = 0;
 int DRM(fb_loaded) = 0;
 
 struct file_operations	DRM(fops) = {
@@ -176,15 +162,6 @@
 
 #define DRIVER_IOCTL_COUNT	DRM_ARRAY_SIZE( DRM(ioctls) )
 
-#ifdef MODULE
-static char *drm_opts = NULL;
-#endif
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_PARM( drm_opts, "s" );
-MODULE_LICENSE("GPL and additional rights");
-
 static int DRM(setup)( drm_device_t *dev )
 {
 	int i;
@@ -453,37 +430,19 @@
 	DRM(PCI_IDS)
 };
 
-static int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+int DRM(fill_in_dev)(drm_device_t *dev, struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	drm_device_t *dev;
 	int retcode;
 
-	DRM_DEBUG( "\n" );
-
-	if (DRM(numdevs) >= MAX_DEVICES)
-		return -ENODEV;
-
-	dev = &(DRM(device)[DRM(numdevs)]);
-	memset( (void *)dev, 0, sizeof(*dev) );
 	dev->count_lock = SPIN_LOCK_UNLOCKED;
 	init_timer( &dev->timer );
 	sema_init( &dev->struct_sem, 1 );
 	sema_init( &dev->ctxlist_sem, 1 );
 
-	dev->maplist = DRM(alloc)(sizeof(*dev->maplist), DRM_MEM_MAPS);
-	if(dev->maplist == NULL) 
-		return -ENOMEM;
-	memset(dev->maplist, 0, sizeof(*dev->maplist));
-	INIT_LIST_HEAD(&dev->maplist->head);
-
-	if (DRM(fb_loaded)==0) {
-		pci_set_drvdata(pdev, dev);
-		pci_request_regions(pdev, DRIVER_NAME);
-		pci_enable_device(pdev);
-	}
-
 	dev->name   = DRIVER_NAME;
+
 	dev->pdev   = pdev;
+
 #ifdef __alpha__
 	dev->hose   = pdev->sysdata;
 	dev->pci_domain = dev->hose->bus->number;
@@ -495,6 +454,10 @@
 	dev->pci_func = PCI_FUNC(pdev->devfn);
 	dev->irq = pdev->irq;
 
+	dev->maplist = DRM(calloc)(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
+	if(dev->maplist == NULL) return -ENOMEM;
+	INIT_LIST_HEAD(&dev->maplist->head);
+
 	/* dev_priv_size can be changed by a driver in driver_register_fns */
 	dev->dev_priv_size = sizeof(u32);
 	
@@ -504,14 +467,14 @@
 	
 	if (dev->fn_tbl.preinit)
 		if ((retcode = dev->fn_tbl.preinit(dev, ent->driver_data)))
-			goto error_out;
+			goto error_out_unreg;
 
 	if (drm_core_has_AGP(dev)) {
 		dev->agp = DRM(agp_init)();
 		if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && (dev->agp == NULL)) {
 			DRM_ERROR( "Cannot initialize the agpgart module.\n" );
 			retcode = -EINVAL;
-			goto error_out;
+			goto error_out_unreg;
 		}
 		
 
@@ -527,18 +490,10 @@
 	retcode = DRM(ctxbitmap_init)( dev );
 	if( retcode ) {
 	  DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
-	  goto error_out;
+	  goto error_out_unreg;
 	}
 
-	if ((dev->minor = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
-	{
-		retcode = -EPERM;
-		goto error_out;
-	}
-			
 	dev->device = MKDEV(DRM_MAJOR, dev->minor );
-	
-	DRM(numdevs)++; /* no errors, mark it reserved */
 
 	DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n",
 		DRIVER_NAME,
@@ -558,14 +513,7 @@
 	return 0;
 
  error_out_unreg:
-	DRM(stub_unregister)(dev->minor);
 	DRM(takedown)(dev);
- error_out:
-	if (DRM(fb_loaded)==0) {
-		pci_set_drvdata(pdev, NULL);
-		pci_release_regions(pdev);
-		pci_disable_device(pdev);
-	}
 	return retcode;
 }
 
@@ -574,17 +522,23 @@
 	drm_device_t *dev = pci_get_drvdata(pdev);
 	
 	pci_set_drvdata(pdev, NULL);
-	drm_cleanup(dev);
 	pci_release_regions(pdev);
+	if (dev)
+		drm_cleanup(dev);
 }
 
 static struct pci_driver drm_driver = {
 	.name          = DRIVER_NAME,
 	.id_table      = DRM(pciidlist),
-	.probe         = drm_probe,
+	.probe         = DRM(probe),
 	.remove        = __devexit_p(drm_cleanup_pci),
 };
 
+#ifdef MODULE
+static char *drm_opts = NULL;
+#endif
+MODULE_PARM( drm_opts, "s" );
+
 /**
  * Module initialization. Called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported).
@@ -641,7 +595,7 @@
 			/* pass back in pdev to account for multiple identical cards */
 			while ((pdev = pci_get_subsys(pid->vendor, pid->device, pid->subvendor, pid->subdevice, pdev))) {
 				/* stealth mode requires a manual probe */
-				drm_probe(pdev, &DRM(pciidlist[i]));
+				DRM(probe)(pdev, &DRM(pciidlist[i]));
 			}
 		}
 		DRM_INFO("Used old pci detect: framebuffer loaded\n");
@@ -709,13 +663,6 @@
 	if (DRM(fb_loaded)==0)
 		pci_disable_device(dev->pdev);
 
-	DRM(numdevs)--;
-	if ( DRM(stub_unregister)(dev->minor) ) {
-		DRM_ERROR( "Cannot unload module\n" );
-	} else {
-		DRM_DEBUG( "minor %d unregistered\n", dev->minor);
-	}
-
 	DRM(ctxbitmap_cleanup)( dev );
 
 	if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && dev->agp && dev->agp->agp_mtrr >= 0) {
@@ -733,25 +680,33 @@
 	}
 	if (dev->fn_tbl.postcleanup)
 		dev->fn_tbl.postcleanup(dev);
+
+	if ( DRM(put_minor)(dev) )
+		DRM_ERROR( "Cannot unload module\n" );
 }
 
 static void __exit drm_exit (void)
 {
+	int i;
+	drm_device_t *dev;
+	drm_minor_t *minor;
+	
 	DRM_DEBUG( "\n" );
-	if (DRM(fb_loaded)==1)
-	{
-		int i;
-		drm_device_t *dev;
-
-		for (i = DRM(numdevs) - 1; i >= 0; i--) {
-			dev = &(DRM(device)[i]);
-			/* release the pci driver */
-			if (dev->pdev)
-				pci_dev_put(dev->pdev);
-			drm_cleanup(dev);
+	if (DRM(fb_loaded)) {
+		if (DRM(global)) {
+			for (i = 0; i < DRM(global)->cards_limit; i++) {
+				minor = &DRM(global)->minors[i];
+				dev = minor->dev;
+				DRM_DEBUG("fb loaded release minor %d\n", dev->minor);
+				if ((minor->class == DRM_MINOR_PRIMARY) && (dev->fops == &DRM(fops))) {
+					/* release the pci driver */
+					if (dev->pdev)
+						pci_dev_put(dev->pdev);
+					drm_cleanup(dev);
+				}
+			}
 		}
-	}
-	else
+	} else
 		pci_unregister_driver(&drm_driver);
 	DRM_INFO( "Module unloaded\n" );
 }
@@ -818,18 +773,15 @@
 int DRM(open)( struct inode *inode, struct file *filp )
 {
 	drm_device_t *dev = NULL;
+	int minor = iminor(inode);
 	int retcode = 0;
-	int i;
 
-	for (i = 0; i < DRM(numdevs); i++) {
-		if (iminor(inode) == DRM(device)[i].minor) {
-			dev = &(DRM(device)[i]);
-			break;
-		}
-	}
-	if (!dev) {
+	if (!((minor >= 0) && (minor < DRM(global)->cards_limit)))
+		return -ENODEV;
+		
+	dev = DRM(global)->minors[minor].dev;
+	if (!dev)
 		return -ENODEV;
-	}
 
 	retcode = DRM(open_helper)( inode, filp, dev );
 	if ( !retcode ) {
===== linux/drm_stub.h 1.11 vs edited =====
--- 1.11/linux/drm_stub.h	Fri Aug 27 18:33:53 2004
+++ edited/linux/drm_stub.h	Sun Sep 12 19:42:44 2004
@@ -33,14 +33,18 @@
 
 #include "drmP.h"
 
-#define DRM_STUB_MAXCARDS 16	/* Enough for one machine */
+static unsigned int cards_limit = 16;	/* Enough for one machine */
+static unsigned int debug = 0;		/* 1 to enable debug output */
 
-/** Stub list. One for each minor. */
-static struct drm_stub_list {
-	const char             *name;
-	struct file_operations *fops;	/**< file operations */
-	struct proc_dir_entry  *dev_root;	/**< proc directory entry */
-} *DRM(stub_list);
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL and additional rights");
+module_param(cards_limit, int, 0444);
+MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards");
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable debug output");
+
+drm_global_t *DRM(global);
 
 /**
  * File \c open operation.
@@ -51,15 +55,24 @@
  * Puts the drm_stub_list::fops corresponding to the device minor number into
  * \p filp, call the \c open method, and restore the file operations.
  */
-static int DRM(stub_open)(struct inode *inode, struct file *filp)
+static int stub_open(struct inode *inode, struct file *filp)
 {
-	int                    minor = iminor(inode);
-	int                    err   = -ENODEV;
+	drm_device_t *dev = NULL;
+	int minor = iminor(inode);
+	int err = -ENODEV;
 	struct file_operations *old_fops;
+	
+	DRM_DEBUG("\n");
+
+	if (!((minor >= 0) && (minor < DRM(global)->cards_limit)))
+		return -ENODEV;
 
-	if (!DRM(stub_list) || !DRM(stub_list)[minor].fops) return -ENODEV;
-	old_fops   = filp->f_op;
-	filp->f_op = fops_get(DRM(stub_list)[minor].fops);
+	dev = DRM(global)->minors[minor].dev;
+	if (!dev)
+		return -ENODEV;
+
+	old_fops = filp->f_op;
+	filp->f_op = fops_get(dev->fops);
 	if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) {
 		fops_put(filp->f_op);
 		filp->f_op = fops_get(old_fops);
@@ -72,23 +85,24 @@
 /** File operations structure */
 static struct file_operations DRM(stub_fops) = {
 	.owner = THIS_MODULE,
-	.open  = DRM(stub_open)
+	.open  = stub_open
 };
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
-static int drm_hotplug (struct class_device *dev, char **envp, int num_envp,
+static int drm_hotplug (struct class_device *cdev, char **envp, int num_envp,
 				char *buffer, int buffer_size)
 {
+	drm_device_t *dev;
 	struct pci_dev *pdev;
 	char *scratch;
 	int i = 0;
 	int length = 0;
-	
+
 	DRM_DEBUG("\n");
-	if (!dev)
+	if (!cdev)
 		return -ENODEV;
 
-	pdev = to_pci_dev(dev->dev);
+	pdev = to_pci_dev(cdev->dev);
 	if (!pdev)
 		return -ENODEV;
 
@@ -127,19 +141,17 @@
 		return -ENOMEM;
 	++length;
 	scratch += length;
-#if 0	
-	drm_device_t *ddev;
-	ddev = pci_get_drvdata(pdev);
-	if (ddev) {
+
+	dev = pci_get_drvdata(pdev);
+	if (dev) {
 		envp[i++] = scratch;
 		length += snprintf (scratch, buffer_size - length, 
-							"RESET=%s", (ddev->need_reset ? "true" : "false"));
+							"RESET=%s", (dev->need_reset ? "true" : "false"));
 		if ((buffer_size - length <= 0) || (i >= num_envp))
 			return -ENOMEM;
 	}
-#endif	
 	envp[i] = 0;
-	
+
 	return 0;
 }
 #endif
@@ -156,33 +168,105 @@
  * empty entry and initialize it to the given parameters, and create the proc
  * init entry via proc_init().
  */
-static int DRM(stub_getminor)(const char *name, struct file_operations *fops,
-			      drm_device_t *dev)
+static int get_minor(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	int i;
+	struct class_device *dev_class;
+	drm_device_t *dev;
+	int ret;
+	int minor;
+	drm_minor_t *minors = &DRM(global)->minors[0];
+
+	DRM_DEBUG("\n");
+
+	for (minor = 0; minor < DRM(global)->cards_limit; minor++, minors++) {
+		if (minors->class == DRM_MINOR_FREE) {
+
+			DRM_DEBUG("assigning minor %d\n", minor);
+			dev = DRM(calloc)(1, sizeof(*dev), DRM_MEM_STUB);
+			if(!dev) 
+				return -ENOMEM;
+
+			*minors = (drm_minor_t){.dev = NULL, .class = DRM_MINOR_PRIMARY};
+			dev->minor = minor;
+			if ((ret = DRM(fill_in_dev)(dev, pdev, ent))) {
+				printk (KERN_ERR "DRM: Fill_in_dev failed.\n");
+				goto err_g1;
+			}
+			if ((ret = DRM(proc_init)(dev, minor, DRM(global)->proc_root, &minors->dev_root))) {
+				printk (KERN_ERR "DRM: Failed to initialize /proc/dri.\n");
+				goto err_g1;
+			}
+			if (!DRM(fb_loaded)) {	/* set this before device_add hotplug uses it */
+				pci_set_drvdata(pdev, dev);
+				pci_request_regions(pdev, DRIVER_NAME);
+				pci_enable_device(pdev);
+			}
+			dev_class = class_simple_device_add(DRM(global)->drm_class, 
+					MKDEV(DRM_MAJOR, minor), &pdev->dev, "card%d", minor);
+			if (IS_ERR(dev_class)) {
+				printk (KERN_ERR "DRM: Error class_simple_device_add.\n");
+				ret = PTR_ERR(dev_class);
+				goto err_g2;
+			}
 
-	if (!DRM(stub_list)) {
-		DRM(stub_list) = DRM(alloc)(sizeof(*DRM(stub_list))
-					    * DRM_STUB_MAXCARDS, DRM_MEM_STUB);
-		if(!DRM(stub_list)) return -1;
-		for (i = 0; i < DRM_STUB_MAXCARDS; i++) {
-			DRM(stub_list)[i].name = NULL;
-			DRM(stub_list)[i].fops = NULL;
+			DRM_DEBUG("new primary minor assigned %d\n", minor);
+			return 0;
 		}
 	}
-	for (i = 0; i < DRM_STUB_MAXCARDS; i++) {
-		if (!DRM(stub_list)[i].fops) {
-			DRM(stub_list)[i].name = name;
-			DRM(stub_list)[i].fops = fops;
-			DRM(proc_init)(dev, i, DRM(stub_info).proc_root,
-							&DRM(stub_list)[i].dev_root);
-			(*DRM(stub_info).info_count)++;
-			DRM_DEBUG("info count increased %d\n", *DRM(stub_info).info_count);
-			
-			return i;
+	DRM_ERROR("out of minors\n");
+	return -ENOMEM;
+err_g2:
+	if (!DRM(fb_loaded)) {
+		pci_set_drvdata(pdev, NULL);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+	}
+	DRM(proc_cleanup)(minor, DRM(global)->proc_root, minors->dev_root);
+err_g1:
+	*minors = (drm_minor_t){.dev = NULL, .class = DRM_MINOR_FREE};
+	DRM(free)(dev, sizeof(*dev), DRM_MEM_STUB);
+	return ret;
+}
+
+int DRM(get_secondary_minor)(drm_device_t *dev, drm_minor_t **sec_minor)
+{
+	drm_minor_t *minors = &DRM(global)->minors[0];
+	struct class_device *dev_class;
+	int ret;
+	int minor;
+
+	DRM_DEBUG("\n");
+
+	for (minor = 0; minor < DRM(global)->cards_limit; minor++, minors++) {
+		if (minors->class == DRM_MINOR_FREE) {
+
+			*minors = (drm_minor_t){.dev = dev, .class = DRM_MINOR_SECONDARY};
+			if ((ret = DRM(proc_init)(dev, minor, DRM(global)->proc_root, &minors->dev_root))) {
+				printk (KERN_ERR "DRM: Failed to initialize /proc/dri.\n");
+				goto err_g1;
+			}
+
+			dev_class = class_simple_device_add(DRM(global)->drm_class, 
+					MKDEV(DRM_MAJOR, minor), &dev->pdev->dev, "card%d", minor);
+			if (IS_ERR(dev_class)) {
+				printk (KERN_ERR "DRM: Error class_simple_device_add.\n");
+				ret = PTR_ERR(dev_class);
+				goto err_g2;
+			}
+			*sec_minor = minors;
+
+			DRM_DEBUG("new secondary minor assigned %d\n", minor);
+			return 0;
 		}
 	}
-	return -1;
+	DRM_ERROR("out of minors\n");
+	return -ENOMEM;
+err_g2:
+	DRM(proc_cleanup)(minor, DRM(global)->proc_root, minors->dev_root);
+err_g1:
+	*minors = (drm_minor_t){.dev = NULL, .class = DRM_MINOR_FREE};
+	DRM(free)(dev, sizeof(*dev), DRM_MEM_STUB);
+	return ret;
 }
 
 /**
@@ -195,31 +279,53 @@
  * "drm" data, otherwise unregisters the "drm" data, frees the stub list and
  * unregisters the character device. 
  */
-static int DRM(stub_putminor)(int minor)
+int DRM(put_minor)(drm_device_t *dev)
 {
-	if (minor < 0 || minor >= DRM_STUB_MAXCARDS) return -1;
-	DRM(stub_list)[minor].name = NULL;
-	DRM(stub_list)[minor].fops = NULL;
-	DRM(proc_cleanup)(minor, DRM(stub_info).proc_root,
-			  DRM(stub_list)[minor].dev_root);
-
-	(*DRM(stub_info).info_count)--;
-
-	if ((*DRM(stub_info).info_count) != 0) {
-		if (DRM(numdevs) == 0) {
-			DRM_DEBUG("inter_module_put called %d\n", *DRM(stub_info).info_count);
+	drm_minor_t *minors = &DRM(global)->minors[dev->minor];
+	int i;
+	
+	DRM_DEBUG("release primary minor %d\n", dev->minor);
+
+	DRM(proc_cleanup)(dev->minor, DRM(global)->proc_root, minors->dev_root);
+	class_simple_device_remove(MKDEV(DRM_MAJOR, dev->minor));
+
+	*minors = (drm_minor_t){.dev = NULL, .class = DRM_MINOR_FREE};
+	DRM(free)(dev, sizeof(*dev), DRM_MEM_STUB);
+
+	/* if any device pointers are non-NULL we are not the last module */
+	for (i = 0; i < DRM(global)->cards_limit; i++) {
+		if (DRM(global)->minors[i].class != DRM_MINOR_FREE) {
+			DRM_DEBUG("inter_module_put called\n");
 			inter_module_put("drm");
+			return 0;
 		}
-	} else {
-		DRM_DEBUG("unregistering inter_module \n");
-		inter_module_unregister("drm");
-		DRM(free)(DRM(stub_list),
-			  sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS,
-			  DRM_MEM_STUB);
-		remove_proc_entry("dri", NULL);
-		class_simple_destroy(DRM(stub_info).drm_class);
-		unregister_chrdev(DRM_MAJOR, "drm");
 	}
+	DRM_DEBUG("unregistering inter_module \n");
+	inter_module_unregister("drm");
+	remove_proc_entry("dri", NULL);
+	class_simple_destroy(DRM(global)->drm_class);
+	cdev_del(&DRM(global)->drm_cdev);
+	unregister_chrdev_region(MKDEV(DRM_MAJOR, 0), DRM_MAX_MINOR);
+
+	DRM(free)(DRM(global)->minors, sizeof(*DRM(global)->minors) *
+				DRM(global)->cards_limit, DRM_MEM_STUB);
+	DRM(free)(DRM(global), sizeof(*DRM(global)), DRM_MEM_STUB);
+	DRM(global) = NULL;
+
+	return 0;
+}
+
+int DRM(put_secondary_minor)(drm_minor_t *sec_minor)
+{
+	int minor = sec_minor - &DRM(global)->minors[0];
+
+	DRM_DEBUG("release secondary minor %d\n", minor);
+
+	DRM(proc_cleanup)(minor, DRM(global)->proc_root, sec_minor->dev_root);
+	class_simple_device_remove(MKDEV(DRM_MAJOR, minor));
+
+	*sec_minor = (drm_minor_t){.dev = NULL, .class = DRM_MINOR_FREE};
+
 	return 0;
 }
 
@@ -237,104 +343,79 @@
  *
  * Finally calls stub_info::info_register.
  */
-int DRM(stub_register)(const char *name, struct file_operations *fops,
-		       drm_device_t *dev)
+int DRM(probe)(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	struct drm_stub_info *i = NULL;
-	int ret1;
-	int ret2;
+	dev_t dev = MKDEV(DRM_MAJOR, 0);
+	drm_global_t *global;
+	int ret = -ENOMEM;
 
 	DRM_DEBUG("\n");
 
-	/* if we are registering a second device we don't need to worry
-	   about inter module get/put and other things as they've been
-	   done already */
-	if (DRM(numdevs) == 0) {
-		/* use the inter_module_get to check - as if the same module
-		   registers chrdev twice it succeeds */
-		i = (struct drm_stub_info *)inter_module_get("drm");
-		if (i) {
-			/* Already registered */
-			DRM(stub_info).info_register   = i->info_register;
-			DRM(stub_info).info_unregister = i->info_unregister;
-			DRM(stub_info).drm_class = i->drm_class;
-			DRM(stub_info).info_count = i->info_count;
-			DRM_DEBUG("already registered %d\n", *i->info_count);
-		} else if (*DRM(stub_info).info_count == 0) {
-
-			ret1 = register_chrdev(DRM_MAJOR, "drm", &DRM(stub_fops));
-			if (ret1 < 0) {
-				printk (KERN_ERR "Error registering drm major number.\n");
-				return ret1;
-			}
+	/* use the inter_module_get to check - as if the same module
+		registers chrdev twice it succeeds */
+	global = (drm_global_t *)inter_module_get("drm");
+	if (global) {
+		DRM(global) = global;
+		global = NULL;
+	} else {
+		DRM_DEBUG("first probe\n");
 
-			DRM(stub_info).drm_class = class_simple_create(THIS_MODULE, "drm");
-			if (IS_ERR(DRM(stub_info).drm_class)) {
-				printk (KERN_ERR "Error creating drm class.\n");
-				unregister_chrdev(DRM_MAJOR, "drm");
-				return PTR_ERR(DRM(stub_info).drm_class);
-			}
-			class_simple_set_hotplug(DRM(stub_info).drm_class, drm_hotplug);
+		global = DRM(calloc)(1, sizeof(*global), DRM_MEM_STUB);
+		if(!global) 
+			return -ENOMEM;
+
+		global->cards_limit = (cards_limit < DRM_MAX_MINOR + 1 ? cards_limit : DRM_MAX_MINOR + 1);
+		global->minors = DRM(calloc)(global->cards_limit, 
+					sizeof(*global->minors), DRM_MEM_STUB);
+		if(!global->minors) 
+			goto err_p1;
 
-			DRM_DEBUG("calling inter_module_register\n");
-			inter_module_register("drm", THIS_MODULE, &DRM(stub_info));
+		if (register_chrdev_region(dev, DRM_MAX_MINOR, "drm"))
+			goto err_p1;
+	
+		strncpy(global->drm_cdev.kobj.name, "drm", KOBJ_NAME_LEN);
+		global->drm_cdev.owner = THIS_MODULE;
+		cdev_init(&global->drm_cdev, &DRM(stub_fops));
+		if (cdev_add(&global->drm_cdev, dev, DRM_MAX_MINOR)) {
+			kobject_put(&global->drm_cdev.kobj);
+			printk (KERN_ERR "DRM: Error registering drm major number.\n");
+			goto err_p2;
+		}
 			
-			DRM(stub_info).proc_root = create_proc_entry("dri", S_IFDIR, NULL);
-			if (!DRM(stub_info).proc_root) {
-				DRM_ERROR("Cannot create /proc/dri\n");
-				inter_module_unregister("drm");
-				unregister_chrdev(DRM_MAJOR, "drm");
-				class_simple_destroy(DRM(stub_info).drm_class);
-				return -1;
-			}
-		
+		global->drm_class = class_simple_create(THIS_MODULE, "drm");
+		if (IS_ERR(global->drm_class)) {
+			printk (KERN_ERR "DRM: Error creating drm class.\n");
+			ret = PTR_ERR(global->drm_class);
+			goto err_p3;
 		}
-	} else
-		DRM_DEBUG("already retrieved inter_module information\n");
+		class_simple_set_hotplug(global->drm_class, drm_hotplug);
 
-	if (DRM(stub_info).info_register) {
-		ret2 = DRM(stub_info).info_register(name, fops, dev);
-		if (ret2 < 0) {
-			if (DRM(numdevs) == 0 && !i) {
-				inter_module_unregister("drm");
-				unregister_chrdev(DRM_MAJOR, "drm");
-				class_simple_destroy(DRM(stub_info).drm_class);
-				remove_proc_entry("dri", NULL);
-				DRM_DEBUG("info_register failed, deregistered everything\n");
-			}
-			DRM_DEBUG("info_register failed\n");
-			return ret2;
+		global->proc_root = create_proc_entry("dri", S_IFDIR, NULL);
+		if (!global->proc_root) {
+			DRM_ERROR("Cannot create /proc/dri\n");
+			ret = -1;
+			goto err_p4;
 		}
-		class_simple_device_add(DRM(stub_info).drm_class, 
-				MKDEV(DRM_MAJOR, ret2), &dev->pdev->dev, "card%d", ret2);
-		return ret2;
+		DRM_DEBUG("calling inter_module_register\n");
+		inter_module_register("drm", THIS_MODULE, global);
+		
+		DRM(global) = global;
 	}
-	return -1;
-}
-
-/**
- * Unregister.
- *
- * \param minor
- *
- * Calls drm_stub_info::unregister.
- */
-int DRM(stub_unregister)(int minor)
-{
-	DRM_DEBUG("%d\n", minor);
-	class_simple_device_remove(MKDEV(DRM_MAJOR, minor));
-	if (DRM(stub_info).info_unregister)
-		return DRM(stub_info).info_unregister(minor);
-	return -1;
+	if ((ret = get_minor(pdev, ent))) {
+		if (global)
+			goto err_p4;
+		return ret;
+	}
+	return 0;
+err_p4:
+	class_simple_destroy(global->drm_class);
+err_p3:
+	cdev_del(&global->drm_cdev);
+	unregister_chrdev_region(dev, DRM_MAX_MINOR);
+err_p2:
+	DRM(free)(global->minors, sizeof(*global->minors) * global->cards_limit, DRM_MEM_STUB);
+err_p1:	
+	DRM(free)(global, sizeof(*global), DRM_MEM_STUB);
+	DRM(global) = NULL;
+	return ret;
 }
-
-int DRM(stub_count);
-
-/** Stub information */
-struct drm_stub_info DRM(stub_info) = {
-	.info_register   = DRM(stub_getminor),
-	.info_unregister = DRM(stub_putminor),
-	.drm_class = NULL,
-	.info_count = &DRM(stub_count),
-	.proc_root = NULL,
-};
===== shared/drm.h 1.4 vs edited =====
--- 1.4/shared/drm.h	Wed Sep  8 22:27:40 2004
+++ edited/shared/drm.h	Sun Sep 12 19:42:45 2004
@@ -112,7 +112,7 @@
 #if defined(__linux__) || defined(__NetBSD__)
 #define DRM_MAJOR       226
 #endif
-#define DRM_MAX_MINOR   15
+#define DRM_MAX_MINOR   255
 #endif
 #define DRM_NAME	"drm"	  /**< Name in kernel, /dev, and /proc */
 #define DRM_MIN_ORDER	5	  /**< At least 2^5 bytes = 32 bytes */

Reply via email to