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

How the X Server code uses PCI

X Server collects information about the PCI in two stages:

First by pasing the xorg.conf, the configuration file for the X Server. This file is in some cases generated automatically (like in Ubuntu Linux) and in some cases is filled by the administrator. In the latter case, PCI programs like the lspci or the -scanpci command line option of the Xorg server are used to gather information about the PCI bus of the system.

The second source of information is by making a General PCI probe to discover the whole picture of the PCI bus of the current system.

Stage 1: Parsing the xorg.conf for PCI info

At section 3.2.2.1 and section 3.2.2.2 we followed the xorg.conf parsing from the X server. In those sections an example of parsing a specific section of xorg.conf was illustrated, however since this example was not about the "Device" section that is of interest, regarding PCI, we will shortly illustrate the data structures involved to parsing the "Device" section. The xorg.conf manual page might be usefull in describing the xorg.conf sections.

As noted in these sections the aim of parsing xorg.conf is filling struct XF86ConfigRec, which is defined in xf86Parser.h as:

typedef struct
{
	XF86ConfFilesPtr conf_files;
	XF86ConfModulePtr conf_modules;
	XF86ConfFlagsPtr conf_flags;
	XF86ConfVideoAdaptorPtr conf_videoadaptor_lst;
	XF86ConfModesPtr conf_modes_lst;
	XF86ConfMonitorPtr conf_monitor_lst;
	XF86ConfDevicePtr conf_device_lst;
	XF86ConfScreenPtr conf_screen_lst;
	XF86ConfInputPtr conf_input_lst;
	XF86ConfLayoutPtr conf_layout_lst;
	XF86ConfVendorPtr conf_vendor_lst;
	XF86ConfDRIPtr conf_dri;
	XF86ConfExtensionsPtr conf_extensions;
	char *conf_comment;
}
XF86ConfigRec, *XF86ConfigPtr;

For the "Device" section we focus in conf_device_lst field, which is highlighted in the previous box. This is of type XF86ConfDevicePtr, which is defined in the same file as:

typedef struct
{
	GenericListRec list;
	char *dev_identifier;
	char *dev_vendor;
	char *dev_board;
	char *dev_chipset;
	char *dev_busid;
	char *dev_card;
	char *dev_driver;
	char *dev_ramdac;
	int dev_dacSpeeds[CONF_MAXDACSPEEDS];
	int dev_videoram;
	int dev_textclockfreq;
	unsigned long dev_bios_base;
	unsigned long dev_mem_base;
	unsigned long dev_io_base;
	char *dev_clockchip;
	int dev_clocks;
	int dev_clock[CONF_MAXCLOCKS];
	int dev_chipid;
	int dev_chiprev;
	int dev_irq;
	int dev_screen;
	XF86OptionPtr dev_option_lst;
	char *dev_comment;
}
XF86ConfDeviceRec, *XF86ConfDevicePtr;

The xorg.conf man page explains most of the XF86ConfDeviceRec fields:

BusID "bus-id"
This specifies the bus location of the graphics card. For PCI/AGP cards, the bus-id string has the form PCI:bus:device:function (e.g., "PCI:1:0:0" might be appropriate for an AGP card). This field is usually optional in single-head configurations when using the primary graphics card. In multi-head configurations, or when using a secondary graphics card in a single-head configuration, this entry is mandatory. Its main purpose is to make an unambiguous connection between the device section and the hardware it is representing. This information can usually be found by running the Xorg server with the -scanpci command line option.

Screen number
This option is mandatory for cards where a single PCI entity can drive more than one display (i.e., multiple CRTCs sharing a single graphics accelerator and video memory). One Device section is required for each head, and this parameter determines which head each of the Device sections applies to. The legal values of number range from 0 to one less than the total number of heads per entity. Most drivers require that the primary screen (0) be present.

Chipset "chipset"
This usually optional entry specifies the chipset used on the graphics board. In most cases this entry is not required because the drivers will probe the hardware to determine the chipset type. Don't specify it unless the driver-specific documentation recommends that you do.

Ramdac "ramdac-type"
This optional entry specifies the type of RAMDAC used on the graphics board. This is only used by a few of the drivers, and in most cases it is not required because the drivers will probe the hardware to determine the RAMDAC type where possible. Don't specify it unless the driver-specific documentation recommends that you do.

DacSpeed speed
DacSpeed speed-8 speed-16 speed-24 speed-32
This optional entry specifies the RAMDAC speed rating (which is usually printed on the RAMDAC chip). The speed is in MHz. When one value is given, it applies to all framebuffer pixel sizes. When multiple values are give, they apply to the framebuffer pixel sizes 8, 16, 24 and 32 respectively. This is not used by many drivers, and only needs to be specified when the speed rating of the RAMDAC is different from the defaults built in to driver, or when the driver can't auto-detect the correct defaults. Don't specify it unless the driver-specific documentation recommends that you do.

Clocks clock ...
specifies the pixel that are on your graphics board. The clocks are in MHz, and may be specified as a floating point number. The value is stored internally to the nearest kHz. The ordering of the clocks is important. It must match the order in which they are selected on the graphics board. Multiple Clocks lines may be specified, and each is concatenated to form the list. Most drivers do not use this entry, and it is only required for some older boards with non-programmable clocks. Don't specify this entry unless the driver-specific documentation explicitly recommends that you do.

ClockChip "clockchip-type"
This optional entry is used to specify the clock chip type on graphics boards which have a programmable clock generator. Only a few Xorg drivers support programmable clock chips. For details, see the appropriate driver manual page.

VideoRam mem
This optional entry specifies the amount of video ram that is installed on the graphics board. This is measured in kBytes. In most cases this is not required because the Xorg server probes the graphics board to determine this quantity. The driver-specific documentation should indicate when it might be needed.

BiosBase baseaddress
This optional entry specifies the base address of the video BIOS for the VGA board. This address is normally auto-detected, and should only be specified if the driver-specific documentation recommends it.

MemBase baseaddress
This optional entry specifies the memory base address of a graphics board's linear frame buffer. This entry is not used by many drivers, and it should only be specified if the driver-specific documentation recommends it.

IOBase baseaddress
This optional entry specifies the IO base address. This entry is not used by many drivers, and it should only be specified if the driver-specific documentation recommends it.

ChipID id
This optional entry specifies a numerical ID representing the chip type. For PCI cards, it is usually the device ID. This can be used to override the auto-detection, but that should only be done when the driver-specific documentation recommends it.

ChipRev rev
This optional entry specifies the chip revision number. This can be used to override the auto-detection, but that should only be done when the driver-specific documentation recommends it.

TextClockFreq freq
This optional entry specifies the pixel clock frequency that is used for the regular text mode. The frequency is specified in MHz. This is rarely used.

Options
Option flags may be specified in the Device sections. These include driver-specific options and driver-independent options. The former are described in the driver-specific documentation. Some of the latter are described below in the section about the Screen section, and they may also be included here.

As we see in section 3.2.2.1 xf86readConfigFile() uses the following part of code to parse the "Device" section:

			else if (xf86nameCompare (val.str, "device") == 0)
			{
				xf86conffree(val.str);
				val.str = NULL;
				HANDLE_LIST (conf_device_lst, xf86parseDeviceSection,
							 XF86ConfDevicePtr);
			}

This calls xf86parseDeviceSection(), to fill XF86ConfDeviceRec. For instance the BusID option of the Device section of the xorg.conf is placed in the dev_busid field of XF86ConfDeviceRec with the following code snippet:

		case BUSID:
			if (xf86getSubToken (&(ptr->dev_comment)) != STRING)
				Error (QUOTE_MSG, "BusID");
			ptr->dev_busid = val.str;
			break;
As an example of BusID, consider for instance the following BusID values, as part of the xorg.conf found in 3 monitors, 2 graphics cards, 1 X:

Section "Device"
        Identifier  "G450"
        Driver      "mga"
        BusID       "PCI:1:0:0"
        Screen  0
EndSection

Section "Device"
        Identifier  "G450-1"
        Driver      "mga"
        BusID       "PCI:1:0:0"
        Screen  1
EndSection

Section "Device"
        Identifier      "9200SE"
        Driver          "radeon"
        BusID           "PCI:0:10:0"
EndSection

From the same page we see the lspci output:

00:0a.0 VGA compatible controller: ATI Technologies Inc RV280 [Radeon 9200 SE] (rev 01)
01:00.0 VGA compatible controller: Matrox Graphics, Inc. MGA G400 AGP (rev 82)

X wants these values in decimal, therefore 00:0a:0 will be entered as 0:10:0. 

Also from RadeonDriver we read: "BusID gives the hardware address of the graphics card (...) The BusID can be found using the command lspci. A BusID given in lspci as 01:00.0 will become "PCI:1:0:0" in xorg.conf".

It might be also helpfull to remind what BusID represents. From the xorg.conf man page we read:

BusID bus-id
     This specifies the bus location of the graphics card. For PCI/AGP cards, the bus-id string has the form PCI:bus:device:function (e.g., lqPCI:1:0:0rq might be appropriate for an AGP card). This field is usually optional in single-head configurations when using the primary graphics card. In multi-head configurations, or when using a secondary graphics card in a single-head configuration, this entry is mandatory. Its main purpose is to make an unambiguous connection between the device section and the hardware it is representing. This information can usually be found by running the pciaccess tool scanpci.

To summarise: the lspci (or a similar unix command) is used to find the BusID, which is used to fill the BusID field of xorg.conf, the value of which becomes then the dev_busid field of the XF86ConfDeviceRec struct in the source code of X Server. This struct is pointed by one of the fields of the main configuration struct for X, which is XF86ConfigRec.

Stage 2: General PCI probe

The general PCI probe was covered in section 3.2.2.3. The aim here is to fill xf86PciVideoInfo[], whose element type is a pointer to the following struct:

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;

Certainly some of the fields of pciVideoRec are identical with the ones of XF86ConfDeviceRec, we met at stage 1 previously.

Stage 3:

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;