NOTE: some parts of this are not up to date
The following is an outline for writing a basic unaccelerated driver for a PCI video card with a linear mapped framebuffer, and which has a VGA core. It is includes some general information that is relevant to most drivers (even those which don't fit that basic description).
The information here is based on the initial conversion of the Matrox Millennium driver to the ``new design''. For a fleshing out and sample implementation of some of the bits outlined here, refer to that driver. Note that this is an example only. The approach used here will not be appropriate for all drivers.
Each driver must reserve a unique driver name, and a string that is used to prefix all of its externally visible symbols. This is to avoid name space clashes when loading multiple drivers. The examples here are for the ``ZZZ'' driver, which uses the ``ZZZ'' or ``zzz'' prefix for its externally visible symbols.
All drivers normally include the following headers:
"xf86.h"
"xf86_OSproc.h"
"xf86_ansic.h"
"xf86Resources.h"
Wherever inb/outb (and related things) are used the following should be
included:
"compiler.h"
Note: in drivers, this must be included after "xf86_ansic.h"
.
Drivers that need to access PCI vendor/device definitions need this:
"xf86PciInfo.h"
Drivers that need to access the PCI config space need this:
"xf86Pci.h"
Drivers using the mi banking wrapper need:
"mibank.h"
Drivers that initialise a SW cursor need this:
"mipointer.h"
All drivers implementing backing store need this:
"mibstore.h"
All drivers using the mi colourmap code need this:
"micmap.h"
If a driver uses the vgahw module, it needs this:
"vgaHW.h"
Drivers supporting VGA or Hercules monochrome screens need:
"xf1bpp.h"
Drivers supporting VGA or EGC 16-colour screens need:
"xf4bpp.h"
Drivers using cfb need:
#define PSZ 8
#include "cfb.h"
#undef PSZ
Drivers supporting bpp 16, 24 or 32 with cfb need one or more of:
"cfb16.h"
"cfb24.h"
"cfb32.h"
The driver's own header file:
"zzz.h"
Drivers must NOT include the following:
"xf86Priv.h"
"xf86Privstr.h"
"xf86_libc.h"
"xf86_OSlib.h"
"Xos.h"
any OS header
#define VERSION <version-as-an-int> #define ZZZ_NAME "ZZZ" /* the name used to prefix messages */ #define ZZZ_DRIVER_NAME "zzz" /* the driver name as used in config file */ #define ZZZ_MAJOR_VERSION <int> #define ZZZ_MINOR_VERSION <int> #define ZZZ_PATCHLEVEL <int>
NOTE: ZZZ_DRIVER_NAME
should match the name of the
driver module without things like the "lib" prefix, the "_drv" suffix
or filename extensions.
DriverRec ZZZ = { VERSION, ZZZ_DRIVER_NAME, ZZZIdentify, ZZZProbe, ZZZAvailableOptions, NULL, 0 };
static SymTabRec ZZZChipsets[] = { { PCI_CHIP_ZZZ1234, "zzz1234a" }, { PCI_CHIP_ZZZ5678, "zzz5678a" }, { -1, NULL } };
The token field may be any integer value that the driver may use to
uniquely identify the supported chipsets. For drivers that support
only PCI devices using the PCI device IDs might be a natural choice,
but this isn't mandatory. For drivers that support both PCI and other
devices (like ISA), some other ID should probably used. When other
IDs are used as the tokens it is recommended that the names be
defined as an enum
type.
xf86MatchPciInstances(
)
helper (recommended for drivers that support PCI cards) a list that
maps PCI IDs to chip IDs and fixed resources must be defined:
static PciChipsets ZZZPciChipsets[] = { { PCI_CHIP_ZZZ1234, PCI_CHIP_ZZZ1234, RES_SHARED_VGA }, { PCI_CHIP_ZZZ5678, PCI_CHIP_ZZZ5678, RES_SHARED_VGA }, { -1, -1, RES_UNDEFINED } }
XF86ModuleVersionInfo
struct for the
driver. This is required for the dynamically loaded version:
#ifdef XFree86LOADER static XF86ModuleVersionInfo zzzVersRec = { "zzz", MODULEVENDORSTRING, MODINFOSTRING1, MODINFOSTRING2, XF86_VERSION_CURRENT, ZZZ_MAJOR_VERSION, ZZZ_MINOR_VERSION, ZZZ_PATCHLEVEL, ABI_CLASS_VIDEODRV, ABI_VIDEODRV_VERSION, MOD_CLASS_VIDEODRV, {0,0,0,0} }; #endif
"zzz.h"
file, something like:
typedef struct { type1 field1; type2 field2; int fooHack; Bool pciRetry; Bool noAccel; Bool hwCursor; CloseScreenProcPtr CloseScreen; OptionInfoPtr Options; ... } ZZZRec, *ZZZPtr;
typedef enum { OPTION_FOO_HACK, OPTION_PCI_RETRY, OPTION_HW_CURSOR, OPTION_NOACCEL } ZZZOpts; static const OptionInfoRec ZZZOptions[] = { { OPTION_FOO_HACK, "FooHack", OPTV_INTEGER, {0}, FALSE }, { OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } };
For dynamically loaded modules, a ModuleData
variable is required. It is should be the name of the driver
prepended to "ModuleData". A Setup()
function is
also required, which calls xf86AddDriver()
to add
the driver to the main list of drivers.
#ifdef XFree86LOADER static MODULESETUPPROTO(mgaSetup); XF86ModuleData zzzModuleData = { &zzzVersRec, zzzSetup, NULL }; static pointer zzzSetup(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) { /* * Modules that this driver always requires may be loaded * here by calling LoadSubModule(). */ setupDone = TRUE; xf86AddDriver(&MGA, module, 0); /* * 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; } } #endif
A function is usually required to allocate the driver's
screen-specific data structure and hook it into the
ScrnInfoRec
's driverPrivate
field.
The ScrnInfoRec
's driverPrivate
is
initialised to NULL
, so it is easy to check if the
initialisation has already been done. After allocating it, initialise
the fields. By using xnfcalloc()
to do the allocation
it is zeroed, and if the allocation fails the server exits.
NOTE: When allocating structures from inside the driver which are defined on the common level it is important to initialize the structure to zero. Only this guarantees that the server remains source compatible to future changes in common level structures.
static Bool ZZZGetRec(ScrnInfoPtr pScrn) { if (pScrn->driverPrivate != NULL) return TRUE; pScrn->driverPrivate = xnfcalloc(sizeof(ZZZRec), 1); /* Initialise as required */ ... return TRUE; }
Define a macro in "zzz.h"
which gets a pointer to
the ZZZRec
when given pScrn
:
#define ZZZPTR(p) ((ZZZPtr)((p)->driverPrivate))
Define a function to free the above, setting it to NULL
once it has been freed:
static void ZZZFreeRec(ScrnInfoPtr pScrn) { if (pScrn->driverPrivate == NULL) return; xfree(pScrn->driverPrivate); pScrn->driverPrivate = NULL; }
Define the Identify()
function. It is run before
the Probe, and typically prints out an identifying message, which
might include the chipsets it supports. This function is mandatory:
static void ZZZIdentify(int flags) { xf86PrintChipsets(ZZZ_NAME, "driver for ZZZ Tech chipsets", ZZZChipsets); }
Define the Probe()
function. The purpose of this
is to find all instances of the hardware that the driver supports,
and for the ones not already claimed by another driver, claim the
slot, and allocate a ScrnInfoRec
. This should be
a minimal probe, and it should under no circumstances leave the
state of the hardware changed. Because a device is found, don't
assume that it will be used. Don't do any initialisations other
than the required ScrnInfoRec
initialisations.
Don't allocate any new data structures.
This function is mandatory.
NOTE: The xf86DrvMsg()
functions cannot be used from
the Probe.
static Bool ZZZProbe(DriverPtr drv, int flags) { Bool foundScreen = FALSE; int numDevSections, numUsed; GDevPtr *devSections; int *usedChips; int i; /* * Find the config file Device sections that match this * driver, and return if there are none. */ if ((numDevSections = xf86MatchDevice(ZZZ_DRIVER_NAME, &devSections)) <= 0) { return FALSE; } /* * Since this is a PCI card, "probing" just amounts to checking * the PCI data that the server has already collected. If there * is none, return. * * Although the config file is allowed to override things, it * is reasonable to not allow it to override the detection * of no PCI video cards. * * The provided xf86MatchPciInstances() helper takes care of * the details. */ /* test if PCI bus present */ if (xf86GetPciVideoInfo()) { numUsed = xf86MatchPciInstances(ZZZ_NAME, PCI_VENDOR_ZZZ, ZZZChipsets, ZZZPciChipsets, devSections, numDevSections, drv, &usedChips); for (i = 0; i < numUsed; i++) { ScrnInfoPtr pScrn = NULL; if ((pScrn = xf86ConfigPciEntity(pScrn, flags, usedChips[i], ZZZPciChipsets, NULL, NULL, NULL, NULL, NULL))) { /* Allocate a ScrnInfoRec */ pScrn->driverVersion = VERSION; pScrn->driverName = ZZZ_DRIVER_NAME; pScrn->name = ZZZ_NAME; pScrn->Probe = ZZZProbe; pScrn->PreInit = ZZZPreInit; pScrn->ScreenInit = ZZZScreenInit; pScrn->SwitchMode = ZZZSwitchMode; pScrn->AdjustFrame = ZZZAdjustFrame; pScrn->EnterVT = ZZZEnterVT; pScrn->LeaveVT = ZZZLeaveVT; pScrn->FreeScreen = ZZZFreeScreen; pScrn->ValidMode = ZZZValidMode; foundScreen = TRUE; /* add screen to entity */ } } xfree(usedChips); } #ifdef HAS_ISA_DEVS /* * If the driver supports ISA hardware, the following block * can be included too. */ numUsed = xf86MatchIsaInstances(ZZZ_NAME, ZZZChipsets, ZZZIsaChipsets, drv, ZZZFindIsaDevice, devSections, numDevSections, &usedChips); for (i = 0; i < numUsed; i++) { ScrnInfoPtr pScrn = NULL; if ((pScrn = xf86ConfigIsaEntity(pScrn, flags, usedChips[i], ZZZIsaChipsets, NULL, NULL, NULL, NULL, NULL))) { pScrn->driverVersion = VERSION; pScrn->driverName = ZZZ_DRIVER_NAME; pScrn->name = ZZZ_NAME; pScrn->Probe = ZZZProbe; pScrn->PreInit = ZZZPreInit; pScrn->ScreenInit = ZZZScreenInit; pScrn->SwitchMode = ZZZSwitchMode; pScrn->AdjustFrame = ZZZAdjustFrame; pScrn->EnterVT = ZZZEnterVT; pScrn->LeaveVT = ZZZLeaveVT; pScrn->FreeScreen = ZZZFreeScreen; pScrn->ValidMode = ZZZValidMode; foundScreen = TRUE; } } xfree(usedChips); #endif /* HAS_ISA_DEVS */ xfree(devSections); return foundScreen;
Define the AvailableOptions()
function. The purpose
of this is to return the available driver options back to the
-configure option, so that an XF86Config file can be built and the
user can see which options are available for them to use.
Define the PreInit()
function. The purpose of
this is to find all the information required to determine if the
configuration is usable, and to initialise those parts of the
ScrnInfoRec
that can be set once at the beginning
of the first server generation. The information should be found in
the least intrusive way possible.
This function is mandatory.
NOTES:
PreInit()
function is only called once
during the life of the X server (at the start of the first
generation).
ScrnInfoRec
's privates
field should be allocated here, but data that hooks into the
ScreenRec
's devPrivates
field
should not be allocated here. The driverPrivate
field should also be allocated here.
ScrnInfoRec
has been allocated
before this function is called, the ScreenRec
has not been allocated. That means that things requiring it
cannot be used in this function.
ScrnInfoRec
has been
initialised when this function is called. It is important to
get the order of doing things right in this function.
static Bool ZZZPreInit(ScrnInfoPtr pScrn, int flags) { /* Fill in the monitor field */ pScrn->monitor = pScrn->confScreen->monitor; /* * If using the vgahw module, it will typically be loaded * here by calling xf86LoadSubModule(pScrn, "vgahw"); */ /* * Set the depth/bpp. Our preferred default depth/bpp is 8, and * we support both 24bpp and 32bpp framebuffer layouts. * This sets pScrn->display also. */ if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb | Support32bppFb)) { return FALSE; } else { if (depth/bpp isn't one we support) { print error message; return FALSE; } } /* Print out the depth/bpp that was set */ xf86PrintDepthBpp(pScrn); /* Set bits per RGB for 8bpp */ if (pScrn->depth <= 8) { /* Take into account a dac_6_bit option here */ pScrn->rgbBits = 6 or 8; } /* * xf86SetWeight() and xf86SetDefaultVisual() must be called * after pScrn->display is initialised. */ /* Set weight/mask/offset for depth > 8 */ if (pScrn->depth > 8) { if (!xf86SetWeight(pScrn, defaultWeight, defaultMask)) { return FALSE; } else { if (weight isn't one we support) { print error message; return FALSE; } } } /* Set the default visual. */ if (!xf86SetDefaultVisual(pScrn, -1)) { return FALSE; } else { if (visual isn't one we support) { print error message; return FALSE; } } /* If the driver supports gamma correction, set the gamma. */ if (!xf86SetGamma(pScrn, default_gamma)) { return FALSE; } /* This driver uses a programmable clock */ pScrn->progClock = TRUE; /* Allocate the ZZZRec driverPrivate */ if (!ZZZGetRec(pScrn)) { return FALSE; } pZzz = ZZZPTR(pScrn); /* Collect all of the option flags (fill in pScrn->options) */ xf86CollectOptions(pScrn, NULL); /* * Process the options based on the information in ZZZOptions. * The results are written to pZzz->Options. If all of the options * processing is done within this function a local variable "options" * can be used instead of pZzz->Options. */ if (!(pZzz->Options = xalloc(sizeof(ZZZOptions)))) return FALSE; (void)memcpy(pZzz->Options, ZZZOptions, sizeof(ZZZOptions)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pZzz->Options); /* * Set various fields of ScrnInfoRec and/or ZZZRec based on * the options found. */ from = X_DEFAULT; pZzz->hwCursor = FALSE; if (xf86IsOptionSet(pZzz->Options, OPTION_HW_CURSOR)) { from = X_CONFIG; pZzz->hwCursor = TRUE; } xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n", pZzz->hwCursor ? "HW" : "SW"); if (xf86IsOptionSet(pZzz->Options, OPTION_NOACCEL)) { pZzz->noAccel = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n"); } else { pZzz->noAccel = FALSE; } if (xf86IsOptionSet(pZzz->Options, OPTION_PCI_RETRY)) { pZzz->UsePCIRetry = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n"); } pZzz->fooHack = 0; if (xf86GetOptValInteger(pZzz->Options, OPTION_FOO_HACK, &pZzz->fooHack)) { xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Foo Hack set to %d\n", pZzz->fooHack); } /* * Find the PCI slot(s) that this screen claimed in the probe. * In this case, exactly one is expected, so complain otherwise. * Note in this case we're not interested in the card types so * that parameter is set to NULL. */ if ((i = xf86GetPciInfoForScreen(pScrn->scrnIndex, &pciList, NULL)) != 1) { print error message; ZZZFreeRec(pScrn); if (i > 0) xfree(pciList); return FALSE; } /* Note that pciList should be freed below when no longer needed */ /* * Determine the chipset, allowing config file chipset and * chipid values to override the probed information. The config * chipset value has precedence over its chipid value if both * are present. * * It isn't necessary to fill in pScrn->chipset if the driver * keeps track of the chipset in its ZZZRec. */ ... /* * Determine video memory, fb base address, I/O addresses, etc, * allowing the config file to override probed values. * * Set the appropriate pScrn fields (videoRam is probably the * most important one that other code might require), and * print out the settings. */ ... /* Initialise a clockRanges list. */ ... /* Set any other chipset specific things in the ZZZRec */ ... /* Select valid modes from those available */ i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, pScrn->display->modes, clockRanges, NULL, minPitch, maxPitch, rounding, minHeight, maxHeight, pScrn->display->virtualX, pScrn->display->virtualY, pScrn->videoRam * 1024, LOOKUP_BEST_REFRESH); if (i == -1) { ZZZFreeRec(pScrn); return FALSE; } /* Prune the modes marked as invalid */ xf86PruneDriverModes(pScrn); /* If no valid modes, return */ if (i == 0 || pScrn->modes == NULL) { print error message; ZZZFreeRec(pScrn); return FALSE; } /* * Initialise the CRTC fields for the modes. This driver expects * vertical values to be halved for interlaced modes. */ xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V); /* Set the current mode to the first in the list. */ pScrn->currentMode = pScrn->modes; /* Print the list of modes being used. */ xf86PrintModes(pScrn); /* Set the DPI */ xf86SetDpi(pScrn, 0, 0); /* Load bpp-specific modules */ switch (pScrn->bitsPerPixel) { case 1: mod = "xf1bpp"; break; case 4: mod = "xf4bpp"; break; case 8: mod = "cfb"; break; case 16: mod = "cfb16"; break; case 24: mod = "cfb24"; break; case 32: mod = "cfb32"; break; } if (mod && !xf86LoadSubModule(pScrn, mod)) ZZZFreeRec(pScrn); return FALSE; /* Load XAA if needed */ if (!pZzz->noAccel || pZzz->hwCursor) if (!xf86LoadSubModule(pScrn, "xaa")) { ZZZFreeRec(pScrn); return FALSE; } /* Done */ return TRUE; }
Define functions to map and unmap the video memory and any other memory apertures required. These functions are not mandatory, but it is often useful to have such functions.
static Bool ZZZMapMem(ScrnInfoPtr pScrn) { /* Call xf86MapPciMem() to map each PCI memory area */ ... return TRUE or FALSE; } static Bool ZZZUnmapMem(ScrnInfoPtr pScrn) { /* Call xf86UnMapVidMem() to unmap each memory area */ ... return TRUE or FALSE; }
Define functions to save and restore the original video state. These functions are not mandatory, but are often useful.
static void ZZZSave(ScrnInfoPtr pScrn) { /* * Save state into per-screen data structures. * If using the vgahw module, vgaHWSave will typically be * called here. */ ... } static void ZZZRestore(ScrnInfoPtr pScrn) { /* * Restore state from per-screen data structures. * If using the vgahw module, vgaHWRestore will typically be * called here. */ ... }
Define a function to initialise a new video mode. This function isn't mandatory, but is often useful.
static Bool ZZZModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) { /* * Program a video mode. If using the vgahw module, * vgaHWInit and vgaRestore will typically be called here. * Once up to the point where there can't be a failure * set pScrn->vtSema to TRUE. */ ... }
Define the ScreenInit()
function. This is called
at the start of each server generation, and should fill in as much
of the ScreenRec
as possible as well as any other
data that is initialised once per generation. It should initialise
the framebuffer layers it is using, and initialise the initial video
mode.
This function is mandatory.
NOTE: The ScreenRec
(pScreen
) is
passed to this driver, but it and the
ScrnInfoRecs
are not yet hooked into each
other. This means that in this function, and functions it
calls, one cannot be found from the other.
static Bool ZZZScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { /* Get the ScrnInfoRec */ pScrn = xf86Screens[pScreen->myNum]; /* * If using the vgahw module, its data structures and related * things are typically initialised/mapped here. */ /* Save the current video state */ ZZZSave(pScrn); /* Initialise the first mode */ ZZZModeInit(pScrn, pScrn->currentMode); /* Set the viewport if supported */ ZZZAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); /* * Setup the screen's visuals, and initialise the framebuffer * code. */ /* Reset the visual list */ miClearVisualTypes(); /* * Setup the visuals supported. This driver only supports * TrueColor for bpp > 8, so the default set of visuals isn't * acceptable. To deal with this, call miSetVisualTypes with * the appropriate visual mask. */ if (pScrn->bitsPerPixel > 8) { if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; } else { if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), pScrn->rgbBits, pScrn->defaultVisual)) return FALSE; } /* * Initialise the framebuffer. */ switch (pScrn->bitsPerPixel) { case 1: ret = xf1bppScreenInit(pScreen, FbBase, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth); break; case 4: ret = xf4bppScreenInit(pScreen, FbBase, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth); break; case 8: ret = cfbScreenInit(pScreen, FbBase, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth); break; case 16: ret = cfb16ScreenInit(pScreen, FbBase, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth); break; case 24: ret = cfb24ScreenInit(pScreen, FbBase, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth); break; case 32: ret = cfb32ScreenInit(pScreen, FbBase, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth); break; default: print a message about an internal error; ret = FALSE; break; } if (!ret) return FALSE; /* Override the default mask/offset settings */ if (pScrn->bitsPerPixel > 8) { for (i = 0, visual = pScreen->visuals; i < pScreen->numVisuals; i++, visual++) { if ((visual->class | DynamicClass) == DirectColor) { visual->offsetRed = pScrn->offset.red; visual->offsetGreen = pScrn->offset.green; visual->offsetBlue = pScrn->offset.blue; visual->redMask = pScrn->mask.red; visual->greenMask = pScrn->mask.green; visual->blueMask = pScrn->mask.blue; } } } /* * If banking is needed, initialise an miBankInfoRec (defined in * "mibank.h"), and call miInitializeBanking(). */ if (!miInitializeBanking(pScreen, pScrn->virtualX, pScrn->virtualY, pScrn->displayWidth, pBankInfo)) return FALSE; /* * If backing store is to be supported (as is usually the case), * initialise it. */ miInitializeBackingStore(pScreen); /* * Set initial black & white colourmap indices. */ xf86SetBlackWhitePixels(pScreen); /* * Install colourmap functions. If using the vgahw module, * vgaHandleColormaps would usually be called here. */ ... /* * Initialise cursor functions. This example is for the mi * software cursor. */ miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); /* Initialise the default colourmap */ switch (pScrn->depth) { case 1: if (!xf1bppCreateDefColormap(pScreen)) return FALSE; break; case 4: if (!xf4bppCreateDefColormap(pScreen)) return FALSE; break; default: if (!cfbCreateDefColormap(pScreen)) return FALSE; break; } /* * Wrap the CloseScreen vector and set SaveScreen. */ ZZZPTR(pScrn)->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = ZZZCloseScreen; pScreen->SaveScreen = ZZZSaveScreen; /* Report any unused options (only for the first generation) */ if (serverGeneration == 1) { xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); } /* Done */ return TRUE; }
Define the SwitchMode()
function if mode switching
is supported by the driver.
static Bool ZZZSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { return ZZZModeInit(xf86Screens[scrnIndex], mode); }
Define the AdjustFrame()
function if the driver
supports this.
static void ZZZAdjustFrame(int scrnIndex, int x, int y, int flags) { /* Adjust the viewport */ }
Define the EnterVT()
and LeaveVT()
functions.
These functions are mandatory.
static Bool ZZZEnterVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; return ZZZModeInit(pScrn, pScrn->currentMode); } static void ZZZLeaveVT(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; ZZZRestore(pScrn); }
Define the CloseScreen()
function:
This function is mandatory. Note that it unwraps the previously
wrapped pScreen->CloseScreen
, and finishes by
calling it.
static Bool ZZZCloseScreen(int scrnIndex, ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; if (pScrn->vtSema) { ZZZRestore(pScrn); ZZZUnmapMem(pScrn); } pScrn->vtSema = FALSE; pScreen->CloseScreen = ZZZPTR(pScrn)->CloseScreen; return (*pScreen->CloseScreen)(scrnIndex, pScreen); }
Define the SaveScreen()
function (the screen
blanking function). When using the vgahw module, this will typically
be:
static Bool ZZZSaveScreen(ScreenPtr pScreen, int mode) { return vgaHWSaveScreen(pScreen, mode); }
This function is mandatory. Before modifying any hardware register
directly this function needs to make sure that the Xserver is active
by checking if pScrn
is non-NULL and for
pScrn->vtSema == TRUE
.
Define the FreeScreen()
function. This function
is optional. It should be defined if the ScrnInfoRec
driverPrivate
field is used so that it can be freed
when a screen is deleted by the common layer for reasons possibly
beyond the driver's control. This function is not used in during
normal (error free) operation. The per-generation data is freed by
the CloseScreen()
function.
static void ZZZFreeScreen(int scrnIndex, int flags) { /* * If the vgahw module is used vgaHWFreeHWRec() would be called * here. */ ZZZFreeRec(xf86Screens[scrnIndex]); }