At the start of each server generation, main()
(dix/main.c
) calls the DDX function
InitOutput()
. This is the first place that the DDX gets
control. InitOutput()
is expected to fill in the global
screenInfo
struct, and one
screenInfo.screen[]
entry for each screen present. Here
is what InitOutput()
does:
This is done at the start of the first server generation only.
The xorg.conf file is read in full, and the resulting information stored in data structures. None of the parsed information is processed at this point. The parser data structures are opaque to the video drivers and to most of the common layer code.
The entire file is parsed first to remove any section ordering requirements.
This is done at the start of the first server generation only.
The initial processing is to determine paths like the ModulePath, etc, and to determine which ServerLayout, Screen and Device sections are active.
Port I/O access is controlled from the XFree86 common layer, and is ``all or nothing''. It is enabled prior to calling driver probes, at the start of subsequent server generations, and when VT switching back to the Xserver. It is disabled at the end of server generations, and when VT switching away from the Xserver.
The implementation details of this may vary on different platforms.
This is done at the start of the first server generation only.
In the case of ix86 machines, this will be a general PCI probe.
The full information obtained here will be available to the drivers.
This information persists for the life of the Xserver. In the PCI
case, the PCI information for all video cards found is available by
calling xf86GetPciVideoInfo()
.
pciVideoPtr *xf86GetPciVideoInfo(void)
returns a pointer to a list of pointers to
pciVideoRec
entries, of which there is one for each detected PCI video card. The list is terminated with aNULL
pointer. If no PCI video cards were detected, the return value isNULL
.
After the bus probe, the resource broker is initialised.
This is done at the start of the first server generation only.
The core server contains a list of mandatory modules. These are loaded first. Currently the only module on this list is the bitmap font module.
The next set of modules loaded are those specified explicitly in the Module section of the config file.
The final set of initial modules are the driver modules referenced by the active Device and InputDevice sections in the config file. Each of these modules is loaded exactly once.
This is done at the start of the first server generation only.
When a driver module is loaded, the loader calls its
Setup
function. For video drivers, this function
calls xf86AddDriver()
to register the driver's
DriverRec
, which contains a small set of essential
details and driver entry points required during the early phase of
InitOutput()
. xf86AddDriver()
adds
it to the global xf86DriverList[]
array.
The DriverRec
contains the driver canonical name,
the Identify()
,
Probe()
and AvailableOptions()
function entry points as well as a pointer
to the driver's module (as returned from the loader when the driver
was loaded) and a reference count which keeps track of how many
screens are using the driver. The entry driver entry points are
those required prior to the driver allocating and filling in its
ScrnInfoRec
.
For a static server, the xf86DriverList[]
array is
initialised at build time, and the loading of modules is not done.
A similar procedure is used for input drivers. The input driver's
Setup
function calls
xf86AddInputDriver()
to register the driver's
InputDriverRec
, which contains a small set of
essential details and driver entry points required during the early
phase of InitInput()
.
xf86AddInputDriver()
adds it to the global
xf86InputDriverList[]
array. For a static server,
the xf86InputDriverList[]
array is initialised at
build time.
Both the xf86DriverList[]
and
xf86InputDriverList[]
arrays have been initialised
by the end of this stage.
Once all the drivers are registered, their
ChipIdentify()
functions are called.
void ChipIdentify(int flags)
This is expected to print a message indicating the driver name, a short summary of what it supports, and a list of the chipset names that it supports. It may use the xf86PrintChipsets() helper to do this.
void xf86PrintChipsets(const char *drvname, const char *drvmsg,
SymTabPtr chips)This function provides an easy way for a driver's ChipIdentify function to format the identification message.
This is done at the start of the first server generation only.
The Resource Access Control (RAC) subsystem is initialised before calling any driver functions that may access hardware. All generic bus information is probed and saved (for restoration later). All (shared resource) video devices are disabled at the generic bus level, and a probe is done to find the ``primary'' video device. These devices remain disabled for the next step.
This is done at the start of the first server generation only. The
ChipProbe()
function of each registered video driver
is called.
Bool ChipProbe(DriverPtr drv, int flags)
The purpose of this is to identify all instances of hardware supported by the driver. The flags value is currently either 0,
PROBE_DEFAULT
orPROBE_DETECT
.PROBE_DETECT
is used if "-configure" or "-probe" command line arguments are given and indicates to theProbe()
function that it should not configure the bus entities and that no xorg.conf information is available.The probe must find the active device sections that match the driver by calling
xf86MatchDevice()
. The number of matches found limits the maximum number of instances for this driver. If no matches are found, the function should returnFALSE
immediately.Devices that cannot be identified by using device-independent methods should be probed at this stage (keeping in mind that access to all resources that can be disabled in a device-independent way are disabled during this phase). The probe must be a minimal probe. It should just determine if there is a card present that the driver can drive. It should use the least intrusive probe methods possible. It must not do anything that is not essential, like probing for other details such as the amount of memory installed, etc. It is recommended that the
xf86MatchPciInstances()
helper function be used for identifying matching PCI devices, and similarly thexf86MatchIsaInstances()
for ISA (non-PCI) devices (see the RAC section). These helpers also checks and claims the appropriate entity. When not using the helper, that should be done withxf86CheckPciSlot()
andxf86ClaimPciSlot()
for PCI devices andxf86ClaimIsaSlot()
for ISA devices (see the RAC section).The probe must register all non-relocatable resources at this stage. If a resource conflict is found between exclusive resources the driver will fail immediately. This is usually best done with the
xf86ConfigPciEntity()
helper function for PCI andxf86ConfigIsaEntity()
for ISA (see the RAC section). It is possible to register some entity specific functions with those helpers. When not using the helpers, thexf86AddEntityToScreen()
xf86ClaimFixedResources()
andxf86SetEntityFuncs()
should be used instead (see the RAC section).If a chipset is specified in an active device section which the driver considers relevant (ie it has no driver specified, or the driver specified matches the driver doing the probe), the Probe must return
FALSE
if the chipset doesn't match one supported by the driver.If there are no active device sections that the driver considers relevant, it must return
FALSE
.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 thexf86ConfigIsaEntity()
helper function for ISA instances orxf86ConfigPciEntity()
for PCI instances. These functions allocate aScrnInfoRec
for active entities. Optionallyxf86AllocateScreen()
function may also be used to allocate theScrnInfoRec
. Any of these functions take care of initialising fields to defined ``unused'' values.Claim the entities for each instance of the hardware found. This prevents other drivers from claiming the same hardware.
Must leave hardware in the same state it found it in, and must not do any hardware initialisation.
All detection can be overridden via the config file, and that parsed information is available to the driver at this stage.
Returns
TRUE
if one or more instances are found, andFALSE
otherwise.
int xf86MatchDevice(const char *drivername,
GDevPtr **driversectlist)This function takes the name of the driver and returns via
driversectlist
a list of device sections that match the driver name. The function return value is the number of matches found. If a fatal error is encountered the return value is-1
.The caller should use
xfree()
to free*driversectlist
when it is no longer needed.
ScrnInfoPtr xf86AllocateScreen(DriverPtr drv, int flags)
This function allocates a new
ScrnInfoRec
in thexf86Screens[]
array. This function is normally called by the video driverChipProbe()
functions. The return value is a pointer to the newly allocatedScrnInfoRec
. ThescrnIndex
,origIndex
,module
anddrv
fields are initialised. The reference count indrv
is incremented. The storage for any currently allocated ``privates'' pointers is also allocated and theprivates
field initialised (the privates data is of course not allocated or initialised). This function never returns on failure. If the allocation fails, the server exits with a fatal error. The flags value is not currently used, and should be set to zero.
At the completion of this, a list of ScrnInfoRecs
have been allocated in the xf86Screens[]
array, and
the associated entities and fixed resources have been claimed. The
following ScrnInfoRec
fields must be initialised at
this point:
driverVersion driverName scrnIndex(*) origIndex(*) drv(*) module(*) name Probe PreInit ScreenInit EnterVT LeaveVT numEntities entityList access
(*)
These are initialised when the ScrnInfoRec
is allocated, and not explicitly by the driver.
The following ScrnInfoRec
fields must be initialised
if the driver is going to use them:
SwitchMode AdjustFrame FreeScreen ValidMode
This is done at the start of the first server generation only.
After the Probe phase is finished, there will be some number of
ScrnInfoRecs
. These are then matched with the active
Screen sections in the xorg.conf, and those not having an active
Screen section are deleted. If the number of remaining screens
is 0, InitOutput()
sets
screenInfo.numScreens
to 0
and
returns.
At this point the following fields of the ScrnInfoRecs
must be initialised:
confScreen
This is done at the start of the first server generation only.
Before calling the drivers again, the resource information collected from the Probe phase is processed. This includes checking the extent of PCI resources for the probed devices, and resolving any conflicts in the relocatable PCI resources. It also reports conflicts, checks bus routing issues, and anything else that is needed to enable the entities for the next phase.
If any drivers registered an EntityInit()
function
during the Probe phase, then they are called here.
This is done at the start of the first server generation only.
The list of screens is sorted to match the ordering requested in the config file.
The list of modes for each active monitor is checked against the monitor's parameters. Invalid modes are pruned.
This is done at the start of the first server generation only.
For each ScrnInfoRec
, enable access to the screens entities and call
the ChipPreInit()
function.
Bool ChipPreInit(ScrnInfoRec screen, int flags)
The purpose of this function is to find out 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 number of entities registered for the screen should be checked against the expected number (most drivers expect only one). The entity information for each of them should be retrieved (with
xf86GetEntityInfo()
) and checked for the correct bus type and that none of the sharable resources registered during the Probe phase was rejected.Access to resources for the entities that can be controlled in a device-independent way are enabled before this function is called. If the driver needs to access any resources that it has disabled in an
EntityInit()
function that it registered, then it may enable them here providing that it disables them before this function returns.This includes probing for video memory, clocks, ramdac, and all other HW info that is needed. It includes determining the depth/bpp/visual and related info. It includes validating and determining the set of video modes that will be used (and anything that is required to determine that).
This information should be determined in the least intrusive way possible. The state of the HW must remain unchanged by this function. Although video memory (including MMIO) may be mapped within this function, it must be unmapped before returning. Driver specific information should be stored in a structure hooked into the
ScrnInfoRec
'sdriverPrivate
field. Any other modules which require persistent data (ie data that persists across server generations) should be initialised in this function, and they should allocate a ``privates'' index to hook their data into by callingxf86AllocateScrnInfoPrivateIndex().
The ``privates'' data is persistent.Helper functions for some of these things are provided at the XFree86 common level, and the driver can choose to make use of them.
All additional resources that the screen needs must be registered here. This should be done with
xf86RegisterResources()
. If some of the fixed resources registered in the Probe phase are not needed or not decoded by the hardware when in the OPERATING server state, their status should be updated withxf86SetOperatingState()
.Modules may be loaded at any point in this function, and all modules that the driver will need must be loaded before the end of this function. Either the
xf86LoadSubModule()
or thexf86LoadDrvSubModule()
function should be used to load modules depending on whether aScrnInfoRec
has been set up. A driver may unload a module within this function if it was only needed temporarily, and thexf86UnloadSubModule()
function should be used to do that. Otherwise there is no need to explicitly unload modules because the loader takes care of module dependencies and will unload submodules automatically if/when the driver module is unloaded.The bulk of the
ScrnInfoRec
fields should be filled out in this function.
ChipPreInit()
returnsFALSE
when the configuration is unusable in some way (unsupported depth, no valid modes, not enough video memory, etc), andTRUE
if it is usable.It is expected that if the
ChipPreInit()
function returnsTRUE
, then the only reasons that subsequent stages in the driver might fail are lack or resources (like xalloc failures). All other possible reasons for failure should be determined by theChipPreInit()
function.
The ScrnInfoRecs
for screens where the ChipPreInit()
fails are removed.
If none remain, InitOutput()
sets screenInfo.numScreens
to 0
and returns.
At this point, further fields of the ScrnInfoRecs
would normally be
filled in. Most are not strictly mandatory, but many are required
by other layers and/or helper functions that the driver may choose
to use. The documentation for those layers and helper functions
indicates which they require.
The following fields of the ScrnInfoRecs
should be filled in if the
driver is going to use them:
monitor display depth pixmapBPP bitsPerPixel weight (>8bpp only) mask (>8bpp only) offset (>8bpp only) rgbBits (8bpp only) gamma defaultVisual maxHValue maxVValue virtualX virtualY displayWidth frameX0 frameY0 frameX1 frameY1 zoomLocked modePool modes currentMode progClock (TRUE if clock is programmable) chipset ramdac clockchip numClocks (if not programmable) clock[] (if not programmable) videoRam biosBase memBase memClk driverPrivate chipID chipRev
pointer xf86LoadSubModule(ScrnInfoPtr pScrn, const char *name)
: andpointer xf86LoadDrvSubModule(DriverPtr drv, const char *name)
:Load a module that a driver depends on. This function loads the module
name
as a sub module of the driver. The return value is a handle identifying the new module. If the load fails, the return value will beNULL
. If a driver needs to explicitly unload a module it has loaded in this way, the return value must be saved and passed toxf86UnloadSubModule()
when unloading.
void xf86UnloadSubModule(pointer module)
Unloads the module referenced by
module
.module
should be a pointer returned previously byxf86LoadSubModule()
orxf86LoadDrvSubModule()
.
At this point it is known which screens will be in use, and which drivers are being used. Unreferenced drivers (and modules they may have loaded) are unloaded here.
The parameters that must be global to the server, like pixmap formats, bitmap bit order, bitmap scanline unit and image byte order are compared for each of the screens. If a mismatch is found, the server exits with an appropriate message.
Determine if resource access control is needed. This is the case if more than one screen is used. If necessary the RAC wrapper module is loaded.
At this point, the valid screens are known.
AddScreen()
is called for each of them, passing
ChipScreenInit()
as the argument.
AddScreen()
is a DIX function that allocates a new
screenInfo.screen[]
entry (aka
pScreen
), and does some basic initialisation of it.
It then calls the ChipScreenInit()
function, with
pScreen
as one of its arguments. If
ChipScreenInit()
returns FALSE
,
AddScreen()
returns -1
. Otherwise
it returns the index of the screen. AddScreen()
should only fail because of programming errors or failure to allocate
resources (like memory). All configuration problems should be
detected BEFORE this point.
Bool ChipScreenInit(int index, ScreenPtr pScreen,
int argc, char **argv)This is called at the start of each server generation.
Fill in all of
pScreen
, possibly doing some of this by calling ScreenInit functions from other layers like mi, framebuffers (cfb, etc), and extensions.Decide which operations need to be placed under resource access control. The classes of operations are the frame buffer operations (
RAC_FB
), the pointer operations (RAC_CURSOR
), the viewport change operations (RAC_VIEWPORT
) and the colormap operations (RAC_COLORMAP
). Any operation that requires resources which might be disabled during OPERATING state should be set to use RAC. This can be specified separately for memory and IO resources (theracMemFlags
andracIoFlags
fields of theScrnInfoRec
respectively).Map any video memory or other memory regions.
Save the video card state. Enough state must be saved so that the original state can later be restored.
Initialise the initial video mode. The
ScrnInfoRec
'svtSema
field should be set toTRUE
just prior to changing the video hardware's state.
The ChipScreenInit()
function (or functions from other
layers that it calls) should allocate entries in the
ScreenRec
's devPrivates
area by
calling AllocateScreenPrivateIndex()
if it needs
per-generation storage. Since the ScreenRec
's
devPrivates
information is cleared for each server
generation, this is the correct place to initialise it.
After AddScreen()
has successfully returned, the
following ScrnInfoRec
fields are initialised:
pScreen racMemFlags racIoFlags
The ChipScreenInit()
function should initialise the
CloseScreen
and SaveScreen
fields
of pScreen
. The old value of
pScreen->CloseScreen
should be saved as part of
the driver's per-screen private data, allowing it to be called from
ChipCloseScreen()
. This means that the existing
CloseScreen()
function is wrapped.
After all the ChipScreenInit()
functions have been
called, each screen has registered its RAC requirements. This
information is used to determine which shared resources are requested
by more than one driver and set the access functions accordingly.
This is done following these rules:
At this point InitOutput()
is finished, and all the
screens have been setup in their initial video mode.
When a SwitchMode event is received, ChipSwitchMode()
is called (when it exists):
Bool ChipSwitchMode(int index, DisplayModePtr mode, int flags)
Initialises the new mode for the screen identified by
index;
. The viewport may need to be adjusted also.
When a Change Viewport event is received,
ChipAdjustFrame()
is called (when it exists):
void ChipAdjustFrame(int index, int x, int y, int flags)
Changes the viewport for the screen identified by
index;
.It should be noted that many chipsets impose restrictions on where the viewport may be placed in the virtual resolution, either for alignment reasons, or to prevent the start of the viewport from being positioned within a pixel (as can happen in a 24bpp mode). After calculating the value the chipset's panning registers need to be set to for non-DGA modes, this function should recalculate the ScrnInfoRec's
frameX0
,frameY0
,frameX1
andframeY1
fields to correspond to that value. If this is not done, switching to another mode might cause the position of a hardware cursor to change.
When a VT switch event is received, xf86VTSwitch()
is called. xf86VTSwitch()
does the following:
ChipEnterVT()
for each screen
ChipLeaveVT()
for each screen
Bool ChipEnterVT(int index, int flags)
This function should initialise the current video mode and initialise the viewport, turn on the HW cursor if appropriate, etc.
Should it re-save the video state before initialising the video mode?
void ChipLeaveVT(int index, int flags)
This function should restore the saved video state. If appropriate it should also turn off the HW cursor, and invalidate any pixmap/font caches.
Optionally,
ChipLeaveVT()
may also unmap memory regions. If so,ChipEnterVT()
will need to remap them. Additionally, if an aperture used to access video memory is unmapped and remapped in this fashion,ChipEnterVT()
will also need to notify the framebuffer layers of the aperture's new location in virtual memory. This is done with a call to the screen'sModifyPixmapHeader()
function, as follows
(*pScreen->ModifyPixmapHeader)(pScrn->ppix,
-1, -1, -1, -1, -1, NewApertureAddress);where the
``ppix''
field in a ScrnInfoRec points to the pixmap used by the screen'sSaveRestoreImage()
function to hold the screen's contents while switched out.Currently, aperture remapping, as described here, should not be attempted if the driver uses the
xf8_16bpp
orxf8_32bpp
framebuffer layers. A pending restructuring of VT switching will address this restriction in the near future.
Other layers may wrap the ChipEnterVT()
and
ChipLeaveVT()
functions if they need to take some
action when these events are received.
At the end of each server generation, the DIX layer calls
ChipCloseScreen()
for each screen:
Bool ChipCloseScreen(int index, ScreenPtr pScreen)
This function should restore the saved video state and unmap the memory regions.
It should also free per-screen data structures allocated by the driver. Note that the persistent data held in the
ScrnInfoRec
'sdriverPrivate
field should not be freed here because it is needed by subsequent server generations.The
ScrnInfoRec
'svtSema
field should be set toFALSE
once the video HW state has been restored.Before freeing the per-screen driver data the saved
CloseScreen
value should be restored topScreen->CloseScreen
, and that function should be called after freeing the data.