drm_stub.c revision c94f70298529d99ac6e1ee7709f61eab00adeb39
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \file drm_stub.h
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stub support
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \author Rickard E. (Rik) Faith <faith@valinux.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All Rights Reserved.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Permission is hereby granted, free of charge, to any person obtaining a
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * copy of this software and associated documentation files (the "Software"),
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to deal in the Software without restriction, including without limitation
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the rights to use, copy, modify, merge, publish, distribute, sublicense,
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and/or sell copies of the Software, and to permit persons to whom the
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Software is furnished to do so, subject to the following conditions:
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The above copyright notice and this permission notice (including the next
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * paragraph) shall be included in all copies or substantial portions of the
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Software.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DEALINGS IN THE SOFTWARE.
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "drmP.h"
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "drm_core.h"
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int drm_cards_limit = 16;	/* Enough for one machine */
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int drm_debug = 0;		/* 1 to enable debug output */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(drm_debug);
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR( CORE_AUTHOR );
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION( CORE_DESC );
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL and additional rights");
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards");
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Enable debug output");
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(cards_limit, drm_cards_limit, int, 0444);
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(debug, drm_debug, int, 0666);
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdrm_head_t **drm_heads;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct drm_sysfs_class *drm_class;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct proc_dir_entry *drm_proc_root;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int drm_fill_in_dev(drm_device_t *dev, struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver)
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retcode;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&dev->count_lock);
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer( &dev->timer );
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sema_init( &dev->struct_sem, 1 );
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sema_init( &dev->ctxlist_sem, 1 );
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->pdev   = pdev;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __alpha__
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->hose   = pdev->sysdata;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->pci_domain = dev->hose->bus->number;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->pci_domain = 0;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->pci_bus = pdev->bus->number;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->pci_slot = PCI_SLOT(pdev->devfn);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->pci_func = PCI_FUNC(pdev->devfn);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->irq = pdev->irq;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the DRM has 6 basic counters */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->counters = 6;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->types[0]  = _DRM_STAT_LOCK;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->types[1]  = _DRM_STAT_OPENS;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->types[2]  = _DRM_STAT_CLOSES;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->types[3]  = _DRM_STAT_IOCTLS;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->types[4]  = _DRM_STAT_LOCKS;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->types[5]  = _DRM_STAT_UNLOCKS;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->driver = driver;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->driver->preinit)
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((retcode = dev->driver->preinit(dev, ent->driver_data)))
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error_out_unreg;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drm_core_has_AGP(dev)) {
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->agp = drm_agp_init(dev);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && (dev->agp == NULL)) {
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DRM_ERROR( "Cannot initialize the agpgart module.\n" );
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			retcode = -EINVAL;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error_out_unreg;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (drm_core_has_MTRR(dev)) {
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (dev->agp)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							       dev->agp->agp_info.aper_size*1024*1024,
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							       MTRR_TYPE_WRCOMB,
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							       1 );
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retcode = drm_ctxbitmap_init( dev );
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if( retcode ) {
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error_out_unreg;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror_out_unreg:
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drm_takedown(dev);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return retcode;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * File \c open operation.
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \param inode device inode.
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \param filp file pointer.
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Puts the dev->fops corresponding to the device minor number into
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \p filp, call the \c open method, and restore the file operations.
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint drm_stub_open(struct inode *inode, struct file *filp)
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drm_device_t *dev = NULL;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int minor = iminor(inode);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENODEV;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct file_operations *old_fops;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DRM_DEBUG("\n");
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!((minor >= 0) && (minor < drm_cards_limit)))
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!drm_heads[minor])
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(dev = drm_heads[minor]->dev))
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_fops = filp->f_op;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	filp->f_op = fops_get(&dev->driver->fops);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) {
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fops_put(filp->f_op);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		filp->f_op = fops_get(old_fops);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fops_put(old_fops);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get a secondary minor number.
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \param dev device data structure
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \param sec-minor structure to hold the assigned minor
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \return negative number on failure.
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Search an empty entry and initialize it to the given parameters, and
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * create the proc init entry via proc_init(). This routines assigns
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * minor numbers to secondary heads of multi-headed cards
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
171c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airliestatic int drm_get_head(drm_device_t *dev, drm_head_t *head)
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drm_head_t **heads = drm_heads;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int minor;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DRM_DEBUG("\n");
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (minor = 0; minor < drm_cards_limit; minor++, heads++) {
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!*heads) {
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*head = (drm_head_t) {
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				.dev = dev,
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				.device = MKDEV(DRM_MAJOR, minor),
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				.minor = minor,
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			};
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((ret = drm_proc_init(dev, minor, drm_proc_root, &head->dev_root))) {
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk (KERN_ERR "DRM: Failed to initialize /proc/dri.\n");
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_g1;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			head->dev_class = drm_sysfs_device_add(drm_class,
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							       MKDEV(DRM_MAJOR,
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								     minor),
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							       &dev->pdev->dev,
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							       "card%d", minor);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (IS_ERR(head->dev_class)) {
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_ERR "DRM: Error sysfs_device_add.\n");
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ret = PTR_ERR(head->dev_class);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto err_g2;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*heads = head;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DRM_DEBUG("new minor assigned %d\n", minor);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DRM_ERROR("out of minors\n");
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOMEM;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_g2:
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_g1:
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*head = (drm_head_t) {.dev = NULL};
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
219c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie/**
220c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie * Register.
221c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie *
222c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie * \param pdev - PCI device structure
223c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie * \param ent entry from the PCI ID table with device type flags
224c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie * \return zero on success or a negative number on failure.
225c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie *
226c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie * Attempt to gets inter module "drm" information. If we are first
227c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie * then register the character device and inter module information.
228c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie * Try and register, if we fail to register, backout previous work.
229c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie */
230c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlieint drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
231c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	      struct drm_driver *driver)
232c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie{
233c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	drm_device_t *dev;
234c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	int ret;
235c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie
236c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	DRM_DEBUG("\n");
237c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie
238c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
239c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	if (!dev)
240c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie		return -ENOMEM;
241c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie
242c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	pci_enable_device(pdev);
243c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie
244c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
245c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie		printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
246c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie		goto err_g1;
247c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	}
248c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	if ((ret = drm_get_head(dev, &dev->primary)))
249c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie		goto err_g1;
250c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie
251c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	/* postinit is a required function to display the signon banner */
252c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	/* drivers add secondary heads here if needed */
253c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	if ((ret = dev->driver->postinit(dev, ent->driver_data)))
254c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie		goto err_g1;
255c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie
256c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	return 0;
257c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie
258c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlieerr_g1:
259c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
260c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie	return ret;
261c94f70298529d99ac6e1ee7709f61eab00adeb39Dave Airlie}
262c94f70298529d99ac6e1ee7709f61eab00adeb39Dave AirlieEXPORT_SYMBOL(drm_get_dev);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Put a device minor number.
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \param dev device data structure
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \return always zero
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cleans up the proc resources. If it is the last minor then release the foreign
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "drm" data, otherwise unregisters the "drm" data, frees the dev list and
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * unregisters the character device.
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint drm_put_dev(drm_device_t * dev)
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->unique) {
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->unique = NULL;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->unique_len = 0;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->devname) {
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		drm_free(dev->devname, strlen(dev->devname) + 1,
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 DRM_MEM_DRIVER);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->devname = NULL;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Put a secondary minor number.
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \param sec_minor - structure to be released
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * \return always zero
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cleans up the proc resources. Not legal for this to be the
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * last minor released.
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint drm_put_head(drm_head_t *head)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int minor = head->minor;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DRM_DEBUG("release secondary minor %d\n", minor);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drm_sysfs_device_remove(MKDEV(DRM_MAJOR, head->minor));
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*head = (drm_head_t){.dev = NULL};
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	drm_heads[minor] = NULL;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
318