Site hosted by Angelfire.com: Build your free website today!

Hands-on Projects for the Linux Graphics Subsystem

New book from Christos Karayiannis

Available in Amazon Kindle format at:

amazon.com   amazon.co.uk   amazon.de   amazon.es   amazon.fr   amazon.it

Driver Processing

We continue here with InitOutput() at the point we left the 'Module Loading' paragraph. At this point xf86DriverList[] is filled with entries for each of the drivers and xf86NumDrivers has the number of drivers.

Identify functions

The comment in InitOutput() indicates the next step that follows:

     * Call each of the Identify functions and call the driverFunc to check
     * if HW access is required.  The Identify functions print out some
     * identifying information, and anything else that might be
     * needed at this early stage.

The source code that implements this is the following:

    for (i = 0; i < xf86NumDrivers; i++) {
	xorgHWFlags flags;
      /* The Identify function is mandatory, but if it isn't there continue */
	if (xf86DriverList[i]->Identify != NULL)
   	    xf86DriverList[i]->Identify(0);        
	else {
	    xf86Msg(X_WARNING, "Driver `%s' has no Identify function\n",
		  xf86DriverList[i]->driverName ? xf86DriverList[i]->driverName
					     : "noname");
	}
	if (!xorgHWAccess
	    && (!xf86DriverList[i]->driverFunc
		|| !xf86DriverList[i]->driverFunc(NULL,
						  GET_REQUIRED_HW_INTERFACES,
						  &flags)
		|| NEED_IO_ENABLED(flags)))
	    xorgHWAccess = TRUE;
    }

If we continue with the example of the previous paragraph, the mga driver the identify routine that is used is MGAIdentify(), which is a member of the driver's DriverRec struct that was added previously in xf86DriverList[].

_X_EXPORT DriverRec MGA_C_NAME = {
    MGA_VERSION,
    MGA_DRIVER_NAME,
    MGAIdentify,
    MGAProbe,
    MGAAvailableOptions,
    NULL,
    0
};

MGAIdentify() is implemented as:

static void
MGAIdentify(int flags)
{
    xf86PrintChipsets(MGA_NAME, "driver for Matrox chipsets", MGAChipsets);
}

xf86PrintChipsets() prints out to stderr or to a log file, via xf86Msg(), the driver name, message passed in the second argument and the names of the supported chipsets. Those chipsets as found in mga_driver.c are:

/* Supported chipsets */
static SymTabRec MGAChipsets[] = {
    { PCI_CHIP_MGA2064,		"mga2064w" },
    { PCI_CHIP_MGA1064,		"mga1064sg" },
    { PCI_CHIP_MGA2164,		"mga2164w" },
    { PCI_CHIP_MGA2164_AGP,	"mga2164w AGP" },
    { PCI_CHIP_MGAG100,		"mgag100" },
    { PCI_CHIP_MGAG100_PCI,	"mgag100 PCI" },
    { PCI_CHIP_MGAG200,		"mgag200" },
    { PCI_CHIP_MGAG200_PCI,	"mgag200 PCI" },
    { PCI_CHIP_MGAG200_SE_A_PCI,	"mgag200 SE A PCI" },
    { PCI_CHIP_MGAG200_SE_B_PCI,	"mgag200 SE B PCI" },
    { PCI_CHIP_MGAG400,		"mgag400" },
    { PCI_CHIP_MGAG550,		"mgag550" },
    {-1,			NULL }
};

SymTabRec is defined in xf86str.h.

Probe functions

The next step is shown by the comment in InitOutput():

     * Now call each of the Probe functions.  Each successful probe will
     * result in an extra entry added to the xf86Screens[] list for each
     * instance of the hardware found.

The source code that follows it is:

    for (i = 0; i < xf86NumDrivers; i++) {
	xorgHWFlags flags;
	if (!xorgHWAccess) {
	    if (!xf86DriverList[i]->driverFunc
		|| !xf86DriverList[i]->driverFunc(NULL,
						 GET_REQUIRED_HW_INTERFACES,
						  &flags)
		|| NEED_IO_ENABLED(flags)) 
		continue;
	}
	    
	if (xf86DriverList[i]->Probe != NULL)
	    xf86DriverList[i]->Probe(xf86DriverList[i], PROBE_DEFAULT);   
	else {
	    xf86MsgVerb(X_WARNING, 0,
			"Driver `%s' has no Probe function (ignoring)\n",
			xf86DriverList[i]->driverName
			? xf86DriverList[i]->driverName : "noname");
	}
	xf86SetPciVideo(NULL,NONE);
    }

For the mga driver the probe function is called MGAProbe()

Case study: MGAProbe()

We read at the MGAProbe() comment:

     * The aim here is to find all cards that this driver can handle,
     * and for the ones not already claimed by another driver, claim the
     * slot, and allocate a ScrnInfoRec.

MGAProbe() calls xf86MatchDevice() as:

    if ((numDevSections = xf86MatchDevice(MGA_DRIVER_NAME,
					  &devSections)) <= 0) {

In a Nutshell

MGAProbe() calls xf86MatchDevice(), which is used fill devSections (given as pgdp[] in xf86MatchDevice) a list of pointers to GDevRec. This includes the devices supported by the drivers that the server loads at run time that also appear in the config file.

devSections is then passed to xf86MatchPciInstances() where the xf86PciVideoInfo[], obtained from Parsing the xorg.conf file (Part 2)", is used to find the PCI devices that match the given vendor ID, which in our example is PCI_VENDOR_MATROX. The matching fill instances[].

The devices from instances[] are compared with devSections (devList[]).

xf86MatchDevice()

Its comment explains its usage:

    /*
     * This is a very important function that matches the device sections
     * as they show up in the config file with the drivers that the server
     * loads at run time.
     *
     * ChipProbe can call 
     * int xf86MatchDevice(char * drivername, GDevPtr ** sectlist) 
     * with its driver name. The function allocates an array of GDevPtr and
     * returns this via sectlist and returns the number of elements in
     * this list as return value. 0 means none found, -1 means fatal error.
     * 
     * It can figure out which of the Device sections to use for which card
     * (using things like the Card statement, etc). For single headed servers
     * there will of course be just one such Device section.
     */

As the previous comment explained the drivers found in the Layout section of the config file:

xf86ConfigLayout.screens[j].screen->device->driver

are compared with the drivers the server loads at run time in our case MGA_DRIVER_NAME and generally drivername, i.e the first argument of xf86MatchDevice. Any matching udpdates the second argument of xf86MatchDevice().

MGA_DRIVER_NAME is defined as mga in mga.h:

#define MGA_DRIVER_NAME "mga"

Also two GDevRec as seen in the example of the previous section have device values "mga". Their GDevPtr are included in the devSections.

    /*
     * first we need to loop over all the Screens sections to get to all
     * 'active' device sections
     */
    for (j=0; xf86ConfigLayout.screens[j].screen != NULL; j++) {
        screensecptr = xf86ConfigLayout.screens[j].screen;
        if ((screensecptr->device->driver != NULL)
            && (xf86NameCmp( screensecptr->device->driver,drivername) == 0)
            && (! screensecptr->device->claimed)) {
            /*
             * we have a matching driver that wasn't claimed, yet
             */
            pgdp = xnfrealloc(pgdp, (i + 2) * sizeof(GDevPtr));
            pgdp[i++] = screensecptr->device;
        }
    }

For each screen found at the layout section (see "Parsing the xorg.conf file (Part 2)") as xf86ConfigLayout.screens[j].screen (a confScreenRec struct) xf86NameCmp() is used to find a drivername hit in the layout drivers.

typedef struct _confscreenrec {
    char *		id;
    int			screennum;
    int			defaultdepth;
    int			defaultbpp;
    int			defaultfbbpp;
    MonPtr		monitor;
    GDevPtr		device;
    int			numdisplays;
    DispPtr		displays;
    int			numxvadaptors;
    confXvAdaptorPtr	xvadaptors;
    pointer		options;
} confScreenRec, *confScreenPtr;

The device is then added to pgdp[] an array of GDevPtr. GDevPtr is defined in xf86str.h as:

typedef struct {
   char *			identifier;
   char *			vendor;
   char *			board;
   char *			chipset;
   char *			ramdac;
   char *			driver;
   struct _confscreenrec *	myScreenSection;
   Bool				claimed;
   int				dacSpeeds[MAXDACSPEEDS];
   int				numclocks;
   int				clock[MAXCLOCKS];
   char *			clockchip;
   char *			busID;
   Bool				active;
   Bool				inUse;
   int				videoRam;
   int				textClockFreq;
   unsigned long		BiosBase;	/* Base address of video BIOS */
   unsigned long		MemBase;	/* Frame buffer base address */
   unsigned long		IOBase;
   int				chipID;
   int				chipRev;
   pointer			options;
   int                          irq;
   int                          screen;         /* For multi-CRTC cards */
} GDevRec, *GDevPtr;

As most arrays in Xserver source pgdp[] becomes also NULL terminated. pgdp[] updates the second argument passed to xf86MatchDevice().

Next we examine the following part of MGAProbe() code:

     * All of the cards this driver supports are PCI, so the "probing" just
     * amounts to checking the PCI data that the server has already collected.
     */
    if (xf86GetPciVideoInfo() == NULL) {
	/*
	 * We won't let anything in the config file override finding no
	 * PCI video cards at all.  This seems reasonable now, but we'll see.
	 */
	return FALSE;
    }

    numUsed = xf86MatchPciInstances(MGA_NAME, PCI_VENDOR_MATROX,
			            MGAChipsets, MGAPciChipsets, devSections,
			            numDevSections, drv, &usedChips);

xf86GetPciVideoInfo() is implemented as:

/*
 * Get xf86PciVideoInfo for a driver.
 */
pciVideoPtr *
xf86GetPciVideoInfo(void)
{
    return xf86PciVideoInfo;
}

xf86PciVideoInfo[] was filled previously as we saw at the General Bus Probe section. It is returned now, to pciVideoPtr data and will be used in the code that follows. The devSections, filled at xf86MatchDevice() will be passed as the fifth parameter to the next routine called, xf86MatchPciInstances():

xf86MatchPciInstances() [called by MGAProbe()]

For xf86MatchPciInstances() we read at its comment (at another version of xf86Helper.c though):

 * Find set of unclaimed devices matching a given vendor ID.
 * 
 * Used by drivers to find as yet unclaimed devices matching the specified
 * vendor ID.
 *
 * \param driverName     Name of the driver.  This is used to find Device
 *                       sections in the config file.
 * \param vendorID       PCI vendor ID of associated devices.  If zero, then
 *                       the true vendor ID must be encoded in the \c PCIid
 *                       fields of the \c PCIchipsets entries.
 * \param chipsets       Symbol table used to associate chipset names with
 *                       PCI IDs.
 * \param devList        List of Device sections parsed from the config file.
 * \param numDevs        Number of entries in \c devList.
 * \param drvp           Pointer the driver's control structure.
 * \param foundEntities  Returned list of entity indicies associated with the
 *                       driver.
 * 
 * \returns
 * The number of elements in returned in \c foundEntities on success or zero
 * on failure.

Step 1

In the MGAProbe() function xf86MatchPciInstances() was called with vendorID PCI_VENDOR_MATROX and the following code executes:

    } else {
	/* Find PCI devices that match the given vendor ID */
	for (ppPci = xf86PciVideoInfo; (ppPci != NULL)
	       && (*ppPci != NULL); ppPci++) {
	    if ((*ppPci)->vendor == vendorID) {
		++allocatedInstances;
		instances = xnfrealloc(instances,
			      allocatedInstances * sizeof(struct Inst));
		instances[allocatedInstances - 1].pci = *ppPci;
		instances[allocatedInstances - 1].dev = NULL;
		instances[allocatedInstances - 1].claimed = FALSE;
		instances[allocatedInstances - 1].foundHW = FALSE;
	        instances[allocatedInstances - 1].screen = 0;

		/* Check if the chip type is listed in the chipsets table */
		for (id = PCIchipsets; id->PCIid != -1; id++) {
		    if (id->PCIid == (*ppPci)->chipType) {
			instances[allocatedInstances - 1].chip
			    = id->numChipset;
			instances[allocatedInstances - 1].foundHW = TRUE;
			numFound++;
			break;
		    }
		}

The xf86PciVideoInfo[] items are checked for the given vendorID, i.e. PCI_VENDOR_MATROX, and if a match is found an instances[] element is filled. Recall that xf86PciVideoInfo[] was filled by FindPCIVideoInfo() at the Make a General bus probe section. At this point the instances[] are filled if a Matrox ID exist in the PCI devices included in xf86PciVideoInfo[]. That means that the previous PCI probe returned a Matrox device. The code looks after the device ID. If the chiptype from xf86PciVideoInfo[] matches one in MGAPciChipsets[] (provided by the MGA driver) the foundHW field of instances is set to TRUE.

instances[] represent therefore PCI devices found from the PCI probe that have the given device driver's vendor and chip ID. The elements of this array include also a 'screen' field that will be explained latter. instances[] is defined inside the routine as:

    struct Inst {
	pciVideoPtr	pci;
	GDevPtr		dev;
	Bool		foundHW;  /* PCIid in list of supported chipsets */
	Bool		claimed;  /* BusID matches with a device section */
        int             chip;
        int		screen;
    } *instances = NULL;

where pci is of type pciVideoPtr, defined in xf86str.h as:

typedef struct {
    int			vendor;
    int			chipType;
    int			chipRev;
    int			subsysVendor;
    int			subsysCard;
    int			bus;
    int			device;
    int			func;
    int			class;
    int			subclass;
    int			interface;
    memType  	        memBase[6];
    memType  	        ioBase[6];
    int			size[6];
    unsigned char	type[6];
    memType   	        biosBase;
    int			biosSize;
    pointer		thisCard;
    Bool                validSize;
    Bool                validate;
    CARD32              listed_class;
} pciVideoRec, *pciVideoPtr;

PCIchipsets, the fourth argument was MGAPciChipsets[] passed to xf86MatchPciInstances() from MGAProbe() as MGAPciChipsets[]. It is found in mga_driver.c as:

static PciChipsets MGAPciChipsets[] = {
    { PCI_CHIP_MGA2064,	    PCI_CHIP_MGA2064,	(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGA1064,	    PCI_CHIP_MGA1064,	(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGA2164,	    PCI_CHIP_MGA2164,	(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGA2164_AGP, PCI_CHIP_MGA2164_AGP,(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGAG100,	    PCI_CHIP_MGAG100,	(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGAG100_PCI, PCI_CHIP_MGAG100_PCI,(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGAG200,	    PCI_CHIP_MGAG200,	(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGAG200_PCI, PCI_CHIP_MGAG200_PCI,(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGAG200_SE_B_PCI, PCI_CHIP_MGAG200_SE_B_PCI,
	(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGAG200_SE_A_PCI, PCI_CHIP_MGAG200_SE_A_PCI,
	(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGAG400,	    PCI_CHIP_MGAG400,	(resRange*)RES_SHARED_VGA },
    { PCI_CHIP_MGAG550,	    PCI_CHIP_MGAG550,	(resRange*)RES_SHARED_VGA },
    { -1,			-1,		(resRange*)RES_UNDEFINED }
};

PciChipsets is defined as:

typedef struct {
    int numChipset;
    int PCIid;
    resRange *resList;
} PciChipsets;

Step 2

The next part of code does what its comment says:

    * Check for devices that need duplicated instances.  This is required
    * when there is more than one screen per entity.

devList is actually the devSections filled by xf86MatchDevice(). If a device is found with screen number > 0 and a PCI busID that matches one in the instances, then instances[] obtain a new element that includes the current device. This is the case with the example of a previous section.

    for (j = 0; j < numDevs; j++) {
        if (devList[j]->screen > 0 && devList[j]->busID 
	    && *devList[j]->busID) {
	    for (i = 0; i < allocatedInstances; i++) {
	        pPci = instances[i].pci;
	        if (xf86ComparePciBusString(devList[j]->busID, pPci->bus,
					    pPci->device,
					    pPci->func)) {
		    allocatedInstances++;
		    instances = xnfrealloc(instances,
					   allocatedInstances * 
					   sizeof(struct Inst));
		    instances[allocatedInstances - 1] = instances[i];
		    instances[allocatedInstances - 1].screen =
		      				devList[j]->screen;
		    numFound++;
		    break;
		}
	    }
	}
    }

Example

Consider the following part of xorg.conf from from a laptop with one video card and two displays found at here:

# ===================================================

Section "Device"
	Identifier	"Matrox Graphics, Inc. MGA G400 AGP"
	Driver		"mga"
	Option	        "AGPMode" "4"
	Option	        "hw cursor" "on"
	BusID		"PCI:1:0:0"
	Screen      0
EndSection

Section "Device"
	Identifier	"Matrox Graphics, Inc. MGA G400 AGP second head"
	Driver		"mga"
	Option	        "AGPMode" "4"
	Option	        "hw cursor" "on"
	BusID		"PCI:1:0:0"
	Screen      1
EndSection

Section "ServerLayout"
	Identifier	"Default Layout"
	Screen      0   "Default Screen" RightOf "Screen1" 
	Screen		"Screen1" 0 0
	InputDevice	"Generic Keyboard"
	InputDevice	"Configured Mouse"
EndSection

# ========================================================

The first device provided a screen instance in the step 1, with screen number 0, given that the Vendor ID was found in the PCI probe and also the the chip type is included in the chipset list. For the first instance chip became the value the PCIid, the PciChipsets of the current driver gave for the G400 card which for the current example is found in MGAPciChipsets[] to be PCI_CHIP_MGAG400. This is defined as 0x0525 in xf86PciInfo.h. At step 1 the foundHW field for the first instance became TRUE.

In step 2 the second device has a screen number > 0 and the same BusID with the first. It is therefore included as a new instance, which is a copy of the first by changing only the screen value to 1. The value is taken from the screen field of the specific item from the GDevPtr list, the xf86MatchDevice() filled that matches one of the instances in the PCI characteristics.

At step 3 the dev field of both instances take their value from the devList[] item that has the same PCI characteristics and the same screen number with the specific instance. As mentioned above the list was filled by xf86MatchDevice() with the device taken from the xf86ConfigLayout (xf86ConfigLayout.screens[j].screen->device) with the device name MGA_DRIVER_NAME for the current example.

The claimed field becomes also TRUE.

Two Screen Instances with the same PCI Entity

 Instance 0Instance 1
pci0x102B0x102B
devdev1_valdev2_val
foundHWTRUETRUE
claimedTRUETRUE
chip0x05250x0525
screen01

Step 1 Step 2 Step 3

The following names dev1_val, dev2_val and pci_val are given by us to express the following:

The dev1_val, dev2_val values is of type GDevPtr and were previously filled in this Example.

The pci value (0x102B) is the pciVideoPtr specific item from xf86PciVideoInfo[] as resulted from the General Bus Probe, whose vendor field matches the one passed as second parameter to x86MatchPciInstance(). In our example this is PCI_VENDOR_MATROX defined in xf86PciInfo.h as hex value 0x102B.

The 'screen' field of the instances[] elements, mentioned previously, is to be assigned next. The PCI characteristics (bus, device, function) from the devList[], which is actually the device list from xorg.conf that xf86MatchDevice() updated previously, are compared with the ones of the instances[] elements. Is a match is found a new instsance[] element is created with the 'screen' given from the devList[].

Step 3

The following part of code executes next:

    for (i = 0; i < allocatedInstances; i++) {
	pPci = instances[i].pci;
	devBus = NULL;
	dev = NULL;
	for (j = 0; j < numDevs; j++) {
	    if (devList[j]->busID && *devList[j]->busID) {
		if (xf86ComparePciBusString(devList[j]->busID, pPci->bus,
					   pPci->device,
					   pPci->func) &&
		    devList[j]->screen == instances[i].screen) {
		   
		    if (devBus)
                        xf86MsgVerb(X_WARNING,0,
			    "%s: More than one matching Device section for "
			    "instances\n\t(BusID: %s) found: %s\n",
			    driverName, devList[j]->busID,
			    devList[j]->identifier);
		    else
			devBus = devList[j];
		} 

        . . .

	if (devBus) dev = devBus;  /* busID preferred */ 
	if (!dev) {
	    if (xf86CheckPciSlot(pPci->bus, pPci->device, pPci->func)) {
		xf86MsgVerb(X_WARNING, 0, "%s: No matching Device section "
			    "for instance (BusID PCI:%i:%i:%i) found\n",
			    driverName, pPci->bus, pPci->device, pPci->func);
	    }
	} else {
	    numClaimedInstances++;
	    instances[i].claimed = TRUE;
	    instances[i].dev = dev;

xf86ComparePciBusString calls xf86ParsePciBusString(), where a BUS ID string with the format "bus[@domain]:device[:func]" is analysed to bus, device, function and those are compared with the second, third and fourth argument of xf86ComparePciBusString(). Therefore the bus, device and function PCI values that are compared are from the instances[] and the devList[]. Recall that devList[] is the devSections filled by xf86MatchDevice() and instances[] resulted from the General PCI scanning.

The screen values are also compared:

devList[j]->screen == instances[i].screen

On success and if the bus is not occupied the found bus becomes the one at the current devSections item:

devBus = devList[j];

Next the retEntries[] should be returned to the caller routine.

    numFound = 0;
    for (i = 0; i < allocatedInstances && numClaimedInstances > 0; i++) {
	
	if (!instances[i].claimed)
	    continue;
	pPci = instances[i].pci;

        /*
	 * Allow the same entity to be used more than once for devices with
	 * multiple screens per entity.  This assumes implicitly that there
	 * will be a screen == 0 instance.
	 *
	 * XXX Need to make sure that two different drivers don't claim
	 * the same screen > 0 instance.
	 */
        if (instances[i].screen == 0 &&
	    !xf86CheckPciSlot(pPci->bus, pPci->device, pPci->func))
	    continue;


	/* Allocate an entry in the lists to be returned */
	numFound++;
	retEntities = xnfrealloc(retEntities, numFound * sizeof(int));
	retEntities[numFound - 1]
	    = xf86ClaimPciSlot(pPci->bus, pPci->device,
			       pPci->func,drvp,	instances[i].chip,
			       instances[i].dev,instances[i].dev->active ?
			       TRUE : FALSE);
        if (retEntities[numFound - 1] == -1 && instances[i].screen > 0) {
	    for (j = 0; j < xf86NumEntities; j++) {
	        EntityPtr pEnt = xf86Entities[j];
	        if (pEnt->busType != BUS_PCI)
		    continue;
	        if (pEnt->pciBusId.bus == pPci->bus &&
		    pEnt->pciBusId.device == pPci->device &&
		    pEnt->pciBusId.func == pPci->func) {
		    retEntities[numFound - 1] = j;
		    xf86AddDevToEntity(j, instances[i].dev);
		    break;
		}
	    }
	}
    }
    xfree(instances);
    if (numFound > 0) {
	*foundEntities = retEntities;
    }
	
    return numFound;
}

The list xf86MatchPciInstances() returns (as the last argument though) is actually foundEntities (or retEntities). This is the list of entity indicies associated with the driver.

xf86ClaimPciSlot() claims a slot in xf86Entities[] and fills it. It is implemented as:

In the example we follow here two instances use the same entity. The first instance claims the PCI slot and in xf86ClaimPciSlot() adds its device to the entity with a xf86AddDevToEntity() that is called by xf86ClaimPciSlot(). The second instance (the one with screen number > 0) since it has the same PCI bus, dev, function adds its device to the entity with a second xf86AddDevToEntity().

xf86MatchPciInstances() [called by xf86MatchPciInstances()]

/*
 * If the slot requested is already in use, return -1.
 * Otherwise, claim the slot for the screen requesting it.
 */

int
xf86ClaimPciSlot(int bus, int device, int func, DriverPtr drvp,
		 int chipset, GDevPtr dev, Bool active)
{
    EntityPtr p = NULL;
    pciAccPtr *ppaccp = xf86PciAccInfo;
    BusAccPtr pbap = xf86BusAccInfo;
    
    int num;
    
    if (xf86CheckPciSlot(bus, device, func)) {
	num = xf86AllocateEntity();
	p = xf86Entities[num];
	p->driver = drvp;
	p->chipset = chipset;
	p->busType = BUS_PCI;
	p->pciBusId.bus = bus;
	p->pciBusId.device = device;
	p->pciBusId.func = func;
	p->active = active;
	p->inUse = FALSE;
	if (dev)
            xf86AddDevToEntity(num, dev);
	/* Here we initialize the access structure */
	p->access = xnfcalloc(1,sizeof(EntityAccessRec));
	while (ppaccp && *ppaccp) {
	    if ((*ppaccp)->busnum == bus
		&& (*ppaccp)->devnum == device
		&& (*ppaccp)->funcnum == func) {
		p->access->fallback = &(*ppaccp)->io_memAccess;
		p->access->pAccess = &(*ppaccp)->io_memAccess;
 		(*ppaccp)->ctrl = TRUE; /* mark control if not already */
		break;
	    }
	    ppaccp++;
	}
	if (!ppaccp || !*ppaccp) {
	    p->access->fallback = &AccessNULL;
	    p->access->pAccess = &AccessNULL;
	}
	
	p->busAcc = NULL;
	while (pbap) {
	    if (pbap->type == BUS_PCI && pbap->busdep.pci.bus == bus)
		p->busAcc = pbap;
	    pbap = pbap->next;
	}
	fixPciSizeInfo(num);

	/* in case bios is enabled disable it */
	disablePciBios(pciTag(bus,device,func));
	pciSlotClaimed = TRUE;

	if (active) {
	    /* Map in this domain's I/O space */
	   p->domainIO = xf86MapDomainIO(-1, VIDMEM_MMIO,
					 pciTag(bus, device, func), 0, 1);
	}
	
 	return num;
    } else
 	return -1;
}

==============================
Notice the use of the following 
macros defined in xf86Bus.h:

#define busType bus.type
#define pciBusId bus.id.pci

xf86Entities[] is defined in xf86Bus.c as:

EntityPtr *xf86Entities = NULL;	/* Bus slots claimed by drivers */

where EntityPtr points to EntityRec, as found in xf86Bus.h:

typedef struct {
    DriverPtr                   driver;
    int                         chipset;
    int                         entityProp;
    EntityProc                  entityInit;
    EntityProc                  entityEnter;
    EntityProc                  entityLeave;
    pointer                     private;
    resPtr                      resources;
    Bool                        active;
    Bool                        inUse;
    BusRec                      bus;
    EntityAccessPtr             access;
    AccessFuncPtr               rac;
    pointer                     busAcc;
    int                         lastScrnFlag;
    DevUnion *                  entityPrivates;
    int                         numInstances;
    GDevPtr *                   devices;   
    IOADDRESS                   domainIO;
} EntityRec, *EntityPtr;

xf86AllocateEntity() is implemented as:

int
xf86AllocateEntity(void)
{
    xf86NumEntities++;
    xf86Entities = xnfrealloc(xf86Entities,
			      sizeof(EntityPtr) * xf86NumEntities);
    xf86Entities[xf86NumEntities - 1] = xnfcalloc(1,sizeof(EntityRec));
    xf86Entities[xf86NumEntities - 1]->entityPrivates =
               xnfcalloc(sizeof(DevUnion) * xf86EntityPrivateCount, 1);
    return (xf86NumEntities - 1);
}

If we consider for example that we have one entity, xf86AllocateEntity() returns 0.

xf86CheckPciSlot checks if the slot requested is free.

xf86AddDevToEntity [called by xf86MatchPciInstances()]

xf86AddDevToEntity() is implemented as:

void
xf86AddDevToEntity(int entityIndex, GDevPtr dev)
{
    EntityPtr pEnt;
    
    if (entityIndex >= xf86NumEntities)
	return;
    
    pEnt = xf86Entities[entityIndex];
    pEnt->numInstances++;
    pEnt->devices = xnfrealloc(pEnt->devices,
				pEnt->numInstances * sizeof(GDevPtr));
    pEnt->devices[pEnt->numInstances - 1] = dev;
    dev->claimed = TRUE;
}

xf86AllocateEntity() returned 0 to entityIndex, which is the first argument here. Notice that since xf86AddDevToEntity() for the current example runs twice (the first time embedded in xf86ClaimPciSlot) the numInstances becomes 2. Also pEnt->devices[0] and pEnt->devices[1] that are created in the first and the second xf86AddDevToEntity() call respectively take the GDevPtr values used in this example.

Example (continued)

From the two instances that composed the device in our example (because two screens were required) one Entity is created by calling xf86AddDevToEntity() twice. The first call is hidden inside xf86ClaimPciSlot() and the second call follows xf86ClaimPciSlot().

 Entity
driverDriverRec for mga driver found at xf86DriverList[] and filled in this Example
chipset0x0525
entityProp
entityInit
entityEnter
entityLeave
private
resources
activeTRUE
inUseFALSE
bus
access
rac
busAcc
lastScrnFlag
entityPrivates
numInstances2
devicesThe dev1_val, dev2_val values is of type GDevPtr and were previously filled in this Example
domainIO

Notice: inUse becomes TRUE when xf86AddEntityToScreen() is called.

From this routine becomes clear the relationship between instance and entity, two notions we met frequently at the most recently routines:

An entity has many instances (entity instances) represented by numInstances field from EntityRec. This is the result of xf86AddDevToEntity().

The instance refers to a HARDWARE instance (PCI device) that match the given vendor ID, also their chip type is listed in the chipsets table of the certain vendor and also takes the screen number from the device that match it at the PCI characteristics. An instance has a screen number starting from 0.

To each entity is assigned a driver, a chipset, a bus, device and func (taken from the instance). Therefore the entity claims PCI slot for each instance of the hardware found. This prevents other drivers from claiming the same hardware.

The same entity can be used more than once for devices with multiple screens per entity. This assumes implicitly that there will be a screen == 0 instance. Both heads (screens) will be driven by different instances of the same driver. Each driver runs on a different entity of the same device. Since there is a different copy of the screen structures and driver structures for each driver for each entity this doesn't differ much from the same driver running two distinct chipsets.

For each active instance of the hardware found, a ScrenInfoRec is allocated.

multiple screens implies including multiple instances of drivers

What is an entity? From the DESIGN document we read:

The smallest independently addressable unit on a system bus is referred to as
an entity.  So far we know ISA and PCI entities. PCI entities can be located
on the PCI bus by an unique ID consisting of the bus, card and function num-
ber.

MGAProbe() allocates a new ScrnInfoRec:

	ScrnInfoPtr pScrn;

        . . .
 
	/* Allocate a ScrnInfoRec and claim the slot */
	pScrn = NULL;

ScrnInfoPtr is defined in xf86str.h as:

typedef struct _ScrnInfoRec *ScrnInfoPtr;

where _ScrnInfoRec is a big struct, defined in the same file as:

typedef struct _ScrnInfoRec {
    int			driverVersion;
    char *		driverName;		/* canonical name used in */
						/* the config file */
    ScreenPtr		pScreen;		/* Pointer to the ScreenRec */
    int			scrnIndex;		/* Number of this screen */
    Bool		configured;		/* Is this screen valid */
    int			origIndex;		/* initial number assigned to
						 * this screen before
						 * finalising the number of
						 * available screens */

    /* Display-wide screenInfo values needed by this screen */
    int			imageByteOrder;
    int			bitmapScanlineUnit;
    int			bitmapScanlinePad;
    int			bitmapBitOrder;
    int			numFormats;
    PixmapFormatRec	formats[MAXFORMATS];
    PixmapFormatRec	fbFormat;

    int			bitsPerPixel;		/* fb bpp */
    Pix24Flags		pixmap24;		/* pixmap pref for depth 24 */
    int			depth;			/* depth of default visual */
    MessageType		depthFrom;		/* set from config? */
    MessageType		bitsPerPixelFrom;	/* set from config? */
    rgb			weight;			/* r/g/b weights */
    rgb			mask;			/* rgb masks */
    rgb			offset;			/* rgb offsets */
    int			rgbBits;		/* Number of bits in r/g/b */
    Gamma		gamma;			/* Gamma of the monitor */
    int			defaultVisual;		/* default visual class */
    int			maxHValue;		/* max horizontal timing */
    int			maxVValue;		/* max vertical timing value */
    int			virtualX;		/* Virtual width */
    int			virtualY; 		/* Virtual height */
    int			xInc;			/* Horizontal timing increment */
    MessageType		virtualFrom;		/* set from config? */
    int			displayWidth;		/* memory pitch */
    int			frameX0;		/* viewport position */
    int			frameY0;
    int			frameX1;
    int			frameY1;
    int			zoomLocked;		/* Disallow mode changes */
    DisplayModePtr	modePool;		/* list of compatible modes */
    DisplayModePtr	modes;			/* list of actual modes */
    DisplayModePtr	currentMode;		/* current mode
						 * This was previously
						 * overloaded with the modes
						 * field, which is a pointer
						 * into a circular list */
    confScreenPtr	confScreen;		/* Screen config info */
    MonPtr		monitor;		/* Monitor information */
    DispPtr		display;		/* Display information */
    int *		entityList;		/* List of device entities */
    int			numEntities;
    int			widthmm;		/* physical display dimensions
						 * in mm */
    int			heightmm;
    int			xDpi;			/* width DPI */
    int			yDpi;			/* height DPI */
    char *		name;			/* Name to prefix messages */
    pointer		driverPrivate;		/* Driver private area */
    DevUnion *		privates;		/* Other privates can hook in
						 * here */
    DriverPtr		drv;			/* xf86DriverList[] entry */
    pointer		module;			/* Pointer to module head */
    int			colorKey;
    int			overlayFlags;

    /* Some of these may be moved out of here into the driver private area */

    char *		chipset;		/* chipset name */
    char *		ramdac;			/* ramdac name */
    char *		clockchip;		/* clock name */
    Bool		progClock;		/* clock is programmable */
    int			numClocks;		/* number of clocks */
    int			clock[MAXCLOCKS];	/* list of clock frequencies */
    int			videoRam;		/* amount of video ram (kb) */
    unsigned long	biosBase;		/* Base address of video BIOS */
    unsigned long	memPhysBase;		/* Physical address of FB */
    unsigned long 	fbOffset;		/* Offset of FB in the above */
    IOADDRESS    	domainIOBase;		/* Domain I/O base address */
    int			memClk;			/* memory clock */
    int			textClockFreq;		/* clock of text mode */
    Bool		flipPixels;		/* swap default black/white */
    pointer		options;

    int			chipID;
    int			chipRev;
    int			racMemFlags;
    int			racIoFlags;
    pointer		access;
    xf86CurrentAccessPtr CurrentAccess;
    resType		resourceType;
    pointer		busAccess;

    /* Allow screens to be enabled/disabled individually */
    Bool		vtSema;
    DevUnion		pixmapPrivate;		/* saved devPrivate from pixmap */

    /* hw cursor moves at SIGIO time */
    Bool		silkenMouse;

    /* Storage for clockRanges and adjustFlags for use with the VidMode ext */
    ClockRangesPtr	clockRanges;
    int			adjustFlags;

    /*
     * These can be used when the minor ABI version is incremented.
     * The NUM_* parameters must be reduced appropriately to keep the
     * structure size and alignment unchanged.
     */
    int			reservedInt[NUM_RESERVED_INTS];

    int *		entityInstanceList;
    pointer		reservedPtr[NUM_RESERVED_POINTERS];

    /*
     * Driver entry points.
     *
     */

    xf86ProbeProc			*Probe;
    xf86PreInitProc			*PreInit;
    xf86ScreenInitProc			*ScreenInit;
    xf86SwitchModeProc			*SwitchMode;
    xf86AdjustFrameProc			*AdjustFrame;
    xf86EnterVTProc			*EnterVT;
    xf86LeaveVTProc			*LeaveVT;
    xf86FreeScreenProc			*FreeScreen;
    xf86ValidModeProc			*ValidMode;
    xf86EnableDisableFBAccessProc	*EnableDisableFBAccess;
    xf86SetDGAModeProc			*SetDGAMode;
    xf86ChangeGammaProc			*ChangeGamma;
    xf86PointerMovedProc		*PointerMoved;
    xf86PMEventProc			*PMEvent;
    xf86HandleMessageProc		*HandleMessage;
    xf86DPMSSetProc			*DPMSSet;
    xf86LoadPaletteProc			*LoadPalette;
    xf86SetOverscanProc			*SetOverscan;
    xorgDriverFuncProc			*DriverFunc;

    /*
     * This can be used when the minor ABI version is incremented.
     * The NUM_* parameter must be reduced appropriately to keep the
     * structure size and alignment unchanged.
     */
    funcPointer		reservedFuncs[NUM_RESERVED_FUNCS];

} ScrnInfoRec;

then MGAProbe() calls xf86ConfigPciEntity() to return a ScrnInfoPtr as pScrn. It is called as:

    else for (i = 0; i < numUsed; i++) {
	ScrnInfoPtr pScrn;
	EntityInfoPtr pEnt;
#ifdef DISABLE_VGA_IO
	MgaSavePtr smga;
#endif

	/* Allocate a ScrnInfoRec and claim the slot */
	pScrn = NULL;

#ifndef DISABLE_VGA_IO
	if ((pScrn = xf86ConfigPciEntity(pScrn, 0,usedChips[i],
                                         MGAPciChipsets, NULL, NULL,
                                         NULL, NULL, NULL)))
#else
	    smga = xnfalloc(sizeof(MgaSave));
	    smga->pvp = xf86GetPciInfoForEntity(usedChips[i]);
	    if ((pScrn = xf86ConfigPciEntity(pScrn, 0,usedChips[i],
					       MGAPciChipsets, NULL,VgaIOSave,
					       VgaIOSave, VgaIORestore,smga)))
#endif	

Example (continued)

For the current example (based in this xorg.conf) numUsed, the variable xf86MatchPciInstances() returned is 2 and therefore the previous 'for' loop allocates and fills two ScrnInfoRec. Also the code that follows in this section is executed twice.

xf86ConfigPciEntity() [called by MGAProbe()]

xf86ConfigPciEntity's comment says:

 * xf86ConfigIsa/PciEntity() -- These helper functions assign an
 * active entity to a screen, registers its fixed resources, assign
 * special enter/leave functions and their private scratch area to
 * this entity, take the dog for a walk...

From the DESIGN document we read:

          Allocate a ScrnInfoRec for each active instance of the
          hardware found, and fill in the basic information,
          including the other driver entry points.   This is best
          done with the xf86ConfigIsaEntity() helper function for
          ISA instances or xf86ConfigPciEntity() for PCI instances.
          These functions allocate a ScrnInfoRec for active enti-
          ties. 

ScrnInfoPtr
xf86ConfigPciEntity(ScrnInfoPtr pScrn, int scrnFlag, int entityIndex,
			  PciChipsets *p_chip, resList res, EntityProc init,
			  EntityProc enter, EntityProc leave, pointer private)
{
    PciChipsets *p_id;
    EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);
    if (!pEnt) return pScrn;

    if (!(pEnt->location.type == BUS_PCI) 
	|| !xf86GetPciInfoForEntity(entityIndex)) {
	xfree(pEnt);
	return pScrn;
    }
    if (!pEnt->active) {
	xf86ConfigPciEntityInactive(pEnt, p_chip, res, init,  enter,
				    leave,  private);
	return pScrn;
    }

    if (!pScrn)
	pScrn = xf86AllocateScreen(pEnt->driver,scrnFlag);
    if (xf86IsEntitySharable(entityIndex)) {
        xf86SetEntityShared(entityIndex);
    }
    xf86AddEntityToScreen(pScrn,entityIndex);
    if (xf86IsEntityShared(entityIndex)) {
        return pScrn;
    }
    if (p_chip) {
	for (p_id = p_chip; p_id->numChipset != -1; p_id++) {
	    if (pEnt->chipset == p_id->numChipset) break;
	}
	xf86ClaimFixedResources(p_id->resList,entityIndex);
    }
    xfree(pEnt);

    xf86ClaimFixedResources(res,entityIndex);
    xf86SetEntityFuncs(entityIndex,init,enter,leave,private);

    return pScrn;
}

xf86GetEntityInfo() [called from xf86ConfigPciEntity()]

xf86ConfigPciEntity calls xf86GetEntityInfo() as:

EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);

entityIndex was passed to xf86ConfigPciEntity as the third argument. This was the usedChips[] elements. usedChips[] was previously filled by xf86MatchPciInstances(). It was the last argument, which was corresponding to the "Returned list of entity indicies associated with the driver."

xf86GetEntityInfo is implemented as:

/*
 * xf86GetEntityInfo() -- This function hands information from the
 * EntityRec struct to the drivers. The EntityRec structure itself
 * remains invisible to the driver.
 */
EntityInfoPtr
xf86GetEntityInfo(int entityIndex)
{
    EntityInfoPtr pEnt;
    int i;
    
    if (entityIndex >= xf86NumEntities)
	return NULL;
    
    pEnt = xnfcalloc(1,sizeof(EntityInfoRec));
    pEnt->index = entityIndex;
    pEnt->location = xf86Entities[entityIndex]->bus;
    pEnt->active = xf86Entities[entityIndex]->active;
    pEnt->chipset = xf86Entities[entityIndex]->chipset;
    pEnt->resources = xf86Entities[entityIndex]->resources;
    pEnt->driver = xf86Entities[entityIndex]->driver;
    if ( (xf86Entities[entityIndex]->devices) &&
         (xf86Entities[entityIndex]->devices[0]) ) {
	for (i = 0; i < xf86Entities[entityIndex]->numInstances; i++)
	    if (xf86Entities[entityIndex]->devices[i]->screen == 0)
	        break;
	pEnt->device = xf86Entities[entityIndex]->devices[i];
    } else
	pEnt->device = NULL;
    
    return pEnt;
}

The current info is found at xf86Entities[entityIndex]. As entityIndex is passed from MGAProbe() to xf86ConfigPciEntity() the usedChips[i] value. This was filled by xf86MatchPciInstances() and returned to the caller routine (MGAProbe) as foundEntities or retEntities in the code since:

	*foundEntities = retEntities;

We read from the DESIGN document for xf86AllocateScreen():

          This function allocates a new ScrnInfoRec in the
          xf86Screens[] array.  This function is normally called by
          the video driver ChipProbe() functions. 

/* Allocate a new ScrnInfoRec in xf86Screens */

ScrnInfoPtr
xf86AllocateScreen(DriverPtr drv, int flags)
{
    int i;

    if (xf86Screens == NULL)
	xf86NumScreens = 0;

    i = xf86NumScreens++;
    xf86Screens = xnfrealloc(xf86Screens, xf86NumScreens * sizeof(ScrnInfoPtr));
    xf86Screens[i] = xnfcalloc(sizeof(ScrnInfoRec), 1);
    xf86Screens[i]->scrnIndex = i;	/* Changes when a screen is removed */
    xf86Screens[i]->origIndex = i;	/* This never changes */
    xf86Screens[i]->privates = xnfcalloc(sizeof(DevUnion),
					 xf86ScrnInfoPrivateCount);
    /*
     * EnableDisableFBAccess now gets initialized in InitOutput()
     * xf86Screens[i]->EnableDisableFBAccess = xf86EnableDisableFBAccess;
     */

    xf86Screens[i]->drv = drv;
    drv->refCount++;
#ifdef XFree86LOADER
    xf86Screens[i]->module = DuplicateModule(drv->module, NULL);
#else
    xf86Screens[i]->module = NULL;
#endif
    /*
     * set the initial access state. This will be modified after PreInit.
     * XXX Or should we do it some other place?
     */
    xf86Screens[i]->CurrentAccess = &xf86CurrentAccess;
    xf86Screens[i]->resourceType = MEM_IO;

#ifdef DEBUG
    /* OOps -- What's this ? */
    ErrorF("xf86AllocateScreen - xf86Screens[%d]->pScreen = %p\n",
	   i, xf86Screens[i]->pScreen );
    if ( NULL != xf86Screens[i]->pScreen ) {
      ErrorF("xf86Screens[%d]->pScreen->CreateWindow = %p\n",
	     i, xf86Screens[i]->pScreen->CreateWindow );
    }
#endif

    xf86Screens[i]->DriverFunc = drv->driverFunc;
    
    return xf86Screens[i];
}

xf86ConfigPciEntity [called by xf86ConfigPciEntity()]

xf86AddEntityToScreen() as the comment of the DESIGN document says:

          This function associates the entity referenced by enti-
          tyIndex with the screen.

It is implemented as:


_X_EXPORT void
xf86AddEntityToScreen(ScrnInfoPtr pScrn, int entityIndex)
{
    if (entityIndex == -1)
	return;
    if (xf86Entities[entityIndex]->inUse &&
	!(xf86Entities[entityIndex]->entityProp & IS_SHARED_ACCEL))
	FatalError("Requested Entity already in use!\n");

    pScrn->numEntities++;
    pScrn->entityList = xnfrealloc(pScrn->entityList,
				    pScrn->numEntities * sizeof(int));
    pScrn->entityList[pScrn->numEntities - 1] = entityIndex;
    xf86Entities[entityIndex]->access->next = pScrn->access;
    pScrn->access = xf86Entities[entityIndex]->access;
    xf86Entities[entityIndex]->inUse = TRUE;
    pScrn->entityInstanceList = xnfrealloc(pScrn->entityInstanceList,
				    pScrn->numEntities * sizeof(int));
    pScrn->entityInstanceList[pScrn->numEntities - 1] = 0;
    pScrn->domainIOBase = xf86Entities[entityIndex]->domainIO;
}

For xf86SetEntityFuncs() the DESIGN document refers:

          This function registers with an entity the init, enter,
          leave functions along with the pointer to their private
          area.

It is implemented as:

Bool
xf86SetEntityFuncs(int entityIndex, EntityProc init, EntityProc enter,
		   EntityProc leave, pointer private)
{
    if (entityIndex >= xf86NumEntities)
	return FALSE;
    xf86Entities[entityIndex]->entityInit = init;
    xf86Entities[entityIndex]->entityEnter = enter;
    xf86Entities[entityIndex]->entityLeave = leave;
    xf86Entities[entityIndex]->private = private;
    return TRUE;
}

MGAProbe() (continued)

MGAProbe() fills then some fields for the ScrnInfoRec:

	/* Fill in what we can of the ScrnInfoRec */
		pScrn->driverVersion	= MGA_VERSION;
		pScrn->driverName	= MGA_DRIVER_NAME;
		pScrn->name		= MGA_NAME;
		pScrn->Probe		= MGAProbe;
		pScrn->PreInit		= MGAPreInit;
		pScrn->ScreenInit	= MGAScreenInit;
		pScrn->SwitchMode	= MGASwitchMode;
		pScrn->AdjustFrame	= MGAAdjustFrame;
		pScrn->EnterVT		= MGAEnterVT;
		pScrn->LeaveVT		= MGALeaveVT;
		pScrn->FreeScreen	= MGAFreeScreen;
		pScrn->ValidMode	= MGAValidMode;

		foundScreen = TRUE;

Example (continued)

The following are the two ScrnInfoRec structs that are resulted from the current example:

FieldScrnInfoRec 1ScrnInfoRec 2
driverVersionMGA_VERSIONMGA_VERSION
driverNameMGA_DRIVER_NAMEMGA_DRIVER_NAME
pScreenfilled in section 3.2.2.10filled in section 3.2.2.10
scrnIndex01
configuredTRUE (filled at section 3.2.2.8)TRUE (at section 3.2.2.8)
origIndex01
imageByteOrder
bitmapScanlineUnit
bitmapScanlinePad
bitmapBitOrder
numFormats
formats[]
fbFormat
bitsPerPixelfilled in section 3.2.2.8filled in section 3.2.2.8
pixmap24filled in section 3.2.2.8filled in section 3.2.2.8
depthfilled in section 3.2.2.8filled in section 3.2.2.8
depthFromfilled in section 3.2.2.8filled in section 3.2.2.8
bitsPerPixelFromfilled in section 3.2.2.8filled in section 3.2.2.8
weight
mask
offset
rgbBitsfilled in section 3.2.2.8filled in section 3.2.2.8
gamma
defaultVisual
maxHValue
maxVValue
virtualX
virtualY
xInc
virtualFrom
displayWidth
frameX0
frameY0
frameX1
frameY1
zoomLocked
modePool
modes
currentMode
confScreenfilled in section 3.2.2.7 filled in section 3.2.2.7
monitor
display
entityListentitilist[0] = 0entitilist[0] = 0
numEntities11
widthmm
heightmm
xDpi
yDpi
nameMGA_NAMEMGA_NAME
driverPrivatefilled in section 3.2.2.8 with the form of various fields pMga points tofilled in section 3.2.2.8 with the form of various fields pMga points to
privates
drvDriverRecDriverRec
modulea ModuleDescPtr to this ModuleDesca ModuleDescPtr to this ModuleDesc
colorKey
overlayFlags
chipset
ramdac
clockchip
progClockfilled in section 3.2.2.8filled in section 3.2.2.8
numClocks
clock[]
videoRam
biosBase
memPhysBase
fbOffset
domainIOBase
memClk
textClockFreq
flipPixels
optionsfilled in section 3.2.2.8filled in section 3.2.2.8
chipID
chipRev
racMemFlags
racIoFlags
access
CurrentAccess&xf86CurrentAccess&xf86CurrentAccess
resourceTypeMEM_IOMEM_IO
busAccess
vtSemafilled in section 3.2.2.10filled in section 3.2.2.10
pixmapPrivate
silkenMouse
clockRanges
adjustFlags
reservedInt[]
entityInstanceListentityInstanceList[0]=0entityInstanceList[0]=0
reservedPtr[]
ProbeMGAProbeMGAProbe
PreInitMGAPreInitMGAPreInit
ScreenInitMGAScreenInitMGAScreenInit
SwitchModeMGASwitchModeMGASwitchMode
AdjustFrameMGAAdjustFrameMGAAdjustFrame
EnterVTMGAEnterVTMGAEnterVT
LeaveVTMGALeaveVTMGALeaveVT
FreeScreenMGAFreeScreenMGAFreeScreen
ValidModeMGAValidModeMGAValidMode
EnableDisableFBAccessfilled in section 3.2.2.10filled in section 3.2.2.10
SetDGAModefilled in section 3.2.2.10filled in section 3.2.2.10
ChangeGamma
PointerMoved
PMEvent
HandleMessage
DPMSSetfilled in section 3.2.2.10filled in section 3.2.2.10
LoadPalettefilled in section 3.2.2.10filled in section 3.2.2.10
SetOverscanfilled in section 3.2.2.10filled in section 3.2.2.10
DriverFuncNULL (filled in section 3.2.2.10)NULL (filled in section 3.2.2.10)
reservedFuncs[]

	/*
	 * For cards that can do dual head per entity, mark the entity
	 * as sharable. 
	 */
	pEnt = xf86GetEntityInfo(usedChips[i]);
	if ((pEnt->chipset == PCI_CHIP_MGAG400 || pEnt->chipset == PCI_CHIP_MGAG550)) {
	    MGAEntPtr pMgaEnt = NULL;
	    DevUnion *pPriv;

	    xf86SetEntitySharable(usedChips[i]);
	    /* Allocate an entity private if necessary */
	    if (MGAEntityIndex < 0)
		MGAEntityIndex = xf86AllocateEntityPrivateIndex();
	    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], MGAEntityIndex);
	    if (!pPriv->ptr) {
		pPriv->ptr = xnfcalloc(sizeof(MGAEntRec), 1);
		pMgaEnt = pPriv->ptr;
		pMgaEnt->lastInstance = -1;
	    } else {
		pMgaEnt = pPriv->ptr;
	    }
	    /*
	     * Set the entity instance for this instance of the driver.  For
	     * dual head per card, instance 0 is the "master" instance, driving
	     * the primary head, and instance 1 is the "slave".
	     */
	    pMgaEnt->lastInstance++;
	    xf86SetEntityInstanceForScreen(pScrn, pScrn->entityList[0],
					   pMgaEnt->lastInstance);
	}
    }

NOTES:

Blue colored code indicates that a value is assigned to a ScrnInfoRec field.

REFERENCES:

Graphic Stack Overview
DESIGN Document
Driver Development
Nouveau open source driver