Hands-on Projects for the Linux Graphics Subsystem
|
Modules specified in the config file and driver modules required by the X Server should by loaded at this stage. At xorg.conf man page we see a description of the "Module Section" and "Device Section" that include in the xorg.conf file the modules to be loaded. There is also an "Inputdevice Section" which includes the modules for the mouse and keyboard.
Consider for instance the following part of the xorg.conf:
Section "Module" Load "extmod" Load "glx" Load "dri" Load "dbe" Load "record" Load "xtrap" Load "type1" Load "freetype" EndSection Section "InputDevice" Identifier "Keyboard0" Driver "keyboard" Option "XkbRules" "xfree86" Option "XkbModel" "pc101" Option "XkbLayout" "us" EndSection Section "InputDevice" Identifier "Mouse0" Driver "mouse" Option "Device" "/dev/sysmouse" Option "Protocol" "auto" Option "ZAxisMapping" "4 5 6 7" EndSection Section "Device" Identifier "Card0" Driver "mga" VendorName "Matrox" BoardName "MGA G400 AGP" ChipSet "mgag400" BusID "PCI:1:0:0" Option "NoDDC" Option "AGPMode" "4" EndSection |
At the previous config file we see that the driver name is mga. The module loading stage is logged in /var/log/Xorg.0.log. At this file we find that the driver's module, mga_drv.so, is loaded along with the other modules:
(II) LoadModule: "extmod" (II) Loading /usr/local/lib/xorg/modules/extensions//libextmod.so (II) Module extmod: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.0.0 Module class: X.Org Server Extension ABI class: X.Org Server Extension, version 0.3 . . . (II) LoadModule: "glx" (II) Loading /usr/local/lib/xorg/modules/extensions//libglx.so (II) Module glx: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.0.0 ABI class: X.Org Server Extension, version 0.3 (==) AIGLX disabled (II) Loading extension GLX (II) LoadModule: "dri" (II) Loading /usr/local/lib/xorg/modules/extensions//libdri.so (II) Module dri: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.0.0 ABI class: X.Org Server Extension, version 0.3 (II) Loading extension XFree86-DRI (II) LoadModule: "dbe" (II) Loading /usr/local/lib/xorg/modules/extensions//libdbe.so (II) Module dbe: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.0.0 Module class: X.Org Server Extension ABI class: X.Org Server Extension, version 0.3 (II) Loading extension DOUBLE-BUFFER (II) LoadModule: "record" (II) Loading /usr/local/lib/xorg/modules/extensions//librecord.so (II) Module record: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.13.0 Module class: X.Org Server Extension ABI class: X.Org Server Extension, version 0.3 (II) Loading extension RECORD (II) LoadModule: "xtrap" (II) Loading /usr/local/lib/xorg/modules/extensions//libxtrap.so (II) Module xtrap: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.0.0 Module class: X.Org Server Extension ABI class: X.Org Server Extension, version 0.3 (II) Loading extension DEC-XTRAP (II) LoadModule: "type1" (II) Loading /usr/local/lib/xorg/modules/fonts//libtype1.so (II) Module type1: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.0.2 Module class: X.Org Font Renderer ABI class: X.Org Font Renderer, version 0.5 (II) Loading font Type1 (II) LoadModule: "freetype" (II) Loading /usr/local/lib/xorg/modules/fonts//libfreetype.so (II) Module freetype: vendor="X.Org Foundation & the After X-TT Project" compiled for 7.2.0, module version = 2.1.0 Module class: X.Org Font Renderer ABI class: X.Org Font Renderer, version 0.5 (II) Loading font FreeType (II) LoadModule: "mga" (II) Loading /usr/local/lib/xorg/modules/drivers//mga_drv.so (II) Module mga: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.4.6 Module class: X.Org Video Driver ABI class: X.Org Video Driver, version 1.1 (II) LoadModule: "mouse" (II) Loading /usr/local/lib/xorg/modules/input//mouse_drv.so (II) Module mouse: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.1.1 Module class: X.Org XInput Driver ABI class: X.Org XInput driver, version 0.7 (II) LoadModule: "keyboard" (II) Loading /usr/local/lib/xorg/modules/input//keyboard_drv.so (II) Module keyboard: vendor="X.Org Foundation" compiled for 7.2.0, module version = 1.0.0 Module class: X.Org XInput Driver ABI class: X.Org XInput driver, version 0.7 |
As we see the following modules, which are included in the "Module" section, are loaded first:
libextmod.so libglx.so libdri.so libdbe.so librecord.so libxtrap.so libtype1.so libfreetype.so
Then the modules of the video driver, found at the "Device" section, that is mga_drv.so is loaded next to be followed by the modules of the two "InputDevice" sections mouse_drv.so and keyboard_drv.so.
Each module is a Dynamically Linked "Shared Object" Libraries (.so) with a 'soname' (see Linux How-to) of the form lib<name>.so. Notice that a module can also call a submodule.
It certainly depends on many factors, for instance the module format (e.g. elf), the architecture (e.g. i386), the kind of the system the X server runs (32-bit or 64-bit), the number of the modules loaded, etc. To take a view from above we can read the Bactrace sections of the Xorg.0.log files from X serves that crashed. Such files can return a 'Backtrace Xorg.0.log' query from Google. Consider from instance the following example:
Backtrace: 0: /usr/bin/Xorg(xorg_backtrace+0x3c) [0x80a442c] 1: /usr/bin/Xorg [0x80a7c26] 2: [0x5ba40c] 3: /usr/lib/libpixman-1.so.0 [0x15be10] 4: /usr/lib/libpixman-1.so.0 [0x15c001] 5: /usr/lib/libpixman-1.so.0 [0x1275c4] 6: /usr/lib/libpixman-1.so.0(pixman_blt+0x79) [0x149aa9] 7: /usr/lib/xorg/modules/libfb.so(fbCopyNtoN+0x1aa) [0x291cca] 8: /usr/bin/Xorg(miCopyRegion+0x213) [0x818bf33] 9: /usr/bin/Xorg(miDoCopy+0x44d) [0x818c45d] 10: /usr/lib/xorg/modules/libfb.so(fbCopyArea+0x79) [0x2912b9] 11: /usr/lib/xorg/modules/libexa.so [0xc8d8b0] 12: /usr/lib/xorg/modules/libexa.so [0xc86d5e] 13: /usr/bin/Xorg(miCopyRegion+0x213) [0x818bf33] 14: /usr/bin/Xorg(miDoCopy+0x44d) [0x818c45d] 15: /usr/lib/xorg/modules/libexa.so [0xc851db] 16: /usr/bin/Xorg [0x811a894] 17: /usr/lib/xorg/modules/libfb.so(image_from_pict+0x332) [0x295982] 18: /usr/lib/xorg/modules/libfb.so(fbComposite+0xc4) [0x295c94] 19: /usr/lib/xorg/modules/libexa.so [0xc8e65b] 20: /usr/lib/xorg/modules/libexa.so [0xc8bd60] 21: /usr/bin/Xorg [0x81187d7] 22: /usr/bin/Xorg(CompositePicture+0x290) [0x810bf80] 23: /usr/bin/Xorg [0x80d17d8] 24: /usr/lib/xorg/modules/drivers/radeon_drv.so [0xe5a496] 25: /usr/bin/Xorg [0x81a87db] 26: /usr/bin/Xorg [0x80e572b] 27: /usr/bin/Xorg(BlockHandler+0x58) [0x8074278] 28: /usr/bin/Xorg(WaitForSomething+0x104) [0x80a1dd4] 29: /usr/bin/Xorg [0x806eb70] 30: /usr/bin/Xorg [0x8063115] 31: /lib/libc.so.6(__libc_start_main+0xe6) [0x5d1b36] |
A backtrace shows the thread the functions follow inside X server (appears as 'Xorg' in the previous list), from the last function run when the program was crashed, to the first. The last routine is xf86SigHandler(). This is the function registered for X server, in the case unexpected signals, e.g. SIGSEGV (see InitOutput()). Then xf86SigHandler() calls xorg_backtrace(), which calls backtrace_symbols(), which is described from the Linux backtrace_symbols man page.
The address returned from the backtrace belongs to the virtual address space of the current process, i.e. the X server (Xorg). We also notice that the X server runs in a 32-bit system (8 hex numbers, e.g 0xffffff). We find that in the virtual address space, which is dedicated to the X server alone, the server itself is loaded near the memory location 0x8070e8b and the mga_drv.so driver near 0xe7d075 if we use as example the next backtrace:
Backtrace: 0: Xorg(xf86SigHandler+0x81) [0x80ceb41] 1: [0x88b420] 2: /usr/lib/xorg/modules/drivers//mga_drv.so(MGAClientGetBiosInfo+0x7f) [0xe6ea9f] 3: /usr/lib/xorg/modules/drivers//mga_hal_drv.so(HSLGBIOSReadPins+0x12d) [0xfa05fd] 4: /usr/lib/xorg/modules/drivers//mga_hal_drv.so(HSLCONGGetPInSInfo+0x44) [0xfa37a4] 5: /usr/lib/xorg/modules/drivers//mga_hal_drv.so(HSLCONGGetBoardInfo+0x3c) [0xfa2a4c] 6: /usr/lib/xorg/modules/drivers//mga_hal_drv.so(HSLGInit+0x65) [0xf85e25] 7: /usr/lib/xorg/modules/drivers//mga_hal_drv.so(HALGGetBoardInfo+0xc8) [0xf84368] 8: /usr/lib/xorg/modules/drivers//mga_hal_drv.so(MATROXOpenLibrary+0x58) [0xf79be8] 9: /usr/lib/xorg/modules/drivers//mga_drv.so [0xe7d075] 10: Xorg(InitOutput+0x9a8) [0x80a2f68] 11: Xorg(main+0x27b) [0x8070e8b] 12: /lib/libc.so.6(__libc_start_main+0xe0) [0x17cf70] 13: Xorg(FontFileCompleteXLFD+0x1e1) [0x8070391] |
The following part of InitOutput() is responsible for loading the three categories of modules mentioned previously, that is the modules specified explicitly in the config file, video drivers and input drivers:
#ifdef XFree86LOADER /* Load all modules specified explicitly in the config file */ if ((modulelist = xf86ModulelistFromConfig(&optionlist))) { xf86LoadModules(modulelist, optionlist); xfree(modulelist); xfree(optionlist); } /* Load all driver modules specified in the config file */ if ((modulelist = xf86DriverlistFromConfig())) { xf86LoadModules(modulelist, NULL); xfree(modulelist); } #ifdef USE_DEPRECATED_KEYBOARD_DRIVER /* Setup the builtin input drivers */ xf86AddInputDriver(&XF86KEYBOARD, NULL, 0); #endif /* Load all input driver modules specified in the config file. */ if ((modulelist = xf86InputDriverlistFromConfig())) { xf86LoadModules(modulelist, NULL); xfree(modulelist); } /* * It is expected that xf86AddDriver()/xf86AddInputDriver will be * called for each driver as it is loaded. Those functions save the * module pointers for drivers. * XXX Nothing keeps track of them for other modules. */ /* XXX What do we do if not all of these could be loaded? */ #endif /* * At this point, xf86DriverList[] is all filled in with entries for * each of the drivers to try and xf86NumDrivers has the number of * drivers. If there are none, return now. */ if (xf86NumDrivers == 0) { xf86Msg(X_ERROR, "No drivers available.\n"); return; } |
The first part is for modules specified explicitly in the config file, then follows the video drivers part and the last one is the input drivers part:
if ((modulelist = xf86ModulelistFromConfig(&optionlist))) { xf86LoadModules(modulelist, optionlist); |
At xf86ModulelistFromConfig() as the comment indicates:
/* * use the datastructure that the parser provides and pick out the parts * that we need at this point */The data structure the parser prepares is:
conf_moduleswhich as explained in 3.2.2.1 is a field of the global struct XF86ConfigRec. conf_modules is actually of type XF86ConfModulePtr which is defined as:
typedef struct { XF86LoadPtr mod_load_lst; char *mod_comment; } XF86ConfModuleRec, *XF86ConfModulePtr; |
Therefore conf_modules->mod_load_lst is walked and the module names are returned and the module options update the routine's argument. For Module options see the xorg.conf man page.
xf86LoadModules() iterates over the list that is being passed as the first argument and for each module name calls LoadModule().
LoadModule() is called with the following arguments that are explained in loadmod.c:
/* * LoadModule: load a module * * module The module name. Normally this is not a filename but the * module's "canonical name. A full pathname is, however, * also accepted. * path A comma separated list of module directories. * subdirlist A NULL terminated list of subdirectories to search. When * NULL, the default "stdSubdirs" list is used. The default * list is also substituted for entries with value DEFAULT_LIST. * patternlist A NULL terminated list of regular expressions used to find * module filenames. Each regex should contain exactly one * subexpression that corresponds to the canonical module name. * When NULL, the default "stdPatterns" list is used. The * default list is also substituted for entries with value * DEFAULT_LIST. * options A NULL terminated list of Options that are passed to the * module's SetupProc function. * modreq An optional XF86ModReqInfo* containing * version/ABI/vendor-ABI requirements to check for when * loading the module. The following fields of the * XF86ModReqInfo struct are checked: * majorversion - must match the module's majorversion exactly * minorversion - the module's minorversion must be >= this * patchlevel - the module's minorversion.patchlevel must be * >= this. Patchlevel is ignored when * minorversion is not set. * abiclass - (string) must match the module's abiclass * abiversion - must be consistent with the module's * abiversion (major equal, minor no older) * moduleclass - string must match the module's moduleclass * string * "don't care" values are ~0 for numbers, and NULL for strings * errmaj Major error return. * errmin Minor error return. * */ |
LoadModule() calls LoaderOpen() as:
ret->handle = LoaderOpen(found, name, 0, errmaj, errmin, &wasLoaded); |
where ret is of type ModuleDescPtr:
typedef struct module_desc { struct module_desc *child; struct module_desc *sib; struct module_desc *parent; struct module_desc *demand_next; char *name; char *filename; char *identifier; XID client_id; int in_use; int handle; ModuleSetupProc SetupProc; ModuleTearDownProc TearDownProc; void *TearDownData; /* returned from SetupProc */ const char *path; const XF86ModuleVersionInfo *VersionInfo; } ModuleDesc, *ModuleDescPtr; |
Starting with Xorg 7.0, dlloader has become the default module loader for X (see this Gentoo link). LoaderOpen() calls therefore either the specific funcs[modtype].LoadModule routine for versions up to 6.9 or the DLLoadModule() for version 7.0 or latter.
LoaderOpen() opens the module as:
LoaderOpen() calls _GetModuleType() to return the Module type at modtype:
If for instance the module object is ELF it returns LD_ELFOBJECT. _GetModuleType() does this by comparing the magic number of the ELF file header with the module's header data. The elf magic number is the hex 7f 45 4c 46 which stands in ascii for 7fELF. It is defined in elf.h as:
For more info on ELF see for instance this page. Next tmp of type loaderPtr is used to store info about the module:
_LoaderListPush() returns tmp, a static loaderPtr. It is defined in loader.h as:
where _loader is found in the same file as:
Next the LoadModule specific routine for the current module is called as:
The funcs[] item that provide the LoadModule is found at position 'modtype', which for our previous example was LD_ELFOBJECT (1). Looking therefore at the first position in funcs[] we find that LoadModule becomes ELFLoadModule:
After the specific LoadModule, e.g. ELFLoadModule() returns, LoaderOpen() calls LoaderAddSymbols() to add the symbols obtained from ELFLoadModule() to its pLookup array:
On return from LoaderOpen() the LoadModule() checks if the special data object <modulename>ModuleData is present. Therefore the following instructions are executed:
LoaderSymbol() calls the specific funcs[] member ResolveSymbols() routine, which for the example we follow is ELFResolveSymbols() and then calls LoaderHashFind() to return the address of the symbol that was passed as argument. Therefore on success the address of struct <ModuleName>ModuleData is found. The address is returned to initdata, which is a pointer to a XF86ModuleData struct:
Next some of the ret fields are filled and if there is a module setup routine it is executed.
|
In the realm of xorg version 7.0 and latter LoadModule() calls DoLoadModule() and this LoaderOpen(). LoaderOpen() calls DLLoadModule() and this dlopen() as:
dlfile->dlhandle = dlopen(modrec->name, dlopen_flags); |
A description of dlopen() is found in this man page. Also dlopen() is described in the Program Library HOWTO.
dlopen() is part of libdl, which allows manual dynamic linking. Also libdl is part of glibc. For instance for Debian Linux (see this link) we run dpkg-query as:
$ dpkg-query -S /lib/libdl-2.3.2.so libc6: /lib/libdl-2.3.2.so The source code of function dlopen() is found in the archives of glibc, by downloading via ftp a glibc archieve from the Index of /gnu/glibc, found at this gnu.org page, and then opening file dl-open.c. |
As we read from Dynamic Link library support for the Linux OS:
Function: void *dlopen ( const char filename, int flags )
This function opens the dynamic library specified by filename and returns an abstract handle, which can be used in subsequent calls to dlsym. |
A nice code example of how the dl interface is used comes from Shared Library Mini-Tutorial:
int main() { void * my_lib_handle; int (*some_func)(); my_lib_handle = dlopen("libmylib.so",RTLD_NOW); if(my_lib_handle==NULL) { /* ERROR HANDLING */ } some_func = (int (*)()) dlsym(my_lib_handle,"some_function"); if(some_func==NULL) { /* ERROR HANDLING */ } printf("Return code is %i\n",(*some_func)()); return 0; } |
doLoadModule() calls also LoaderSymbol(), which calls DLFindSymbol() and this DLFindSymbolLocal(). The latter is an encapsulation of dlsym(), which finds a symbol within the given shared library handle, passed as the first argument and returns a pointer to it. LoaderSymbol() is called in the following part of code:
/* * now check if the special data object |
Therefore a pointer to the
Next the module's setup routine runs in DoLoadModule() as:
We continue here from the last important point of LoadModule() for the Old versions examined in Case I or of doLoadModule() for the New versions, examined in Case II, that is where the SetupProc() is called:
The important steps at this stage are the following:
This is described in the previous paragraphs.
Loading a module, e.g. a video driver is one part. The other thing of interest at this point is its initialization. Finding the setup routine that does the job is straightforward when reading the source code however it is more complicated in run time when there is a binary executable, e.g. an with ELF format, which provides the addresses of its routines only by processing its header file.
Locating the setup routine requires to anchor first the XF86ModuleData struct in the module that includes it. From The XFree86 Architecture article we read:
The mga video driver source code, used as example in the previous article can be found by following Xorg's cvs or cgit sites. At mga_driver.c we find MGA_MODULE_DATA, which is resolved to mgaModuleData in mga.h .
Again from the The XFree86 Architecture article we read for mgaModuleData:
The setup routine called from LoadModule() for the mga video driver, which we use here as a case study, is therefore found in mga_driver.c as:
Notice: this step depends on the video driver. Function setup() could be different in many points to other drivers.
xf86AddDriver is called from the Module's setup() routine to add the driver's DriverRec to the global xf86DriverList[]:
DriverPtr is defined in xf86str.h as:
xf86DriverList is defined in xf86Globals.c as:
Each time xf86AddDriver() adds a driver to xf86DriverList[] the number of the array's items, xf86NumDrivers, is updated.
For the example we use in this sections, originated by this xorg.conf the DriverRec that xf86AddDriver() adds to xf86DriverList[] has the following format:
Since this was provided by the MGA_C_NAME DriverRec:
Notice that the value of driverFunc is provided by xf86AddDriver().
module is of type ModuleDescPtr. It points for the current example to the following ModuleDesc struct (created by LoadModule()):
As we previously saw mgaVersRec is:
Available in Amazon Kindle format at:
amazon.com
amazon.co.uk
amazon.de
amazon.es
amazon.fr
amazon.it
typedef struct {
XF86ModuleVersionInfo * vers;
ModuleSetupProc setup;
ModuleTearDownProc teardown;
} XF86ModuleData;
if (setup)
ret->SetupProc = setup;
. . .
if (ret->SetupProc) {
ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin);
ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin);
Module processing
Step 1: the Module gets loaded
Step 2: The Module's setup() routine is located and then is called
In order to hook the module into the server, right after opening a module (and
before the relocation of any symbols) the server will be looking for a data
entry called <ModuleName>ModuleData. For example, Mark Vojkovich's Matrox module
(mgaModuleData) is used below:
static MODULESETUPPROTO(mgaSetup);
static XF86ModuleVersionInfo mgaVersRec =
{
MGA_DRIVER_NAME,
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XORG_VERSION_CURRENT,
MGA_MAJOR_VERSION, MGA_MINOR_VERSION, MGA_PATCHLEVEL,
ABI_CLASS_VIDEODRV, /* This is a video driver */
ABI_VIDEODRV_VERSION,
MOD_CLASS_VIDEODRV,
{0,0,0,0}
};
_X_EXPORT XF86ModuleData MGA_MODULE_DATA = { &mgaVersRec, mgaSetup, NULL };
This structure includes versioning information, as well as function pointers
that the server binary calls to initialize and (in case it is unloaded)
de-initialize the module. The setup function is very important when you are
planning to write a driver. This is the function that hooks the new driver into
the server data structures and, therefore, makes the functionality of the driver
available. Again, the Matrox driver gives a good example.
The important part (after making sure that this function is only called once) is
to add a structure describing the driver to the list of drivers using
xf86AddDriver(). The DriverRec structure that is passed to xf86AddDriver()
contains version and naming information on this driver, plus three function
pointers: a function which can be used to print out the name of this driver, a
function which allows this driver to probe for the hardware it supports, and a
function which lists the option names (in the configuration file) this driver
recognizes.
With these functions the server can now announce that it has loaded this module,
parse the corresponding part of the configuration file, and finally ask the
module to probe for supported hardware. If the module recognizes hardware in the
system that it supports, it then will create the full set of data structures
that are needed for an XFree86 graphics card driver.
static pointer
mgaSetup(pointer module, pointer opts, int *errmaj, int *errmin)
{
static Bool setupDone = FALSE;
/* This module should be loaded only once, but check to be sure. */
if (!setupDone) {
setupDone = TRUE;
xf86AddDriver(&MGA_C_NAME, module, 0);
/*
* Modules that this driver always requires may be loaded here
* by calling LoadSubModule().
*/
/*
* Tell the loader about symbols from other modules that this module
* might refer to.
*/
LoaderRefSymLists(vgahwSymbols, xaaSymbols,
xf8_32bppSymbols, ramdacSymbols,
ddcSymbols, i2cSymbols, shadowSymbols,
fbdevHWSymbols, vbeSymbols,
fbSymbols, int10Symbols,
#ifdef XF86DRI
drmSymbols, driSymbols,
#endif
#ifdef USEMGAHAL
halSymbols,
#endif
NULL);
/*
* The return value must be non-NULL on success even though there
* is no TearDownProc.
*/
return (pointer)1;
} else {
if (errmaj) *errmaj = LDR_ONCEONLY;
return NULL;
}
}
Step 3: the Module's setup() routine calls xf86AddDriver()
void
xf86AddDriver(DriverPtr driver, pointer module, int flags)
{
/* Don't add null entries */
if (!driver)
return;
if (xf86DriverList == NULL)
xf86NumDrivers = 0;
xf86NumDrivers++;
xf86DriverList = xnfrealloc(xf86DriverList,
xf86NumDrivers * sizeof(DriverPtr));
xf86DriverList[xf86NumDrivers - 1] = xnfalloc(sizeof(DriverRec));
if (flags & HaveDriverFuncs)
*xf86DriverList[xf86NumDrivers - 1] = *driver;
else {
memcpy(xf86DriverList[xf86NumDrivers - 1], driver, sizeof(DriverRec1));
xf86DriverList[xf86NumDrivers - 1]->driverFunc = NULL;
}
xf86DriverList[xf86NumDrivers - 1]->module = module;
xf86DriverList[xf86NumDrivers - 1]->refCount = 0;
}
typedef struct _DriverRec {
int driverVersion;
char * driverName;
void (*Identify)(int flags);
Bool (*Probe)(struct _DriverRec *drv, int flags);
const OptionInfoRec * (*AvailableOptions)(int chipid, int bustype);
pointer module;
int refCount;
xorgDriverFuncProc *driverFunc;
} DriverRec, *DriverPtr;
DriverPtr *xf86DriverList = NULL;
Example
DriverRec for mga driver driverVersion MGA_VERSION driverName MGA_DRIVER_NAME (*Identify)(int flags) MGAIdentify() (*Probe)(struct _DriverRec *drv, int flags) MGAProbe() (*AvailableOptions)(int chipid, int bustype) MGAAvailableOptions module ModuleDescPtr to the ModuleDesc of the next table refCount 0 driverFunc NULL
_X_EXPORT DriverRec MGA_C_NAME = {
MGA_VERSION,
MGA_DRIVER_NAME,
MGAIdentify,
MGAProbe,
MGAAvailableOptions,
NULL,
0
};
name filename identifier SetupProc mgaSetup TearDownProc NULL path VersionInfo &mgaVersRec
static XF86ModuleVersionInfo mgaVersRec =
{
MGA_DRIVER_NAME,
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XORG_VERSION_CURRENT,
MGA_MAJOR_VERSION, MGA_MINOR_VERSION, MGA_PATCHLEVEL,
ABI_CLASS_VIDEODRV, /* This is a video driver */
ABI_VIDEODRV_VERSION,
MOD_CLASS_VIDEODRV,
{0,0,0,0}
};
Hands-on Projects for the Linux Graphics Subsystem