Uma explicação definitiva que você pode pelo menos encontrar nos fontes do kernel, mais especificamente drivers/input/evdev.c :
static long evdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p, int compat_mode)
{
[…]
switch (cmd) {
[…]
case EVIOCGRAB:
if (p)
return evdev_grab(evdev, client);
else
return evdev_ungrab(evdev, client);
[…]
}
[…]
}
Pelo que entendi, tudo o que é avaliado como "false" ( 0 ) levará a evdev_ungrab ( (void*)0 , 0 ,…), tudo que é "verdadeiro" (não 0 ) causará um evdev_grab ( (void*)1 , 1 , 0xDEADBEEF …).
Uma coisa que vale a pena mencionar é que seu primeiro exemplo,
int grab = 1;
ioctl(fd, EVIOCGRAB, &grab);
..
ioctl(fd, EVIOCGRAB, NULL);
funciona apenas de forma não intencional. Não é o valor dentro de grab , mas o fato de que &grab é diferente de zero (você poderia ter adivinhado isso, já que a caixa não é grab = 0; ioctl(…, &grab); mas ioctl(…, NULL); Engraçado.:)