--- a/evdev.c	2008-12-03 08:36:59.000000000 +0200
+++ b/evdev.c	2008-12-03 16:20:53.000000000 +0200
@@ -1333,8 +1333,10 @@
     long rel_bitmask[NBITS(REL_MAX)] = {0};
     long abs_bitmask[NBITS(ABS_MAX)] = {0};
     int i, has_axes, has_keys, num_buttons, has_scroll;
+    int as_mouse, as_touchpad, as_touchscreen, as_keyboard;
     int kernel24 = 0;
     EvdevPtr pEvdev = pInfo->private;
+    pointer pOpts = pInfo->options;
 
     if (pEvdev->grabDevice && ioctl(pInfo->fd, EVIOCGRAB, (void *)1)) {
         if (errno == EINVAL) {
@@ -1367,6 +1369,8 @@
         return 1;
     }
 
+    as_mouse = as_touchpad = as_touchscreen = as_keyboard = FALSE;
+
     has_axes = FALSE;
     has_keys = FALSE;
     has_scroll = FALSE;
@@ -1379,91 +1383,139 @@
             num_buttons++;
     }
 
-    if (num_buttons)
-    {
-        pEvdev->flags |= EVDEV_BUTTON_EVENTS;
-        pEvdev->buttons = num_buttons;
-        xf86Msg(X_INFO, "%s: Found %d mouse buttons\n", pInfo->name,
-                num_buttons);
-    }
-
-    if (TestBit(REL_X, rel_bitmask) && TestBit(REL_Y, rel_bitmask)) {
-        xf86Msg(X_INFO, "%s: Found x and y relative axes\n", pInfo->name);
-	pEvdev->flags |= EVDEV_RELATIVE_EVENTS;
-	has_axes = TRUE;
-    }
+    /* query axes */
+    if (TestBit(REL_X, rel_bitmask) && TestBit(REL_Y, rel_bitmask) ||
+        TestBit(ABS_X, abs_bitmask) && TestBit(ABS_Y, abs_bitmask))
+        has_axes = TRUE;
 
-    if (TestBit(REL_WHEEL, rel_bitmask) || TestBit(REL_HWHEEL, rel_bitmask)) {
-        xf86Msg(X_INFO, "%s: Found scroll wheel(s)\n", pInfo->name);
+    /* poll scroll */
+    if (TestBit(REL_WHEEL, rel_bitmask) || TestBit(REL_HWHEEL, rel_bitmask))
         has_scroll = TRUE;
-    }
-
-    if (TestBit(ABS_X, abs_bitmask) && TestBit(ABS_Y, abs_bitmask)) {
-        xf86Msg(X_INFO, "%s: Found x and y absolute axes\n", pInfo->name);
-	pEvdev->flags |= EVDEV_ABSOLUTE_EVENTS;
-	if (TestBit(BTN_TOUCH, key_bitmask)) {
-            if (num_buttons) {
-                xf86Msg(X_INFO, "%s: Found absolute touchpad\n", pInfo->name);
-                pEvdev->flags |= EVDEV_TOUCHPAD;
-                pEvdev->old_x = pEvdev->old_y = -1;
-            } else {
-                xf86Msg(X_INFO, "%s: Found absolute touchscreen\n", pInfo->name);
-                pEvdev->flags |= EVDEV_TOUCHSCREEN;
-                pEvdev->flags |= EVDEV_BUTTON_EVENTS;
-            }
-	}
-	has_axes = TRUE;
-    }
 
+    /* find keys */
     for (i = 0; i < BTN_MISC; i++)
         if (TestBit(i, key_bitmask))
             break;
+    if (i < BTN_MISC)
+        has_keys = TRUE;
 
-    if (i < BTN_MISC) {
-        xf86Msg(X_INFO, "%s: Found keys\n", pInfo->name);
-	pEvdev->flags |= EVDEV_KEYBOARD_EVENTS;
-	has_keys = TRUE;
-    }
 
+    /* mouse caps */
     if (has_axes && num_buttons) {
-        xf86Msg(X_INFO, "%s: Configuring as mouse\n", pInfo->name);
-	pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
-	    XI86_CONFIGURED;
-	pInfo->type_name = XI_MOUSE;
+        pInfo->flags |= XI86_CONFIGURED;
+        as_mouse = TRUE;
     }
 
-    if (pEvdev->flags & EVDEV_TOUCHSCREEN) {
-        xf86Msg(X_INFO, "%s: Configuring as touchscreen\n", pInfo->name);
-        pInfo->type_name = XI_TOUCHSCREEN;
-        pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
-                        XI86_CONFIGURED;
-    }
+    /* touchscreen/touchpad caps */
+    if (TestBit(ABS_X, abs_bitmask) && TestBit(ABS_Y, abs_bitmask))
+        if (TestBit(BTN_TOUCH, key_bitmask)) {
+            pInfo->flags |= XI86_CONFIGURED;
+            xf86Msg(X_INFO, "%s: Found absolute %s\n",
+                    pInfo->name, num_buttons ? "touchpad" : "touchscreen");
+            if (num_buttons)
+                as_touchpad = TRUE;
+            else
+                as_touchscreen = TRUE;
+        }
 
+    /* keyboard caps */
     if (has_keys) {
         if (kernel24) {
             xf86Msg(X_INFO, "%s: Kernel < 2.6 is too old, ignoring keyboard\n",
                     pInfo->name);
         } else {
-            xf86Msg(X_INFO, "%s: Configuring as keyboard\n", pInfo->name);
-            pInfo->flags |= XI86_KEYBOARD_CAPABLE | XI86_CONFIGURED;
-	    pInfo->type_name = XI_KEYBOARD;
+            pInfo->flags |= XI86_CONFIGURED;
+	    as_keyboard = TRUE;
         }
     }
 
-    if (has_scroll && (pInfo->flags & XI86_CONFIGURED) &&
-        (pInfo->flags & XI86_POINTER_CAPABLE) == 0)
-    {
-        xf86Msg(X_INFO, "%s: Adding scrollwheel support\n", pInfo->name);
-        pInfo->flags  |= XI86_POINTER_CAPABLE;
-        pEvdev->flags |= EVDEV_BUTTON_EVENTS;
-        pEvdev->flags |= EVDEV_RELATIVE_EVENTS;
-    }
-
     if ((pInfo->flags & XI86_CONFIGURED) == 0) {
         xf86Msg(X_WARNING, "%s: Don't know how to use device\n",
 		pInfo->name);
         return 1;
     }
+    else {
+        /* UseAsPointing and UseAsKeyboard, when specified, */
+        /* completely ignore one use for another, forcing type_name; */
+        /* otherwise, keyboard (if any) wins "at no cost". */
+        int is_ptr = as_mouse || as_touchpad || as_touchscreen;
+        int is_kbd = as_keyboard;
+
+        if (is_kbd && is_ptr) {
+            is_ptr = xf86CheckBoolOption(pOpts, "UseAsPointing", FALSE);
+            is_kbd = xf86CheckBoolOption(pOpts, "UseAsKeyboard", FALSE);
+            if (is_kbd && is_ptr)
+                xf86Msg(X_INFO, "%s: Don't care how you set device\n",
+                        pInfo->name);
+            else if (is_ptr)
+                as_keyboard = FALSE;
+            else if (is_kbd)
+                as_mouse = as_touchpad = as_touchscreen = has_scroll = FALSE;
+        } else {
+            is_ptr = (is_ptr == xf86SetBoolOption(pOpts, "UseAsPointing", is_ptr));
+            is_kbd = (is_kbd == xf86SetBoolOption(pOpts, "UseAsKeyboard", is_kbd));
+            if (!is_ptr || !is_kbd)
+                xf86Msg(X_INFO, "%s: Don't mind how you see device\n",
+                        pInfo->name);
+        }
+    }
+
+    if (as_keyboard) {
+        xf86Msg(X_INFO, "%s: Found keys\n", pInfo->name);
+        pEvdev->flags |= EVDEV_KEYBOARD_EVENTS;
+    }
+
+    if (as_mouse || as_touchpad || as_touchscreen) {
+        if (num_buttons) {
+            xf86Msg(X_INFO, "%s: Found %d mouse buttons\n", pInfo->name,
+                    num_buttons);
+            pEvdev->flags |= EVDEV_BUTTON_EVENTS;
+            pEvdev->buttons = num_buttons;
+        }
+        if (has_scroll) {
+            xf86Msg(X_INFO, "%s: Found scroll wheel(s)\n", pInfo->name);
+        }
+        if (TestBit(REL_X, rel_bitmask) && TestBit(REL_Y, rel_bitmask)) {
+            xf86Msg(X_INFO, "%s: Found x and y relative axes\n", pInfo->name);
+            pEvdev->flags |= EVDEV_RELATIVE_EVENTS;
+        }
+        if (TestBit(ABS_X, abs_bitmask) && TestBit(ABS_Y, abs_bitmask)) {
+            xf86Msg(X_INFO, "%s: Found x and y absolute axes\n", pInfo->name);
+            pEvdev->flags |= EVDEV_ABSOLUTE_EVENTS;
+        }
+    } else if (has_scroll) {
+        xf86Msg(X_INFO, "%s: Adding scrollwheel support\n", pInfo->name);
+        pEvdev->flags |= EVDEV_RELATIVE_EVENTS | EVDEV_BUTTON_EVENTS;
+        pInfo->flags |= XI86_POINTER_CAPABLE;
+    }
+
+    if (as_mouse) {
+        xf86Msg(X_INFO, "%s: Configuring as mouse\n", pInfo->name);
+        pInfo->flags |= XI86_SEND_DRAG_EVENTS
+                     |  XI86_POINTER_CAPABLE;
+        pInfo->type_name = XI_MOUSE;
+    }
+
+    if (as_touchpad) {
+        xf86Msg(X_INFO, "%s: Configuring as touchpad\n", pInfo->name);
+        pEvdev->old_x = pEvdev->old_y = -1;
+        pInfo->flags |= XI86_SEND_DRAG_EVENTS
+                     |  XI86_POINTER_CAPABLE;
+        pInfo->type_name = XI_TOUCHPAD;
+    }
+
+    if (as_touchscreen) {
+        xf86Msg(X_INFO, "%s: Configuring as touchscreen\n", pInfo->name);
+        pInfo->flags |= XI86_SEND_DRAG_EVENTS | EVDEV_BUTTON_EVENTS
+                     |  XI86_POINTER_CAPABLE;
+        pInfo->type_name = XI_TOUCHSCREEN;
+    }
+
+    if (as_keyboard) {
+        xf86Msg(X_INFO, "%s: Configuring as keyboard\n", pInfo->name);
+        pInfo->flags |= XI86_KEYBOARD_CAPABLE;
+        pInfo->type_name = XI_KEYBOARD;
+    }
 
     return 0;
 }
