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

InitInput()

InitInput() is implemented in xf86Init.c as:

/*
 * InitInput --
 *      Initialize all supported input devices.
 */

void
InitInput(argc, argv)
     int     	  argc;
     char    	  **argv;
{
    IDevPtr pDev;
    InputDriverPtr pDrv;
    InputInfoPtr pInfo;
    static InputInfoPtr coreKeyboard = NULL, corePointer = NULL;

    xf86Info.vtRequestsPending = FALSE;
    xf86Info.inputPending = FALSE;
#ifdef XTESTEXT1
    xtest_command_key = KEY_Begin + MIN_KEYCODE;
#endif /* XTESTEXT1 */

    if (serverGeneration == 1) {
	/* Call the PreInit function for each input device instance. */
	for (pDev = xf86ConfigLayout.inputs; pDev && pDev->identifier; pDev++) {

#ifdef USE_DEPRECATED_KEYBOARD_DRIVER
	    /* XXX The keyboard driver is a special case for now. */
	    if (!xf86NameCmp(pDev->driver, "keyboard")) {
		xf86MsgVerb(X_WARNING, 0, "...keyboard driver \"keyboard\" is deprecated\n");
		xf86MsgVerb(X_WARNING, 0, "...the next release of the Xorg server.\n");
		xf86MsgVerb(X_WARNING, 0, "...new \"kbd\" driver for \"%s\".\n",
			pDev->identifier);

		continue;
	    }
#endif

	    if ((pDrv = MatchInput(pDev)) == NULL) {
		xf86Msg(X_ERROR, "No Input driver matching `%s'\n", pDev->driver);
		/* XXX For now, just continue. */
		continue;
	    }
	    if (!pDrv->PreInit) {
		xf86MsgVerb(X_WARNING, 0,
		    "Input driver `%s' has no PreInit function (ignoring)\n",
		    pDrv->driverName);
		continue;
	    }
	    pInfo = pDrv->PreInit(pDrv, pDev, 0);
	    if (!pInfo) {
		xf86Msg(X_ERROR, "PreInit returned NULL for \"%s\"\n",
			pDev->identifier);
		continue;
	    } else if (!(pInfo->flags & XI86_CONFIGURED)) {
		xf86Msg(X_ERROR, "PreInit failed for input device \"%s\"\n",
			pDev->identifier);
		xf86DeleteInput(pInfo, 0);
		continue;
	    }
	    if (pInfo->flags & XI86_CORE_KEYBOARD) {
		if (coreKeyboard) {
		    xf86Msg(X_ERROR,
		      "Attempt to register more than one core keyboard (%s)\n",
		      pInfo->name);
		    pInfo->flags &= ~XI86_CORE_KEYBOARD;
		} else {
		    if (!(pInfo->flags & XI86_KEYBOARD_CAPABLE)) {
			/* XXX just a warning for now */
			xf86Msg(X_WARNING,
			    "%s: does not have core keyboard capabilities\n",
			    pInfo->name);
		    }
		    coreKeyboard = pInfo;
		}
	    }
	    if (pInfo->flags & XI86_CORE_POINTER) {
		if (corePointer) {
		    xf86Msg(X_ERROR,
			"Attempt to register more than one core pointer (%s)\n",
			pInfo->name);
		    pInfo->flags &= ~XI86_CORE_POINTER;
		} else {
		    if (!(pInfo->flags & XI86_POINTER_CAPABLE)) {
			/* XXX just a warning for now */
			xf86Msg(X_WARNING,
			    "%s: does not have core pointer capabilities\n",
			    pInfo->name);
		    }
		    corePointer = pInfo;

		}
	    }
	}
	if (!corePointer) {
	    xf86Msg(X_WARNING, "No core pointer registered\n");
	    /* XXX register a dummy core pointer */
	}
#ifdef NEW_KBD
	if (!coreKeyboard) {
	    xf86Msg(X_WARNING, "No core keyboard registered\n");
	    /* XXX register a dummy core keyboard */
	}
#endif
    }

    /* Initialise all input devices. */
    pInfo = xf86InputDevs;
    while (pInfo) {
	xf86ActivateDevice(pInfo);
	pInfo = pInfo->next;
    }

    if (coreKeyboard) {
      xf86Info.pKeyboard = coreKeyboard->dev;
      xf86Info.kbdEvents = NULL; /* to prevent the internal keybord driver usage*/
    }
    else {
#ifdef USE_DEPRECATED_KEYBOARD_DRIVER
      /* Only set this if we're allowing the old driver. */
	if (xf86Info.kbdProc != NULL) 
	    xf86Info.pKeyboard = AddInputDevice(xf86Info.kbdProc, TRUE);
#endif
    }
    if (corePointer)
	xf86Info.pMouse = corePointer->dev;
    if (xf86Info.pKeyboard)
      RegisterKeyboardDevice(xf86Info.pKeyboard); 

  miRegisterPointerDevice(screenInfo.screens[0], xf86Info.pMouse);
#ifdef XINPUT
  xf86eqInit ((DevicePtr)xf86Info.pKeyboard, (DevicePtr)xf86Info.pMouse);
#else
  mieqInit ((DevicePtr)xf86Info.pKeyboard, (DevicePtr)xf86Info.pMouse);
#endif

Global xf86info is defined and initialized in xf86Globals.c. It is of type xf86InfoRec.

Consider for instance the following part of an xorg.conf:

Example:

Section "InputDevice"
        Identifier  "Mouse0"
        Driver      "mouse"
        Option      "Device" "/dev/input/mice"
        Option      "Protocol" "IMPS/2"
        Option      "ZAxisMapping" "4 5"        # Scrollwheel support
        Option      "Emulate3Buttons" "yes"     # L+R buttons count as middle
EndSection

MatchInput() is implemented as:

static InputDriverPtr
MatchInput(IDevPtr pDev)
{
    int i;

    for (i = 0; i < xf86NumInputDrivers; i++) {
	if (xf86InputDriverList[i] && xf86InputDriverList[i]->driverName &&
	    xf86NameCmp(pDev->driver, xf86InputDriverList[i]->driverName) == 0)
	    return xf86InputDriverList[i];
    }
    return NULL;
}

xf86InputDriverList is defined in xf86Globals.c as:

InputDriverPtr *xf86InputDriverList = NULL;

Where InputDriverPtr is defined in xf86Xinput.h as:


/* This holds the input driver entry and module information. */
typedef struct _InputDriverRec {
    int			    driverVersion;
    char *		    driverName;
    void		    (*Identify)(int flags);
    struct _LocalDeviceRec *(*PreInit)(struct _InputDriverRec *drv,
				       IDevPtr dev, int flags);
    void		    (*UnInit)(struct _InputDriverRec *drv,
				      struct _LocalDeviceRec *pInfo,
				      int flags);
    pointer		    module;
    int			    refCount;
} InputDriverRec, *InputDriverPtr;

In a Nutshell

InitInput() calls MatchInput(), which returns pDrv of type InputDriverPtr, which points to the matching item of xf86InputDriverList[].

xf86InputDriverList[] is created by xf86InputDriverlistFromConfig(), called in InitOutput() as:

    /* Load all input driver modules specified in the config file. */
    if ((modulelist = xf86InputDriverlistFromConfig())) {
      xf86LoadModules(modulelist, NULL);
      xfree(modulelist);
    }

xf86LoadModules() calls xf86AddInputDriver(), which adds a new item to xf86InputDriverList[].

The following is this item for the example we follow, after xf86AddInputDriver() is called as seen in the next paragraphs:

driverVersion1
driverName"mouse"
Identify()(int flags)NULL
PreInit()MousePreInit
UnInit()NULL
modulemodule (*)
refCount0

(*) module is of type ModuleDescPtr returned by LoadModule(), which is called by xf86LoadModules().

The pDrv->PreInit function, in our case MousePreInit(), is called next from InitInput(). This fills and returns pInfo, which is of type InputInfoPtr. The InputInfoRec it points to, for the example we follow, is presented in the next example. The pInfo are linked in the xf86InputDevs list. This is the result of xf86AllocateInput() that is called from InitInput() to allocate a new pInfo.

InitInput() calls next xf86ActivateDevice() for each pInfo of the xf86InputDevs list. xf86ActivateDevice() calls AddInputDevice(), which allocates dev, a DeviceIntPtr (points to a _DeviceIntRec) and then it calls RegisterPointerDevice() and RegisterKeyboardDevice() to register the core mouse and keyboard devices.

Two notes about section 3.2.5.1

I.

The following fields of xf86Info

xf86Info.pKeyboard
and
xf86Info.pMouse

are filled from the following instructions of InitInput():

xf86Info.pKeyboard = coreKeyboard->dev;
...
xf86Info.pMouse = corePointer->dev;
where coreKeyboard and corePointer are the pInfo (of type InputInfoPtr) that are returned from the PreInit() functions of the mouse and keyboard drivers, which have the XI86_CORE_POINTER and XI86_CORE_KEYBOARD flags respectively set.

II.

The following lines of xf86ActivateDevice(), called by InitInput() fill dev (of type DeviceIntPtr) which was allocated previously in xf86ActivateDevice() by calling AddInputDevice() with argument the pInfo->device_control:

	if (local->flags & XI86_CORE_POINTER)
	    RegisterPointerDevice(dev);
	else if (local->flags & XI86_CORE_KEYBOARD)
	    RegisterKeyboardDevice(dev);
assign some of the fields of dev (field deviceProc was set by _AddInputDevice). Among the fields in section 3.2.5.1 we are interested in processInputProc. As we see for instance in _RegisterPointerDevice() this becomes ProcessPointerEvent. Similarly for the keyboard in _RegisterKeyboardDevice it becomes ProcessKeyboardEvent.

xf86InputDriverlistFromConfig() is implemented as:

char **
xf86InputDriverlistFromConfig()
{
    int count = 0;
    char **modulearray;
    IDevPtr idp;
    
    /*
     * make sure the config file has been parsed and that we have a
     * ModulePath set; if no ModulePath was given, use the default
     * ModulePath
     */
    if (xf86configptr == NULL) {
        xf86Msg(X_ERROR, "Cannot access global config data structure\n");
        return NULL;
    }
    
    /*
     * Walk the list of driver lines in active "InputDevice" sections to
     * determine now many implicitly loaded modules there are.
     */
    if (xf86ConfigLayout.inputs) {
        idp = xf86ConfigLayout.inputs;
        while (idp->identifier) {
	    if (!xf86BuiltinInputDriver(idp->driver))
	        count++;
	    idp++;
        }
    }

    if (count == 0)
	return NULL;

    /*
     * allocate the memory and walk the list again to fill in the pointers
     */
    modulearray = xnfalloc((count + 1) * sizeof(char*));
    count = 0;
    idp = xf86ConfigLayout.inputs;
    while (idp->identifier) {
	if (!xf86BuiltinInputDriver(idp->driver)) {
	    modulearray[count] = idp->driver;
	    count++;
	}
	idp++;
    }
    modulearray[count] = NULL;

    /* Remove duplicates */
    for (count = 0; modulearray[count] != NULL; count++) {
	int i;

	for (i = 0; i < count; i++)
	    if (xf86NameCmp(modulearray[i], modulearray[count]) == 0) {
		modulearray[count] = "";
		break;
	    }
    }
    return modulearray;
}

Recall from section 3.2.2.2 that xf86ConfigLayout is of type serverLayoutRec. xf86ConfigLayout is the data structure that is used at this point to represent the Layout section information. It collects the information parsed by xorg.conf and stored previously in the XF86ConfLayoutPtr field of the global XF86ConfigRec. This process is done in configLayout() (or in configImpliedLayout()).

typedef struct _serverlayoutrec {
    char *		id;
    screenLayoutPtr	screens;
    GDevPtr		inactives;
    IDevPtr		inputs;
    pointer		options;
} serverLayoutRec, *serverLayoutPtr;

xf86InputDriverlistFromConfig() creates the modulearray[], a array of strings whose elements are the module names. The module names are the ones we find at the driver field of xf86ConfigLayout.inputs. For instance for the xorg.conf of the green boxed example the module name becomes "mouse".

xf86LoadModules() is used then to load all modules of the modulearray[]. This function was covered in a section 3.2.2.5. In a short xf86LoadModules() calls LoadModule() for each module found in the list. One of the main things LoadModule() does is call the module's setup routine as:

ret->TearDownData = ret->SetupProc(ret, options, errmaj, errmin);

The first argument ret is obtained from NewModuleDesc() (called by LoadModule) and is of type ModuleDescPtr. ret is filled by LoadModule() and in the current example 'module' is the actual argument that substitutes ret (the formal parameter).

LoadModule() checks if the special data object <modulename>ModuleData is present. For the current example this found in mouse.c as:

_X_EXPORT XF86ModuleData mouseModuleData = {
    &xf86MouseVersionRec,
    xf86MousePlug,
    xf86MouseUnplug
};

Since XF86ModuleData is defined in xf86Module.h as:


typedef struct {
    XF86ModuleVersionInfo *	vers;
    ModuleSetupProc		setup;
    ModuleTearDownProc		teardown;
} XF86ModuleData;

we conclude that the mouse setup routine is xf86MousePlug().

xf86MousePlug() called by LoadModule() calls xf86AddInputDriver() to add a pointer to the mouse InputDriverRec to xf86InputDriverList[]:

    xf86AddInputDriver(&MOUSE, module, 0);

where MOUSE is defined in mouse.c as:

_X_EXPORT InputDriverRec MOUSE = {
	1,
	"mouse",
	NULL,
	MousePreInit,
	/*MouseUnInit,*/NULL,
	NULL,
	0
};

the last NULL value (the red one) after the xf86AddInputDriver() call is substituted by a pointer to the 'module'.

A common place to find the "mouse" module is:
/usr/lib/xorg/modules/input//mouse_drv.so

The previous steps are described in section 5.6 of the DESIGN document (Register Video and Input Drivers):

5.6  Register Video and Input Drivers

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 refer-
ence 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 ini-
tialised by the end of this stage.

Once all the drivers are registered, their ChipIdentify() functions are
called.

What is a canonical file name? As the Loader Overview explains:
"The module name module is normally the module's canonical name, which doesn't contain any directory path information, or any object/library file prefixes of suffixes."

MousePreInit(), the module's PreInit() function is implemented as:

static InputInfoPtr
MousePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
{
    InputInfoPtr pInfo;
    MouseDevPtr pMse;
    mousePrivPtr mPriv;
    MessageType protocolFrom = X_DEFAULT, deviceFrom = X_CONFIG;
    const char *protocol, *osProt = NULL;
    const char *device;
    MouseProtocolID protocolID;
    MouseProtocolPtr pProto;
    Bool detected;
    int i;
    
    if (!InitProtocols())
	return NULL;

    if (!(pInfo = xf86AllocateInput(drv, 0)))
	return NULL;

    /* Initialise the InputInfoRec. */
    pInfo->name = dev->identifier;
    pInfo->type_name = XI_MOUSE;
    pInfo->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
    pInfo->device_control = MouseProc;
    pInfo->read_input = MouseReadInput;
    pInfo->motion_history_proc = xf86GetMotionEvents;
    pInfo->history_size = 0;
    pInfo->control_proc = NULL;
    pInfo->close_proc = NULL;
    pInfo->switch_mode = NULL;
    pInfo->conversion_proc = MouseConvert;
    pInfo->reverse_conversion_proc = NULL;
    pInfo->fd = -1;
    pInfo->dev = NULL;
    pInfo->private_flags = 0;
    pInfo->always_core_feedback = 0;
    pInfo->conf_idev = dev;

    /* Check if SendDragEvents has been disabled. */
    if (!xf86SetBoolOption(dev->commonOptions, "SendDragEvents", TRUE)) {
	pInfo->flags &= ~XI86_SEND_DRAG_EVENTS;
    }

    /* Allocate the MouseDevRec and initialise it. */
    /*
     * XXX This should be done by a function in the core server since the
     * MouseDevRec is defined in the os-support layer.
     */
    if (!(pMse = xcalloc(sizeof(MouseDevRec), 1)))
	return pInfo;
    pInfo->private = pMse;
    pMse->Ctrl = MouseCtrl;
    pMse->PostEvent = MousePostEvent;
    pMse->CommonOptions = MouseCommonOptions;
    
    /* Find the protocol type. */
    protocol = xf86SetStrOption(dev->commonOptions, "Protocol", NULL);
    if (protocol) {
	protocolFrom = X_CONFIG;
    } else if (osInfo->DefaultProtocol) {
	protocol = osInfo->DefaultProtocol();
	protocolFrom = X_DEFAULT;
    }
    if (!protocol) {
	xf86Msg(X_ERROR, "%s: No Protocol specified\n", pInfo->name);
	return pInfo;
    }

    /* Default Mapping: 1 2 3 8 9 10 11 ... */
    for (i = 0; i < MSE_MAXBUTTONS; i++)
	pMse->buttonMap[i] = 1 << (i > 2 && i < MSE_MAXBUTTONS-4 ? i+4 : i);

    protocolID = ProtocolNameToID(protocol);
    do {
	detected = TRUE;
	switch (protocolID) {
	case PROT_AUTO:
	    if (osInfo->SetupAuto) {
		if ((osProt = osInfo->SetupAuto(pInfo,NULL))) {
		    MouseProtocolID id = ProtocolNameToID(osProt);
		    if (id == PROT_UNKNOWN || id == PROT_UNSUP) {
			protocolID = id;
			protocol = osProt;
			detected = FALSE;
		    }
		}
	    }
	    break;
	case PROT_UNKNOWN:
	    /* Check for a builtin OS-specific protocol,
	     * and call its PreInit. */
	    if (osInfo->CheckProtocol
		&& osInfo->CheckProtocol(protocol)) {
		if (!xf86CheckStrOption(dev->commonOptions, "Device", NULL) &&
		    HAVE_FIND_DEVICE && osInfo->FindDevice) {
		    xf86Msg(X_WARNING, "%s: No Device specified, "
			    "looking for one...\n", pInfo->name);
		    if (!osInfo->FindDevice(pInfo, protocol, 0)) {
			xf86Msg(X_ERROR, "%s: Cannot find which device "
				"to use.\n", pInfo->name);
		    } else
			deviceFrom = X_PROBED;
		}
		if (osInfo->PreInit) {
		    osInfo->PreInit(pInfo, protocol, 0);
		}
		return pInfo;
	    }
	    xf86Msg(X_ERROR, "%s: Unknown protocol \"%s\"\n",
		    pInfo->name, protocol);
	    return pInfo;
	    break;
	case PROT_UNSUP:
	    xf86Msg(X_ERROR,
		    "%s: Protocol \"%s\" is not supported on this "
		    "platform\n", pInfo->name, protocol);
	    return pInfo;
	    break;
	default:
	    break;
	    
	}
    } while (!detected);
    
    if (!xf86CheckStrOption(dev->commonOptions, "Device", NULL) &&
	HAVE_FIND_DEVICE && osInfo->FindDevice) {
	xf86Msg(X_WARNING, "%s: No Device specified, looking for one...\n",
		pInfo->name);
	if (!osInfo->FindDevice(pInfo, protocol, 0)) {
	    xf86Msg(X_ERROR, "%s: Cannot find which device to use.\n",
		    pInfo->name);
	} else {
	    deviceFrom = X_PROBED;
	    xf86MarkOptionUsedByName(dev->commonOptions, "Device");
	}
    }

    device = xf86CheckStrOption(dev->commonOptions, "Device", NULL);
    if (device)
	xf86Msg(deviceFrom, "%s: Device: \"%s\"\n", pInfo->name, device);
	
    xf86Msg(protocolFrom, "%s: Protocol: \"%s\"\n", pInfo->name, protocol);
    if (!(pProto = GetProtocol(protocolID)))
	return pInfo;

    pMse->protocolID = protocolID;
    pMse->oldProtocolID = protocolID;  /* hack */

    pMse->autoProbe = FALSE;
    /* Collect the options, and process the common options. */
    xf86CollectInputOptions(pInfo, pProto->defaults, NULL);
    xf86ProcessCommonOptions(pInfo, pInfo->options);

    /* XXX should handle this OS dependency elsewhere. */
#ifndef __OS2ELF__
    /* OS/2 has a mouse handled by the OS - it cannot fail here */

    /* Check if the device can be opened. */
    pInfo->fd = xf86OpenSerial(pInfo->options);
    if (pInfo->fd == -1) {
	if (xf86GetAllowMouseOpenFail())
	    xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
	else {
	    xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
	    if (pMse->mousePriv)
		xfree(pMse->mousePriv);
	    xfree(pMse);
	    pInfo->private = NULL;
	    return pInfo;
	}
    }
    xf86CloseSerial(pInfo->fd);
#endif
    pInfo->fd = -1;

    if (!(mPriv = (pointer) xcalloc(sizeof(mousePrivRec), 1)))
	return pInfo;
    pMse->mousePriv = mPriv;
    pMse->CommonOptions(pInfo);
    pMse->checkMovements = checkForErraticMovements;
    pMse->autoProbeMouse = autoProbeMouse;
    pMse->collectData = collectData;
    pMse->dataGood = autoGood;
    
    MouseHWOptions(pInfo);
    MouseSerialOptions(pInfo);
    
    pInfo->flags |= XI86_CONFIGURED;
    return pInfo;
}

xf86AllocateInput() is implemented as:

/* Allocate a new InputInfoRec and add it to the head xf86InputDevs. */

InputInfoPtr
xf86AllocateInput(InputDriverPtr drv, int flags)
{
    InputInfoPtr new;

    if (!(new = xcalloc(sizeof(InputInfoRec), 1)))
	return NULL;

    new->drv = drv;
    drv->refCount++;
#ifdef XFree86LOADER
    new->module = DuplicateModule(drv->module, NULL);
#else
    new->module = NULL;
#endif
    new->next = xf86InputDevs;
    xf86InputDevs = new;
    return new;
}

InputInfoPtr is defined in xf86Xinput.h as:


/* This is to input devices what the ScrnInfoRec is to screens. */

typedef struct _LocalDeviceRec {
    struct _LocalDeviceRec *next;
    char *		    name;
    int			    flags;
    
    Bool		    (*device_control)(DeviceIntPtr device, int what);
    void		    (*read_input)(struct _LocalDeviceRec *local);
    int			    (*control_proc)(struct _LocalDeviceRec *local,
					   xDeviceCtl *control);
    void		    (*close_proc)(struct _LocalDeviceRec *local);
    int			    (*switch_mode)(ClientPtr client, DeviceIntPtr dev,
					  int mode);
    Bool		    (*conversion_proc)(struct _LocalDeviceRec *local,
					      int first, int num, int v0,
					      int v1, int v2, int v3, int v4,
					      int v5, int *x, int *y);
    Bool		    (*reverse_conversion_proc)(
					struct _LocalDeviceRec *local,
					int x, int y, int *valuators);
    
    int			    fd;
    Atom		    atom;
    DeviceIntPtr	    dev;
    pointer		    private;
    int			    private_flags;
    pointer		    motion_history;
    ValuatorMotionProcPtr   motion_history_proc;
    unsigned int	    history_size;   /* only for configuration purpose */
    unsigned int	    first;
    unsigned int	    last;
    int			    old_x;
    int			    old_y;
    float		    dxremaind;
    float		    dyremaind;
    char *		    type_name;
    IntegerFeedbackPtr	    always_core_feedback;
    IDevPtr		    conf_idev;
    InputDriverPtr	    drv;
    pointer		    module;
    pointer		    options;
} LocalDeviceRec, *LocalDevicePtr, InputInfoRec, *InputInfoPtr;

Example (continued)

For the given "mouse" device the InputInfoRec (pointed by pInfo) has the following form:

FieldValue
nexta pointer to the next input device
nameMouse0
flagsXI86_POINTER_CAPABLE, XI86_SEND_DRAG_EVENTS, XI86_CONFIGURED
device_controlMouseProc()
read_inputMouseReadInput()
control_procNULL
close_procNULL
switch_modeNULL
conversion_procMouseConvert
reverse_conversion_procNULL
fd -1 (although it obtained the value returned from xf86OpenSerial(), after xf86CloseSerial() it turned again to -1)
atom0
devThe DeviceIntPtr that is presented in the next box of the current example
private MouseDevRec
FieldValue
CtrlMouseCtrl()
PostEventMousePostEvent()
CommonOptionsMouseCommonOptions()
autoProbeMouseautoProbeMouse()
collectDatacollectData()
dataGoodautoGood()
......
private_flags0
motion_history0
motion_history_procxf86GetMotionEvents()
history_size0
first0
last0
old_x0
old_y0
dxremaind0
dyremaind0
type_nameXI_MOUSE
always_core_feedback0
conf_idev
IDevPtr pointer to the following IDevRec:

identifier: Mouse0
driver: mouse
commonOptions: "Device" "/dev/input/mice
               "Protocol" "IMPS/2"
               "ZAxisMapping" "4 5"
               "Emulate3Buttons" "yes"  
drvThe "mouse" InputDriverPtr
moduleThe ModuleDescPtr to the 'module', filled by LoadModule() as previously referred
options 

Notes:

xf86AllocateInput() is used to set the drv field of the InputInfoRec to the first argument of MousePreInit(). This is the return value of MatchInput() which is the xf86InputDriverList[] element with driverName "mouse". As mentioned previously in the current section this list is created by xf86InputDriverlistFromConfig() from xf86ConfigLayout.inputs->driver.

This was filled by configInput() called by configLayout(). For a more detailed explanation see configInput at section 3.2.2.2.

Some values have the predefined value zero since xf86AllocateInput() calls xcalloc() which fills with zero each byte of the current InputInfoRec. Zero value for a pointer is equivalent to NULL.

Also xf86CollectInputOptions() and xf86ProcessCommonOptions(), called by MousePreInit() fills the 'options' field:

  /* Collect the options, and process the common options. */
    xf86CollectInputOptions(pInfo, pProto->defaults, NULL);
    xf86ProcessCommonOptions(pInfo, pInfo->options);

Field 'private' is of type MouseDevPtr.

conf_idev is filled with the IDevPtr that points to the IDevRec which as seen in the first lines of InitInput() results from the xf86ConfigLayout.inputs with the given identifier.

Field 'dev' is filled when xf86ActivateDevice() runs latter.

Field 'atom' also is filled with xf86ActivateDevice().

module and drv fields were filled by xf86AllocateInput().

MSE_MAXBUTTONS is defined in xf86OSmouse.h to 24.

MouseDevPtr is defined in xf86OSmouse.h as:

typedef struct _MouseDevRec {
    PtrCtrlProcPtr	Ctrl;
    PostMseEventProc	PostEvent;
    MouseCommonOptProc	CommonOptions;
    DeviceIntPtr	device;
    const char *	mseDevice;
    const char *	protocol;
    MouseProtocolID	protocolID;
    MouseProtocolID	oldProtocolID; /* hack */
    int			class;
    int			mseModel;
    int			baudRate;
    int			oldBaudRate;
    int			sampleRate;
    int			lastButtons;
    int			threshold;	/* acceleration */
    int			num;
    int			den;
    int			buttons;	/* # of buttons */
    int			emulateState;	/* automata state for 2 button mode */
    Bool		emulate3Buttons;
    Bool		emulate3ButtonsSoft;
    int			emulate3Timeout;/* Timeout for 3 button emulation */
    Bool		chordMiddle;
    Bool                flipXY;
    int                 invX;
    int                 invY;
    int			mouseFlags;	/* Flags to Clear after opening
					 * mouse dev */
    int			truebuttons;	/* (not used)
					 * Arg to maintain before
					 * emulate3buttons timer callback */
    int			resolution;
    int			negativeZ;	/* button mask */
    int			positiveZ;	/* button mask */
    int			negativeW;	/* button mask */
    int			positiveW;	/* button mask */
    pointer		buffer;		/* usually an XISBuffer* */
    int			protoBufTail;
    unsigned char	protoBuf[8];
    unsigned char	protoPara[8];
    unsigned char	inSync;		/* driver in sync with datastream */
    pointer		mousePriv;	/* private area */
    InputInfoPtr	pInfo;
    int			origProtocolID;
    const char *	origProtocol;
    Bool		emulate3Pending;/* timer waiting */
    CARD32		emulate3Expires;/* time to fire emulation code */
    Bool		emulateWheel;
    int			wheelInertia;
    int			wheelButton;
    int			negativeX;	/* Button values.  Unlike the Z and */
    int			positiveX;	/* W equivalents, these are button  */
    int			negativeY;	/* values rather than button masks. */
    int			positiveY;
    int			wheelYDistance;
    int			wheelXDistance;
    Bool		autoProbe;
    checkMovementsProc  checkMovements;
    autoProbeProc	autoProbeMouse;
    collectDataProc	collectData;
    dataGoodProc	dataGood;
    int			angleOffset;
    pointer		pDragLock;	/* drag lock area */
    int			xisbscale;	/* buffer size for 1 event */
    int			wheelButtonTimeout;/* Timeout for the wheel button emulation */
    CARD32		wheelButtonExpires;
    int			doubleClickSourceButtonMask;
    int			doubleClickTargetButton;
    int			doubleClickTargetButtonMask;
    int			doubleClickOldSourceState;
    int			lastMappedButtons;
    int			buttonMap[MSE_MAXBUTTONS];
} MouseDevRec, *MouseDevPtr;

xf86ActivateDevice

xf86ActivateDevice() is called then by InitInput() as:

/***********************************************************************
 *
 * xf86ActivateDevice --
 * 
 *	Initialize an input device.
 *
 ***********************************************************************
 */
void
xf86ActivateDevice(LocalDevicePtr local)
{
    DeviceIntPtr	dev;

    if (local->flags & XI86_CONFIGURED) {
	int	open_on_init;
	
	open_on_init = local->flags &
		(XI86_OPEN_ON_INIT |
		 XI86_ALWAYS_CORE | XI86_CORE_POINTER | XI86_CORE_KEYBOARD);
	
	dev = AddInputDevice(local->device_control,
			     open_on_init);
	if (dev == NULL)
	    FatalError("Too many input devices");
	
	local->atom = MakeAtom(local->type_name,
			       strlen(local->type_name),
			       TRUE);
	AssignTypeAndName (dev, local->atom, local->name);
	dev->public.devicePrivate = (pointer) local;
	local->dev = dev;      
	
	xf86XinputFinalizeInit(dev);

	/*
	 * XXX Can a single device instance be both core keyboard and
	 * core pointer?  If so, this should be changed.
	 */
	if (local->flags & XI86_CORE_POINTER)
	    RegisterPointerDevice(dev);
	else if (local->flags & XI86_CORE_KEYBOARD)
	    RegisterKeyboardDevice(dev);

#ifdef XINPUT
	else
	    RegisterOtherDevice(dev);
#endif

	if (serverGeneration == 1) 
	    xf86Msg(X_INFO, "XINPUT: Adding extended input device \"%s\" (type: %s)\n",
		    local->name, local->type_name);
    }
}

It mainly calls AddInputDevice() , (which actually calls _AddInputDevice) as:

	dev = AddInputDevice(local->device_control,
			     open_on_init);

DeviceIntPtr
_AddInputDevice(DeviceProc deviceProc, Bool autoStart)
{
    register DeviceIntPtr dev;

    if (inputInfo.numDevices >= MAX_DEVICES)
	return (DeviceIntPtr)NULL;
    dev = (DeviceIntPtr) xalloc(sizeof(DeviceIntRec));
    if (!dev)
	return (DeviceIntPtr)NULL;
    dev->type = 0;
    dev->id = inputInfo.numDevices;
    dev->public.on = FALSE;
    dev->public.processInputProc = (ProcessInputProc)NoopDDA;
    dev->public.realInputProc = (ProcessInputProc)NoopDDA;
    dev->public.enqueueInputProc = EnqueueEvent;
    dev->deviceProc = deviceProc;
    dev->startup = autoStart;
    dev->sync.frozen = FALSE;
    dev->sync.other = NullGrab;
    dev->sync.state = NOT_GRABBED;
    dev->sync.event = (xEvent *) NULL;
    dev->sync.evcount = 0;
    dev->grab = NullGrab;
    dev->grabTime = currentTime;
    dev->fromPassiveGrab = FALSE;
    dev->key = (KeyClassPtr)NULL;
    dev->valuator = (ValuatorClassPtr)NULL;
    dev->button = (ButtonClassPtr)NULL;
    dev->focus = (FocusClassPtr)NULL;
    dev->proximity = (ProximityClassPtr)NULL;
    dev->kbdfeed = (KbdFeedbackPtr)NULL;
    dev->ptrfeed = (PtrFeedbackPtr)NULL;
    dev->intfeed = (IntegerFeedbackPtr)NULL;
    dev->stringfeed = (StringFeedbackPtr)NULL;
    dev->bell = (BellFeedbackPtr)NULL;
    dev->leds = (LedFeedbackPtr)NULL;
    dev->next = inputInfo.off_devices;
#ifdef XKB
    dev->xkb_interest= NULL;
#endif
    dev->nPrivates = 0;
    dev->devPrivates = NULL;
    dev->unwrapProc = NULL;
    inputInfo.off_devices = dev;
    return dev;
}

For AddInputDevice() we read at xfree86.org:
"This DIX function allocates the device structure, registers a callback function (which handles device init, close, on and off), and returns the input handle, which can be treated as opaque. It is called once for each input device. Once input handles for core keyboard and core pointer devices have been obtained from AddInputDevice(), they are registered as core devices by calling RegisterPointerDevice() and RegisterKeyboardDevice()."

For the example we follow in the green box the local->device_control (or pInfo->device_control) is function MouseProc(). The second argument are flags added by the xf86ActivateDevice() to the pInfo->flags. Because flag XI86_CORE_POINTER is added now (along with XI86_OPEN_ON_INIT, XI86_ALWAYS_CORE and XI86_CORE_KEYBOARD) RegisterPointerDevice() is also called from xf86ActivateDevice():

void
_RegisterPointerDevice(DeviceIntPtr device)
{
    inputInfo.pointer = device;
#ifdef XKB
    device->public.processInputProc = CoreProcessPointerEvent;
    device->public.realInputProc = CoreProcessPointerEvent;
    if (!noXkbExtension)
       XkbSetExtension(device,ProcessPointerEvent);
#else
    device->public.processInputProc = ProcessPointerEvent;
    device->public.realInputProc = ProcessPointerEvent;
#endif
    device->ActivateGrab = ActivatePointerGrab;
    device->DeactivateGrab = DeactivatePointerGrab;
    if (!device->name)
    {
	char *p = "pointer";
	device->name = (char *)xalloc(strlen(p) + 1);
	strcpy(device->name, p);
    }
}

Example (continued)

DeviceIntPtr is defined in input.h as:

typedef struct _DeviceIntRec *DeviceIntPtr;

where _DeviceIntRec is defined in inputstr.h as:

typedef struct _DeviceIntRec {
    DeviceRec	public;
    DeviceIntPtr next;
    TimeStamp	grabTime;
    Bool	startup;		/* true if needs to be turned on at
				          server intialization time */
    DeviceProc	deviceProc;		/* proc(DevicePtr, DEVICE_xx). It is
					  used to initialize, turn on, or
					  turn off the device */
    Bool	inited;			/* TRUE if INIT returns Success */
    GrabPtr	grab;			/* the grabber - used by DIX */
    struct {
	Bool		frozen;
	int		state;
	GrabPtr		other;		/* if other grab has this frozen */
	xEvent		*event;		/* saved to be replayed */
	int		evcount;
    } sync;
    Atom		type;
    char		*name;
    CARD8		id;
    CARD8		activatingKey;
    Bool		fromPassiveGrab;
    GrabRec		activeGrab;
    void		(*ActivateGrab) (
			DeviceIntPtr /*device*/,
			GrabPtr /*grab*/,
			TimeStamp /*time*/,
			Bool /*autoGrab*/);
    void		(*DeactivateGrab)(
			DeviceIntPtr /*device*/);
    KeyClassPtr		key;
    ValuatorClassPtr	valuator;
    ButtonClassPtr	button;
    FocusClassPtr	focus;
    ProximityClassPtr	proximity;
    KbdFeedbackPtr	kbdfeed;
    PtrFeedbackPtr	ptrfeed;
    IntegerFeedbackPtr	intfeed;
    StringFeedbackPtr	stringfeed;
    BellFeedbackPtr	bell;
    LedFeedbackPtr	leds;
#ifdef XKB
    struct _XkbInterest *	xkb_interest;
#endif
    DevUnion		*devPrivates;
    int			nPrivates;
    DeviceUnwrapProc    unwrapProc;
} DeviceIntRec;

For the current example thread after xf86ActivateDevice() runs and therefore both AddInputDevice() and RegisterPointerDevice() are called the _DeviceIntRec, pointed by DeviceIntPtr (dev) becomes:

FieldValue
deviceProcMouseProc
startupautoStart (that is flags included in open_on_init)
initedTRUE
ActivateGrabActivatePointerGrab
DeactivateGrabDeactivatePointerGrab
name"pointer"
publicprocessInputProc = ProcessPointerEvent
realInputProc = ProcessPointerEvent

Note:
Field inited becomes TRUE when InitAndStartDevices() runs in section 3.2.4

field 'public' is of type _DeviceRec, which is defined in input.h as:


typedef struct _DeviceRec {
    pointer	devicePrivate;
    ProcessInputProc processInputProc;	/* current */
    ProcessInputProc realInputProc;	/* deliver */
    ProcessInputProc enqueueInputProc;	/* enqueue */
    Bool	on;			/* used by DDX to keep state */
} DeviceRec, *DevicePtr;

Notice that DeviceIntPtr points to a DeviceIntRec, defined in inputstr.h as:

typedef struct _DeviceIntRec {
    DeviceRec	public;
    DeviceIntPtr next;
    TimeStamp	grabTime;
    Bool	startup;		/* true if needs to be turned on at
				          server intialization time */
    DeviceProc	deviceProc;		/* proc(DevicePtr, DEVICE_xx). It is
					  used to initialize, turn on, or
					  turn off the device */
    Bool	inited;			/* TRUE if INIT returns Success */
    GrabPtr	grab;			/* the grabber - used by DIX */
    struct {
	Bool		frozen;
	int		state;
	GrabPtr		other;		/* if other grab has this frozen */
	xEvent		*event;		/* saved to be replayed */
	int		evcount;
    } sync;
    Atom		type;
    char		*name;
    CARD8		id;
    CARD8		activatingKey;
    Bool		fromPassiveGrab;
    GrabRec		activeGrab;
    void		(*ActivateGrab) (
			DeviceIntPtr /*device*/,
			GrabPtr /*grab*/,
			TimeStamp /*time*/,
			Bool /*autoGrab*/);
    void		(*DeactivateGrab)(
			DeviceIntPtr /*device*/);
    KeyClassPtr		key;
    ValuatorClassPtr	valuator;
    ButtonClassPtr	button;
    FocusClassPtr	focus;
    ProximityClassPtr	proximity;
    KbdFeedbackPtr	kbdfeed;
    PtrFeedbackPtr	ptrfeed;
    IntegerFeedbackPtr	intfeed;
    StringFeedbackPtr	stringfeed;
    BellFeedbackPtr	bell;
    LedFeedbackPtr	leds;
#ifdef XKB
    struct _XkbInterest *	xkb_interest;
#endif
    DevUnion		*devPrivates;
    int			nPrivates;
    DeviceUnwrapProc    unwrapProc;
} DeviceIntRec;

By returning to InitInput() aftter xf86ActivateDevice() and since corePointer was previously set in the InitInput() code and variable corePointer became pInfo the following execute in InitInput() :


    if (corePointer)
	xf86Info.pMouse = corePointer->dev;

Global struct xf86Info is defined in xf86Globals.c as:

/* Globals that video drivers may not access */

xf86InfoRec xf86Info = {
	NULL,		/* pKeyboard */
	NULL,		/* kbdProc */
	NULL,		/* kbdEvents */
	-1,		/* consoleFd */
	-1,		/* kbdFd */
	-1,		/* vtno */
	-1,		/* kbdType */
	-1,		/* kbdRate */
	-1, 		/* kbdDelay */
	-1,		/* bell_pitch */
	-1,		/* bell_duration */
	TRUE,		/* autoRepeat */
	0,		/* leds */
	0,		/* xleds */
	NULL,		/* vtinit */
	0,		/* scanPrefix */
	FALSE,		/* capsLock */
	FALSE,		/* numLock */
	FALSE,		/* scrollLock */
	FALSE,		/* modeSwitchLock */
	FALSE,		/* composeLock */
	FALSE,		/* vtSysreq */
	SKWhenNeeded,	/* ddxSpecialKeys */
	FALSE,		/* ActionKeyBindingsSet */
#if defined(SVR4) && defined(i386)
	FALSE,		/* panix106 */
#endif
#if defined(__OpenBSD__) || defined(__NetBSD__)
	0,		/* wskbdType */
#endif
	NULL,		/* pMouse */
#ifdef XINPUT
	NULL,		/* mouseLocal */
#endif
	-1,		/* lastEventTime */
	FALSE,		/* vtRequestsPending */
	FALSE,		/* inputPending */
	FALSE,		/* dontVTSwitch */
	FALSE,		/* dontZap */
	FALSE,		/* dontZoom */
	FALSE,		/* notrapSignals */
	FALSE,		/* caughtSignal */
	FALSE,		/* sharedMonitor */
	NULL,		/* currentScreen */
#ifdef CSRG_BASED
	-1,		/* screenFd */
	-1,		/* consType */
#endif
#ifdef XKB
	NULL,		/* xkbkeymap */
	NULL,		/* xkbkeycodes */
	NULL,		/* xkbtypes */
	NULL,		/* xkbcompat */
	NULL,		/* xkbsymbols */
	NULL,		/* xkbgeometry */
	FALSE,		/* xkbcomponents_specified */
	NULL,		/* xkbrules */
	NULL,		/* xkbmodel */
	NULL,		/* xkblayout */
	NULL,		/* xkbvariant */
	NULL,		/* xkboptions */
#endif
	FALSE,		/* allowMouseOpenFail */
	TRUE,		/* vidModeEnabled */
	FALSE,		/* vidModeAllowNonLocal */
	TRUE,		/* miscModInDevEnabled */
	FALSE,		/* miscModInDevAllowNonLocal */
	PCIOsConfig,	/* pciFlags */
	Pix24DontCare,	/* pixmap24 */
	X_DEFAULT,	/* pix24From */
#if defined(i386) || defined(__i386__)
	FALSE,		/* pc98 */
#endif
	TRUE,		/* pmFlag */
	LogNone,	/* syncLog */
	0,		/* estimateSizesAggressively */
	FALSE,		/* kbdCustomKeycodes */
	FALSE,		/* disableRandR */
	X_DEFAULT	/* randRFrom */
};

The usage of xf86Info pKeyboard and pMouse fields that are filled in InitInput() (see blue characters in the InitInput() source code above) can be found in section 3.2.5.1.

For the mieqInit() call see section 3.2.5.1.

REFERENCES:

The DESIGN Document
Input Driver Specifications
Xorg Input HOWTO
The XFree86 Architecture
Distributed Multihead X design