-> evdev + multimedia kbd => xf86Xinput: LookupDeviceIntRec id=0x0 not found

The text below describes the interaction between a Logitech UltraX 
media keyboard, part 867618-0123 or 967568-0123, the evdev driver, and 
the xorg server.  The keyboard announces mouse buttons which might 
cause the found difficulty.

The keyboard's entry in /proc/bus/input/devices is 

I: Bus=0003 Vendor=046d Product=c30e Version=0180
N: Name="Logitech HID compliant keyboard"
P: Phys=usb-0000:00:1d.0-2.1/input0
S: Sysfs=/class/input/input22
H: Handlers=kbd event0 
B: EV=120003
B: KEY=10000 7 ff800000 7ff febeffdf f3cfffff ffffffff fffffffe
B: LED=7

I: Bus=0003 Vendor=046d Product=c30e Version=0180
N: Name="Logitech HID compliant keyboard"
P: Phys=usb-0000:00:1d.0-2.1/input1
S: Sysfs=/class/input/input23
H: Handlers=kbd event1 
B: EV=3
B: KEY=fff ffffffff ffffffff 0 0 387a d800d101 1e0000 0 0 0

where the endpoint input1 corresponds to the multimedia
keys, Media, Play/Pause, Mute, Favorites, E-Mail, WWW.  Note that 
the KEY bitfield advertizes 76 mouse buttons.  

Using one driver for input0 and input1 doesn't work, it results in 
LookupDeviceIntRec id=0x1 and LookupDeviceIntRec id=0x0 not found 
errors when pressing a key.  However, configuring two keyboard drivers 
through 

Section "InputDevice"
    Identifier  "KeybkSeat0"
    Driver "evdev"
    Option "phys" "usb-0000:00:1d.0-2.*/input0"
    Option "evBits" "+1"
    Option "keyBits" "~1-255 ~352-511"
    Option "Pass" "3"
    Option "XkbRules"   "xorg"
    Option "XkbModel"   "evdev"
    Option "XkbLayout"  "be"
    Option "XkbVariant" "wang2"
EndSection

Section "InputDevice"
    Identifier  "KeyblSeat0"
    Driver "evdev"
    Option "phys" "usb-0000:00:1d.0-2.*/input1"
    Option "evBits" "+1"
    Option "keyBits" "~1-255 ~352-511"
    Option "Pass" "3"
    Option "XkbRules"   "xorg"
    Option "XkbModel"   "evdev"
    Option "XkbLayout"  "be"
EndSection

Section "InputDevice"
    Identifier  "MouseSeat0"
    Driver "evdev"
    Option "phys" "usb-0000:00:1d.0-2.*/input0"
    Option "evBits"  "+1-2"
    Option "keyBits" "~272-287"
    Option "relBits" "~0-2 ~6 ~8"
    Option "Pass"    "3"
EndSection

gives the evdev_brain.c: evdev_drivers tree 

             Newdriver         ScanDevice EvdevNew   
                +--- driver1 ---- device=KeybkSeat0-usb-0000:00:1d.0-2.1/input0
                |     |               
  evdevStart ---+--- driver2 ---- device=KeyblSeat0-usb-0000:00:1d.0-2.1/input1
  _pInfo        |     |               
                +--- driver3 ---- device=MouseSeat0-usb-0000:00:1d.0-2.3/input0
                      |
  RescanDevices --> _drivers

and with a ServerLayout including

    InputDevice "KeybkSeat0" "CoreKeyboard"
    InputDevice "KeyblSeat0"
    InputDevice "MouseSeat0" "CorePointer"

results in a working primary keyboard.  Still, pressing a multimedia
key gives the error LookupDeviceIntRec id=0x0 not found from xf86Xinput.c.

If this error is due to the incorrectly detected mouse buttons, then a 
workaround might be to extend the  <map>Bits  syntax 

  +[bitnr | range]  must be set
  -[bitnr | range]  must be unset
  ~[bitnr | range]  any must be set

with 

  =[bitnr | range]  are zeroed before any processing occurs

such that the keyBits 256-331 can be zeroed out.  Or perhaps it is possible
to solve the LookupDeviceIntRec error, although a first look at the 
Xi/extinit.c code doesn't seem to point out a straightforward way.  
-------------------------------------------------------------------------
-> patch to zero <map>Bits before processing capabilities 

This patch allows to zero <map>Bits and thus to turn off 
capabilities which are incorrectly announced by a keyboard or
mouse.  This happens after driver matching and just before processing 
an unseen device through the driver callback EvdevNew(). 

For example, a keyboard which advertizes non-existent buttons can be 
fixed through the syntax 

  Option "keyBits" "~1-255 =256-351 ~352-511"

where the =256-351 specification zeroes all 96 button entries.  

However, it didn't solve the initial problem.  Using two keyboard 
drivers with one device each results in a working primary CoreKeyboard 
but gives the "LookupDeviceIntRec id=0x0 not found" error when pressing
a key on the secondary.  Using one CoreKeyboard with two devices results
in the same error with id=0x1 and id=0x0.  

So, it seems that evdev is not the cause here, but that this is actually 
an xinput bug.
-------------------------------------------------------------------------
Index: driver/xf86-input-evdev/src/evdev.c
===================================================================
RCS file: /cvs/xorg/driver/xf86-input-evdev/src/evdev.c,v
retrieving revision 1.19
diff -u -r1.19 evdev.c
--- driver/xf86-input-evdev/src/evdev.c	14 May 2006 11:55:50 -0000	1.19
+++ driver/xf86-input-evdev/src/evdev.c	14 Jun 2006 18:07:29 -0000
@@ -243,6 +243,15 @@
     return Success;
 }
 
+static void
+ForceOff (unsigned long *dev, unsigned long *foff, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+      dev[i] &= ~foff[i];
+}
+
 static Bool
 EvdevNew(evdevDriverPtr driver, evdevDevicePtr device)
 {
@@ -288,6 +297,20 @@
 	return 0;
     }
 
+#define foff(which)	\
+    ForceOff(device->bits.which, driver->off_bits.which,	\
+	     sizeof(driver->off_bits.which)/sizeof(driver->off_bits.which[0]));
+
+    foff(ev)
+    foff(key)
+    foff(rel)
+    foff(abs)
+    foff(msc)
+    foff(led)
+    foff(snd)
+    foff(ff)
+#undef foff
+
     if (ioctl(pInfo->fd, EVIOCGRAB, (void *)1)) {
 	xf86Msg(X_INFO, "%s: Unable to grab device (%s).  Cowardly refusing to check use as keyboard.\n", pInfo->name, strerror(errno));
 	device->state.can_grab = 0;
@@ -349,7 +372,7 @@
 }
 
 static void
-EvdevParseBitOption (char *opt, unsigned long *all, unsigned long *not, unsigned long *any, int len)
+EvdevParseBitOption (char *opt, unsigned long *all, unsigned long *not, unsigned long *any, unsigned long *off, int len)
 {
     char *cur, *next;
 
@@ -369,6 +392,9 @@
 	    case '~':
 		EvdevParseBits (cur + 1, any, len);
 		break;
+	    case '=':
+		EvdevParseBits (cur + 1, off, len);
+		break;
 	}
     }
 }
@@ -393,6 +419,7 @@
 	EvdevParseBitOption (tmp, pEvdev->all_bits.field,			\
 		pEvdev->not_bits.field,					\
 		pEvdev->any_bits.field,					\
+		pEvdev->off_bits.field,					\
 		sizeof(pEvdev->not_bits.field) / sizeof (unsigned long));	\
 	free (tmp);								\
     }
Index: driver/xf86-input-evdev/src/evdev.h
===================================================================
RCS file: /cvs/xorg/driver/xf86-input-evdev/src/evdev.h,v
retrieving revision 1.7
diff -u -r1.7 evdev.h
--- driver/xf86-input-evdev/src/evdev.h	15 May 2006 22:47:23 -0000	1.7
+++ driver/xf86-input-evdev/src/evdev.h	14 Jun 2006 18:07:29 -0000
@@ -76,7 +76,7 @@
 #define BITS_PER_LONG		(sizeof(unsigned long) * 8)
 #endif
 
-#define NBITS(x)		((((x)-1)/BITS_PER_LONG)+1)
+#define NLONGS(x)		(((x)/BITS_PER_LONG)+1)
 #define LONG(x)			((x)/BITS_PER_LONG)
 #define MASK(x)			(1UL << ((x) & (BITS_PER_LONG - 1)))
 
@@ -137,14 +137,14 @@
 #define EVDEV_MAXBUTTONS	96
 
 typedef struct {
-    unsigned long	ev[NBITS(EV_MAX)];
-    unsigned long	key[NBITS(KEY_MAX)];
-    unsigned long	rel[NBITS(REL_MAX)];
-    unsigned long	abs[NBITS(ABS_MAX)];
-    unsigned long	msc[NBITS(MSC_MAX)];
-    unsigned long	led[NBITS(LED_MAX)];
-    unsigned long	snd[NBITS(SND_MAX)];
-    unsigned long	ff[NBITS(FF_MAX)];
+    unsigned long	ev[NLONGS(EV_MAX)];
+    unsigned long	key[NLONGS(KEY_MAX)];
+    unsigned long	rel[NLONGS(REL_MAX)];
+    unsigned long	abs[NLONGS(ABS_MAX)];
+    unsigned long	msc[NLONGS(MSC_MAX)];
+    unsigned long	led[NLONGS(LED_MAX)];
+    unsigned long	snd[NLONGS(SND_MAX)];
+    unsigned long	ff[NLONGS(FF_MAX)];
 } evdevBitsRec, *evdevBitsPtr;
 
 typedef struct {
@@ -225,6 +225,7 @@
     evdevBitsRec	all_bits;
     evdevBitsRec	not_bits;
     evdevBitsRec	any_bits;
+    evdevBitsRec	off_bits;
 
     struct input_id	id;
 
