Hands-on Projects for the Linux Graphics Subsystem
|
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)); |
ExampleFor 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.