2005-04-17 02:20:36 +04:00
/**
* \ file drm_stub . h
* Stub support
*
* \ author Rickard E . ( Rik ) Faith < faith @ valinux . com >
*/
/*
* Created : Fri Jan 19 10 : 48 : 35 2001 by faith @ acm . org
*
* Copyright 2001 VA Linux Systems , Inc . , Sunnyvale , California .
* All Rights Reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* PRECISION INSIGHT AND / OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE .
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include "drmP.h"
# include "drm_core.h"
unsigned int drm_cards_limit = 16 ; /* Enough for one machine */
2005-09-25 08:28:13 +04:00
unsigned int drm_debug = 0 ; /* 1 to enable debug output */
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( drm_debug ) ;
2005-09-25 08:28:13 +04:00
MODULE_AUTHOR ( CORE_AUTHOR ) ;
MODULE_DESCRIPTION ( CORE_DESC ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL and additional rights " ) ;
MODULE_PARM_DESC ( cards_limit , " Maximum number of graphics cards " ) ;
MODULE_PARM_DESC ( debug , " Enable debug output " ) ;
module_param_named ( cards_limit , drm_cards_limit , int , 0444 ) ;
2005-10-03 23:02:20 +04:00
module_param_named ( debug , drm_debug , int , 0600 ) ;
2005-04-17 02:20:36 +04:00
2007-07-11 09:53:27 +04:00
struct drm_head * * drm_heads ;
2006-01-21 01:08:59 +03:00
struct class * drm_class ;
2005-04-17 02:20:36 +04:00
struct proc_dir_entry * drm_proc_root ;
2007-07-11 09:53:27 +04:00
static int drm_fill_in_dev ( struct drm_device * dev , struct pci_dev * pdev ,
2005-09-25 08:28:13 +04:00
const struct pci_device_id * ent ,
struct drm_driver * driver )
2005-04-17 02:20:36 +04:00
{
int retcode ;
2007-05-25 23:01:51 +04:00
INIT_LIST_HEAD ( & dev - > filelist ) ;
2007-07-11 06:05:36 +04:00
INIT_LIST_HEAD ( & dev - > ctxlist ) ;
INIT_LIST_HEAD ( & dev - > vmalist ) ;
INIT_LIST_HEAD ( & dev - > maplist ) ;
2005-04-17 02:20:36 +04:00
spin_lock_init ( & dev - > count_lock ) ;
2006-10-24 17:04:19 +04:00
spin_lock_init ( & dev - > drw_lock ) ;
2006-10-24 17:30:01 +04:00
spin_lock_init ( & dev - > tasklet_lock ) ;
2007-03-23 05:28:33 +03:00
spin_lock_init ( & dev - > lock . spinlock ) ;
2005-09-25 08:28:13 +04:00
init_timer ( & dev - > timer ) ;
2006-02-02 11:37:46 +03:00
mutex_init ( & dev - > struct_mutex ) ;
mutex_init ( & dev - > ctxlist_mutex ) ;
2005-04-17 02:20:36 +04:00
2005-09-25 08:28:13 +04:00
dev - > pdev = pdev ;
2006-09-21 22:19:34 +04:00
dev - > pci_device = pdev - > device ;
dev - > pci_vendor = pdev - > vendor ;
2005-04-17 02:20:36 +04:00
# ifdef __alpha__
2005-09-25 08:28:13 +04:00
dev - > hose = pdev - > sysdata ;
2005-04-17 02:20:36 +04:00
# endif
dev - > irq = pdev - > irq ;
2006-08-07 16:36:47 +04:00
if ( drm_ht_create ( & dev - > map_hash , 12 ) ) {
return - ENOMEM ;
}
2005-07-10 13:27:04 +04:00
2005-04-17 02:20:36 +04:00
/* the DRM has 6 basic counters */
dev - > counters = 6 ;
2005-09-25 08:28:13 +04:00
dev - > types [ 0 ] = _DRM_STAT_LOCK ;
dev - > types [ 1 ] = _DRM_STAT_OPENS ;
dev - > types [ 2 ] = _DRM_STAT_CLOSES ;
dev - > types [ 3 ] = _DRM_STAT_IOCTLS ;
dev - > types [ 4 ] = _DRM_STAT_LOCKS ;
dev - > types [ 5 ] = _DRM_STAT_UNLOCKS ;
2005-04-17 02:20:36 +04:00
dev - > driver = driver ;
2005-09-25 08:28:13 +04:00
2005-11-10 14:16:34 +03:00
if ( dev - > driver - > load )
if ( ( retcode = dev - > driver - > load ( dev , ent - > driver_data ) ) )
2005-04-17 02:20:36 +04:00
goto error_out_unreg ;
if ( drm_core_has_AGP ( dev ) ) {
2005-07-10 11:31:26 +04:00
if ( drm_device_is_agp ( dev ) )
dev - > agp = drm_agp_init ( dev ) ;
2005-09-25 08:28:13 +04:00
if ( drm_core_check_feature ( dev , DRIVER_REQUIRE_AGP )
& & ( dev - > agp = = NULL ) ) {
DRM_ERROR ( " Cannot initialize the agpgart module. \n " ) ;
2005-04-17 02:20:36 +04:00
retcode = - EINVAL ;
goto error_out_unreg ;
}
if ( drm_core_has_MTRR ( dev ) ) {
if ( dev - > agp )
2005-09-25 08:28:13 +04:00
dev - > agp - > agp_mtrr =
mtrr_add ( dev - > agp - > agp_info . aper_base ,
dev - > agp - > agp_info . aper_size *
1024 * 1024 , MTRR_TYPE_WRCOMB , 1 ) ;
2005-04-17 02:20:36 +04:00
}
}
2005-09-25 08:28:13 +04:00
retcode = drm_ctxbitmap_init ( dev ) ;
if ( retcode ) {
DRM_ERROR ( " Cannot allocate memory for context bitmap. \n " ) ;
2005-04-17 02:20:36 +04:00
goto error_out_unreg ;
}
return 0 ;
2005-09-25 08:28:13 +04:00
error_out_unreg :
2005-11-10 14:16:34 +03:00
drm_lastclose ( dev ) ;
2005-04-17 02:20:36 +04:00
return retcode ;
}
/**
* Get a secondary minor number .
*
* \ param dev device data structure
* \ param sec - minor structure to hold the assigned minor
* \ return negative number on failure .
*
* Search an empty entry and initialize it to the given parameters , and
* create the proc init entry via proc_init ( ) . This routines assigns
* minor numbers to secondary heads of multi - headed cards
*/
2007-07-11 09:53:27 +04:00
static int drm_get_head ( struct drm_device * dev , struct drm_head * head )
2005-04-17 02:20:36 +04:00
{
2007-07-11 09:53:27 +04:00
struct drm_head * * heads = drm_heads ;
2005-04-17 02:20:36 +04:00
int ret ;
int minor ;
DRM_DEBUG ( " \n " ) ;
for ( minor = 0 ; minor < drm_cards_limit ; minor + + , heads + + ) {
if ( ! * heads ) {
2005-09-25 08:28:13 +04:00
2007-07-11 09:53:27 +04:00
* head = ( struct drm_head ) {
2005-09-25 08:28:13 +04:00
. dev = dev , . device =
MKDEV ( DRM_MAJOR , minor ) , . minor = minor , } ;
if ( ( ret =
drm_proc_init ( dev , minor , drm_proc_root ,
& head - > dev_root ) ) ) {
printk ( KERN_ERR
" DRM: Failed to initialize /proc/dri. \n " ) ;
2005-04-17 02:20:36 +04:00
goto err_g1 ;
}
2005-11-11 14:07:35 +03:00
head - > dev_class = drm_sysfs_device_add ( drm_class , head ) ;
2005-04-17 02:20:36 +04:00
if ( IS_ERR ( head - > dev_class ) ) {
2005-09-25 08:28:13 +04:00
printk ( KERN_ERR
" DRM: Error sysfs_device_add. \n " ) ;
2005-04-17 02:20:36 +04:00
ret = PTR_ERR ( head - > dev_class ) ;
goto err_g2 ;
}
* heads = head ;
DRM_DEBUG ( " new minor assigned %d \n " , minor ) ;
return 0 ;
}
}
DRM_ERROR ( " out of minors \n " ) ;
return - ENOMEM ;
2005-09-25 08:28:13 +04:00
err_g2 :
2005-04-17 02:20:36 +04:00
drm_proc_cleanup ( minor , drm_proc_root , head - > dev_root ) ;
2005-09-25 08:28:13 +04:00
err_g1 :
2007-07-11 09:53:27 +04:00
* head = ( struct drm_head ) {
2005-09-25 08:28:13 +04:00
. dev = NULL } ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2005-09-25 08:28:13 +04:00
2005-07-07 15:03:38 +04:00
/**
* Register .
*
* \ param pdev - PCI device structure
* \ param ent entry from the PCI ID table with device type flags
* \ return zero on success or a negative number on failure .
*
* Attempt to gets inter module " drm " information . If we are first
* then register the character device and inter module information .
* Try and register , if we fail to register , backout previous work .
*/
int drm_get_dev ( struct pci_dev * pdev , const struct pci_device_id * ent ,
2005-09-25 08:28:13 +04:00
struct drm_driver * driver )
2005-07-07 15:03:38 +04:00
{
2007-07-11 09:53:27 +04:00
struct drm_device * dev ;
2005-07-07 15:03:38 +04:00
int ret ;
DRM_DEBUG ( " \n " ) ;
dev = drm_calloc ( 1 , sizeof ( * dev ) , DRM_MEM_STUB ) ;
if ( ! dev )
return - ENOMEM ;
2006-12-09 02:50:22 +03:00
ret = pci_enable_device ( pdev ) ;
if ( ret )
goto err_g1 ;
2005-07-07 15:03:38 +04:00
if ( ( ret = drm_fill_in_dev ( dev , pdev , ent , driver ) ) ) {
printk ( KERN_ERR " DRM: Fill_in_dev failed. \n " ) ;
2006-12-09 02:50:22 +03:00
goto err_g2 ;
2005-07-07 15:03:38 +04:00
}
if ( ( ret = drm_get_head ( dev , & dev - > primary ) ) )
2006-12-09 02:50:22 +03:00
goto err_g2 ;
2005-11-10 14:16:34 +03:00
DRM_INFO ( " Initialized %s %d.%d.%d %s on minor %d \n " ,
driver - > name , driver - > major , driver - > minor , driver - > patchlevel ,
driver - > date , dev - > primary . minor ) ;
2005-07-07 15:03:38 +04:00
return 0 ;
2006-12-09 02:50:22 +03:00
err_g2 :
pci_disable_device ( pdev ) ;
err_g1 :
2005-07-07 15:03:38 +04:00
drm_free ( dev , sizeof ( * dev ) , DRM_MEM_STUB ) ;
return ret ;
}
2005-09-25 08:28:13 +04:00
2005-04-17 02:20:36 +04:00
/**
* Put a device minor number .
*
* \ param dev device data structure
* \ return always zero
*
* Cleans up the proc resources . If it is the last minor then release the foreign
* " drm " data , otherwise unregisters the " drm " data , frees the dev list and
* unregisters the character device .
*/
2007-07-11 09:53:27 +04:00
int drm_put_dev ( struct drm_device * dev )
2005-04-17 02:20:36 +04:00
{
DRM_DEBUG ( " release primary %s \n " , dev - > driver - > pci_driver . name ) ;
if ( dev - > unique ) {
drm_free ( dev - > unique , strlen ( dev - > unique ) + 1 , DRM_MEM_DRIVER ) ;
dev - > unique = NULL ;
dev - > unique_len = 0 ;
}
if ( dev - > devname ) {
drm_free ( dev - > devname , strlen ( dev - > devname ) + 1 ,
DRM_MEM_DRIVER ) ;
dev - > devname = NULL ;
}
drm_free ( dev , sizeof ( * dev ) , DRM_MEM_STUB ) ;
return 0 ;
}
/**
* Put a secondary minor number .
*
* \ param sec_minor - structure to be released
* \ return always zero
*
* Cleans up the proc resources . Not legal for this to be the
* last minor released .
*
*/
2007-07-11 09:53:27 +04:00
int drm_put_head ( struct drm_head * head )
2005-04-17 02:20:36 +04:00
{
int minor = head - > minor ;
2005-09-25 08:28:13 +04:00
2005-04-17 02:20:36 +04:00
DRM_DEBUG ( " release secondary minor %d \n " , minor ) ;
2005-09-25 08:28:13 +04:00
2005-04-17 02:20:36 +04:00
drm_proc_cleanup ( minor , drm_proc_root , head - > dev_root ) ;
2005-11-11 14:07:35 +03:00
drm_sysfs_device_remove ( head - > dev_class ) ;
2005-09-25 08:28:13 +04:00
2007-07-11 09:53:27 +04:00
* head = ( struct drm_head ) { . dev = NULL } ;
2005-04-17 02:20:36 +04:00
drm_heads [ minor ] = NULL ;
2005-09-25 08:28:13 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}