static LIST_HEAD(wacom_udev_list);
 static DEFINE_MUTEX(wacom_udev_list_lock);
 
+static bool compare_device_paths(struct hid_device *hdev_a,
+               struct hid_device *hdev_b, char separator)
+{
+       int n1 = strrchr(hdev_a->phys, separator) - hdev_a->phys;
+       int n2 = strrchr(hdev_b->phys, separator) - hdev_b->phys;
+
+       if (n1 != n2 || n1 <= 0 || n2 <= 0)
+               return false;
+
+       return !strncmp(hdev_a->phys, hdev_b->phys, n1);
+}
+
 static bool wacom_are_sibling(struct hid_device *hdev,
                struct hid_device *sibling)
 {
        struct wacom *wacom = hid_get_drvdata(hdev);
        struct wacom_features *features = &wacom->wacom_wac.features;
-       int vid = features->oVid;
-       int pid = features->oPid;
-       int n1,n2;
+       struct wacom *sibling_wacom = hid_get_drvdata(sibling);
+       struct wacom_features *sibling_features = &sibling_wacom->wacom_wac.features;
+       __u32 oVid = features->oVid ? features->oVid : hdev->vendor;
+       __u32 oPid = features->oPid ? features->oPid : hdev->product;
 
-       if (vid == 0 && pid == 0) {
-               vid = hdev->vendor;
-               pid = hdev->product;
+       /* The defined oVid/oPid must match that of the sibling */
+       if (features->oVid != HID_ANY_ID && sibling->vendor != oVid)
+               return false;
+       if (features->oPid != HID_ANY_ID && sibling->product != oPid)
+               return false;
+
+       /*
+        * Devices with the same VID/PID must share the same physical
+        * device path, while those with different VID/PID must share
+        * the same physical parent device path.
+        */
+       if (hdev->vendor == sibling->vendor && hdev->product == sibling->product) {
+               if (!compare_device_paths(hdev, sibling, '/'))
+                       return false;
+       } else {
+               if (!compare_device_paths(hdev, sibling, '.'))
+                       return false;
        }
 
-       if (vid != sibling->vendor || pid != sibling->product)
+       /* Skip the remaining heuristics unless you are a HID_GENERIC device */
+       if (features->type != HID_GENERIC)
+               return true;
+
+       /*
+        * Direct-input devices may not be siblings of indirect-input
+        * devices.
+        */
+       if ((features->device_type & WACOM_DEVICETYPE_DIRECT) &&
+           !(sibling_features->device_type & WACOM_DEVICETYPE_DIRECT))
                return false;
 
-       /* Compare the physical path. */
-       n1 = strrchr(hdev->phys, '.') - hdev->phys;
-       n2 = strrchr(sibling->phys, '.') - sibling->phys;
-       if (n1 != n2 || n1 <= 0 || n2 <= 0)
+       /*
+        * Indirect-input devices may not be siblings of direct-input
+        * devices.
+        */
+       if (!(features->device_type & WACOM_DEVICETYPE_DIRECT) &&
+           (sibling_features->device_type & WACOM_DEVICETYPE_DIRECT))
+               return false;
+
+       /* Pen devices may only be siblings of touch devices */
+       if ((features->device_type & WACOM_DEVICETYPE_PEN) &&
+           !(sibling_features->device_type & WACOM_DEVICETYPE_TOUCH))
+               return false;
+
+       /* Touch devices may only be siblings of pen devices */
+       if ((features->device_type & WACOM_DEVICETYPE_TOUCH) &&
+           !(sibling_features->device_type & WACOM_DEVICETYPE_PEN))
                return false;
 
-       return !strncmp(hdev->phys, sibling->phys, n1);
+       /*
+        * No reason could be found for these two devices to NOT be
+        * siblings, so there's a good chance they ARE siblings
+        */
+       return true;
 }
 
 static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
 {
        struct wacom_hdev_data *data;
 
+       /* Try to find an already-probed interface from the same device */
+       list_for_each_entry(data, &wacom_udev_list, list) {
+               if (compare_device_paths(hdev, data->dev, '/'))
+                       return data;
+       }
+
+       /* Fallback to finding devices that appear to be "siblings" */
        list_for_each_entry(data, &wacom_udev_list, list) {
                if (wacom_are_sibling(hdev, data->dev)) {
                        kref_get(&data->kref);