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

InitAndStartDevices()

As we read from Distributed Multihead X design:

InitAndStartDevices() is a DIX function that is called immediately after InitInput() from the X server's main() function. Its purpose is to initialize each input device that was registered with AddInputDevice(), enable each input device that was successfully initialized, and create the list of enabled input devices.

InitAndStartDevices() is implemented as:

int
InitAndStartDevices()
{
    register DeviceIntPtr dev, next;

    for (dev = inputInfo.off_devices; dev; dev = dev->next)
	dev->inited = ((*dev->deviceProc)(dev, DEVICE_INIT) == Success);
    for (dev = inputInfo.off_devices; dev; dev = next)
    {
	next = dev->next;
	if (dev->inited && dev->startup)
	    (void)EnableDevice(dev);
    }
    for (dev = inputInfo.devices;
	 dev && (dev != inputInfo.keyboard);
	 dev = dev->next)
	;
    if (!dev || (dev != inputInfo.keyboard)) {
	ErrorF("No core keyboard\n");
	return BadImplementation;
    }
    for (dev = inputInfo.devices;
	 dev && (dev != inputInfo.pointer);
	 dev = dev->next)
	;
    if (!dev || (dev != inputInfo.pointer)) {
	ErrorF("No core pointer\n");
	return BadImplementation;
    }
    return Success;
}

inputInfo is the struct that holds core pointer and keyboard info. We met it first when _AddInputDevice() run. It is defined in inputstr.h as:

typedef struct {
    int			numDevices;	/* total number of devices */
    DeviceIntPtr	devices;	/* all devices turned on */
    DeviceIntPtr	off_devices;	/* all devices turned off */
    DeviceIntPtr	keyboard;	/* the main one for the server */
    DeviceIntPtr	pointer;
} InputInfo;

In the example we follow as seen in 3.2.3 deviceProc is MouseProc(). This is implemented as:

static int
MouseProc(DeviceIntPtr device, int what)
{
    InputInfoPtr pInfo;
    MouseDevPtr pMse;
    mousePrivPtr mPriv;
    unsigned char map[MSE_MAXBUTTONS + 1];
    int i;
    
    pInfo = device->public.devicePrivate;
    pMse = pInfo->private;
    pMse->device = device;

    switch (what)
    {
    case DEVICE_INIT:
	device->public.on = FALSE;
	/*
	 * [KAZU-241097] We don't know exactly how many buttons the
	 * device has, so setup the map with the maximum number.
	 */
	for (i = 0; i < MSE_MAXBUTTONS; i++)
	    map[i + 1] = i + 1;

	InitPointerDeviceStruct((DevicePtr)device, map,
				min(pMse->buttons, MSE_MAXBUTTONS),
				miPointerGetMotionEvents, pMse->Ctrl,
				miPointerGetMotionBufferSize());

	/* X valuator */
	xf86InitValuatorAxisStruct(device, 0, 0, -1, 1, 0, 1);
	xf86InitValuatorDefaults(device, 0);
	/* Y valuator */
	xf86InitValuatorAxisStruct(device, 1, 0, -1, 1, 0, 1);
	xf86InitValuatorDefaults(device, 1);
	xf86MotionHistoryAllocate(pInfo);

#ifdef EXTMOUSEDEBUG
	ErrorF("assigning %p atom=%d name=%s\n", device, pInfo->atom,
		pInfo->name);
#endif
	break;

    case DEVICE_ON:
	pInfo->fd = xf86OpenSerial(pInfo->options);
	if (pInfo->fd == -1)
	    xf86Msg(X_WARNING, "%s: cannot open input device\n", pInfo->name);
	else {
	    if (pMse->xisbscale)
		pMse->buffer = XisbNew(pInfo->fd, pMse->xisbscale * 4);
	    else
		pMse->buffer = XisbNew(pInfo->fd, 64);
	    if (!pMse->buffer) {
		xf86CloseSerial(pInfo->fd);
		pInfo->fd = -1;
	    } else {
		if (!SetupMouse(pInfo)) {
		    xf86CloseSerial(pInfo->fd);
		    pInfo->fd = -1;
		    XisbFree(pMse->buffer);
		    pMse->buffer = NULL;
		} else {
		    mPriv = (mousePrivPtr)pMse->mousePriv;
		    if (mPriv != NULL) {
			if ( pMse->protocolID != PROT_AUTO) {
			    pMse->inSync = TRUE; /* @@@ */
			    if (mPriv->soft)
				mPriv->autoState = AUTOPROBE_GOOD;
			    else
				mPriv->autoState = AUTOPROBE_H_GOOD;
			} else {
			    if (mPriv->soft)
				mPriv->autoState = AUTOPROBE_NOPROTO;
			    else
				mPriv->autoState = AUTOPROBE_H_NOPROTO;
			}
		    }
		    xf86FlushInput(pInfo->fd);
		    xf86AddEnabledDevice(pInfo);

		}
	    }
	}
	pMse->lastButtons = 0;
	pMse->lastMappedButtons = 0;
	pMse->emulateState = 0;
	pMse->emulate3Pending = FALSE;
	pMse->wheelButtonExpires = GetTimeInMillis ();
	device->public.on = TRUE;
	FlushButtons(pMse);
	if (pMse->emulate3Buttons || pMse->emulate3ButtonsSoft)
	{
	    RegisterBlockAndWakeupHandlers (MouseBlockHandler, MouseWakeupHandler,
					    (pointer) pInfo);
	}
	break;
	    
    case DEVICE_OFF:
    case DEVICE_CLOSE:
	if (pInfo->fd != -1) {
	    xf86RemoveEnabledDevice(pInfo);
	    if (pMse->buffer) {
		XisbFree(pMse->buffer);
		pMse->buffer = NULL;
	    }
	    xf86CloseSerial(pInfo->fd);
	    pInfo->fd = -1;
	    if (pMse->emulate3Buttons || pMse->emulate3ButtonsSoft)
	    {
		RemoveBlockAndWakeupHandlers (MouseBlockHandler, MouseWakeupHandler,
					      (pointer) pInfo);
	    }
	}
	device->public.on = FALSE;
	usleep(300000);
	break;
    }
    return Success;
}

InitAndStartDevices() calls therefore MouseProc() with a second argument the DEVICE_INIT. As a first argument is receives the current DeviceIntPtr, which is presented in the example of section 3.2.3

For the case DEVICE_INIT function InitPointerDeviceStruct() is called, implemented in devices.c as:


Bool
InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, 
                        ValuatorMotionProcPtr motionProc, 
                        PtrCtrlProcPtr controlProc, int numMotionEvents)
{
    DeviceIntPtr dev = (DeviceIntPtr)device;

    return(InitButtonClassDeviceStruct(dev, numButtons, map) &&
	   InitValuatorClassDeviceStruct(dev, 2, motionProc,
					 numMotionEvents, 0) &&
	   InitPtrFeedbackClassDeviceStruct(dev, controlProc));
}

The second major routine InitAndStartDevices() calls is EnableDevice():

Bool
EnableDevice(register DeviceIntPtr dev)
{
    register DeviceIntPtr *prev;

    for (prev = &inputInfo.off_devices;
	 *prev && (*prev != dev);
	 prev = &(*prev)->next)
	;
    if ((*prev != dev) || !dev->inited ||
	((*dev->deviceProc)(dev, DEVICE_ON) != Success))

	return FALSE;
    *prev = dev->next;
    dev->next = inputInfo.devices;
    inputInfo.devices = dev;
    return TRUE;
}

This calls the deviceProc (MouseProc for the current example) with a second argument DEVICE_ON.

For the case DEVICE_ON MouseProc() calls xf86OpenSerial() implemented in posix_tty.c.

xf86OpenSerial() finds the device to open by calling

	dev = xf86SetStrOption (options, "Device", NULL);

xf86SetStrOption() calls LookupStrOption() and this ParseOptionValue() to obtain the device name from the pInfo options.

xf86OpenSerial() calls then the open() syscall as:

	SYSCALL (fd = open (dev, O_RDWR | O_NONBLOCK));

Example

For the current example the device name would be the pInfo.name that is "Mouse0". Also LookupStrOption() would search for the option "Device", which returns "/dev/input/mice".

The open() system call therefore would be issued as:

fd = open ("/dev/input/mice", O_RDWR | O_NONBLOCK);

Next SetupMouse() is called.

Finally xf86AddEnabledDevice() is called to add the fd to the ones monitored by the event loop. It calls xf86InstallSIGIOHandler() which installs the signal handler via sigaddset(), sigaction() system calls. The installed signal is SIGIO, which is mainly generated when new data arrive at the socket.