Hands-on Projects for the Linux Graphics Subsystem
|
As seen in section 5.1 function xf86AddEnabledDevice() is called from MouseProc() (generally speaking the
pInfo->device_control routine) when called with a DEVICE_ON as the second argument. It is implemented as:
/* * xf86AddEnabledDevice -- * */ void xf86AddEnabledDevice(InputInfoPtr pInfo) { if (!xf86InstallSIGIOHandler (pInfo->fd, xf86SigioReadInput, pInfo)) { AddEnabledDevice(pInfo->fd); } } |
The first function called by xf86AddEnabledDevice(), xf86InstallSIGIOHandler(), is implemented as:
int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *closure) { struct sigaction sa; struct sigaction osa; int i; int blocked; for (i = 0; i < MAX_FUNCS; i++) { if (!xf86SigIOFuncs[i].f) { if (xf86IsPipe (fd)) return 0; blocked = xf86BlockSIGIO(); if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC) == -1) { #ifdef XFree86Server xf86Msg(X_WARNING, "fcntl(%d, O_ASYNC): %s\n", fd, strerror(errno)); #else fprintf(stderr,"fcntl(%d, O_ASYNC): %s\n", fd, strerror(errno)); #endif xf86UnblockSIGIO(blocked); return 0; } if (fcntl(fd, F_SETOWN, getpid()) == -1) { #ifdef XFree86Server xf86Msg(X_WARNING, "fcntl(%d, F_SETOWN): %s\n", fd, strerror(errno)); #else fprintf(stderr,"fcntl(%d, F_SETOWN): %s\n", fd, strerror(errno)); #endif xf86UnblockSIGIO(blocked); return 0; } sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGIO); sa.sa_flags = 0; sa.sa_handler = xf86SIGIO; sigaction(SIGIO, &sa, &osa); xf86SigIOFuncs[i].fd = fd; xf86SigIOFuncs[i].closure = closure; xf86SigIOFuncs[i].f = f; if (i >= xf86SigIOMax) xf86SigIOMax = i+1; if (fd >= xf86SigIOMaxFd) xf86SigIOMaxFd = fd + 1; FD_SET (fd, &xf86SigIOMask); xf86UnblockSIGIO(blocked); return 1; } /* Allow overwriting of the closure and callback */ else if (xf86SigIOFuncs[i].fd == fd) { xf86SigIOFuncs[i].closure = closure; xf86SigIOFuncs[i].f = f; return 1; } } return 0; } |
xf86InstallSIGIOHandler() installs xf86SigioReadInput() as the function that responds to a SIGIO signal. This signal is issued when input is available from a certain input device file descriptor (fd). Normally SIGIO can not be assigned to a specific fd however this is solved through an indirect way:
xf86InstallSIGIOHandler() calls sigaction() to install xf86SIGIO() as the signal handler for SIGIO and this function will do what its comment notes: * SIGIO gives no way of discovering which fd signalled, select * to discoverTherefore to install a signal handler, for instance function f, for a specific fd via xf86InstallSIGIOHandler() another function, xf86SIGIO(), is assigned as the signal handler and this function represents all others signal handlers set by different fds. It uses the array xf86SigIOFuncs[] to store at the next available element a Xf86SigIOFunc struct, which includes the fd of the device, the specific handler (f) and the pInfo (InputInfoPtr) of the device, referred here as 'closure'. Also the fd in included in the xf86SigIOMask fd set. When xf86SIGIO() runs it uses the select() system call to find the ready fds from xf86SigIOMask and return its number to xf86SigIOMaxFd. Then it searches in xf86SigIOFuncs[] to locate the array's items with the fds that are included in xf86SigIOMask. For those items the specific handler routine is called as: (*xf86SigIOFuncs[i].f)(xf86SigIOFuncs[i].fd, xf86SigIOFuncs[i].closure);As seen previously from xf86AddEnabledDevice() the handler routine used is xf86SigioReadInput(), which calls the read_input function from the pInfo that owns the specific fd. pInfo->read_input(pInfo);
|
xf86SigIOFuncs[] is defined in sigio.c as:
static Xf86SigIOFunc xf86SigIOFuncs[MAX_FUNCS]; |
Xf86SigIOFunc is defined in the same file as:
typedef struct _xf86SigIOFunc { void (*f) (int, void *); int fd; void *closure; } Xf86SigIOFunc; |
where MAX_FUNCS is the maximum number of devices and is defined in the same file as:
#ifdef MAX_DEVICES /* MAX_DEVICES represents the maximimum number of input devices usable * at the same time plus one entry for DRM support. */ # define MAX_FUNCS (MAX_DEVICES + 1) #else # define MAX_FUNCS 16 #endif |
When a SIGIO is received by the X Server xf86SIGIO() runs:
/* * SIGIO gives no way of discovering which fd signalled, select * to discover */ static void xf86SIGIO (int sig) { int i; fd_set ready; struct timeval to; int r; ready = xf86SigIOMask; to.tv_sec = 0; to.tv_usec = 0; SYSCALL (r = select (xf86SigIOMaxFd, &ready, 0, 0, &to)); for (i = 0; r > 0 && i < xf86SigIOMax; i++) if (xf86SigIOFuncs[i].f && FD_ISSET (xf86SigIOFuncs[i].fd, &ready)) { (*xf86SigIOFuncs[i].f)(xf86SigIOFuncs[i].fd, xf86SigIOFuncs[i].closure); r--; } #ifdef XFree86Server if (r > 0) { xf86Msg(X_ERROR, "SIGIO %d descriptors not handled\n", r); } #endif } |
As function *xf86SigIOFuncs[i].f was set by xf86InstallSIGIOHandler() the xf86SigioReadInput, which is implemented as:
/* * xf86SigioReadInput -- * signal handler for the SIGIO signal. */ static void xf86SigioReadInput(int fd, void *closure) { int sigstate = xf86BlockSIGIO(); InputInfoPtr pInfo = (InputInfoPtr) closure; pInfo->read_input(pInfo); xf86UnblockSIGIO(sigstate); } |
ExampleIn the example we follow as pInfo->read_input was set MouseReadInput(), which we examine in section 5.1.3 |
The second function called from xf86AddEnabledDevice(), AddEnabledDevice(), is implemented as:
void AddEnabledDevice(int fd) { FD_SET(fd, &EnabledDevices); FD_SET(fd, &AllSockets); if (GrabInProgress) FD_SET(fd, &SavedAllSockets); } |
AddEnabledDevice() adds the input device fd to EnabledDevices (this is how EnabledDevices is filled) and to AllSockets sets. We met those sets at section 3.2.5.2.
REFERENCES