@@ -527,36 +527,95 @@ struct wacom_hdev_data {
527527static LIST_HEAD (wacom_udev_list );
528528static DEFINE_MUTEX (wacom_udev_list_lock );
529529
530+ static bool compare_device_paths (struct hid_device * hdev_a ,
531+ struct hid_device * hdev_b , char separator )
532+ {
533+ int n1 = strrchr (hdev_a -> phys , separator ) - hdev_a -> phys ;
534+ int n2 = strrchr (hdev_b -> phys , separator ) - hdev_b -> phys ;
535+
536+ if (n1 != n2 || n1 <= 0 || n2 <= 0 )
537+ return false;
538+
539+ return !strncmp (hdev_a -> phys , hdev_b -> phys , n1 );
540+ }
541+
530542static bool wacom_are_sibling (struct hid_device * hdev ,
531543 struct hid_device * sibling )
532544{
533545 struct wacom * wacom = hid_get_drvdata (hdev );
534546 struct wacom_features * features = & wacom -> wacom_wac .features ;
535- int vid = features -> oVid ;
536- int pid = features -> oPid ;
537- int n1 ,n2 ;
547+ struct wacom * sibling_wacom = hid_get_drvdata (sibling );
548+ struct wacom_features * sibling_features = & sibling_wacom -> wacom_wac .features ;
549+ __u32 oVid = features -> oVid ? features -> oVid : hdev -> vendor ;
550+ __u32 oPid = features -> oPid ? features -> oPid : hdev -> product ;
538551
539- if (vid == 0 && pid == 0 ) {
540- vid = hdev -> vendor ;
541- pid = hdev -> product ;
552+ /* The defined oVid/oPid must match that of the sibling */
553+ if (features -> oVid != HID_ANY_ID && sibling -> vendor != oVid )
554+ return false;
555+ if (features -> oPid != HID_ANY_ID && sibling -> product != oPid )
556+ return false;
557+
558+ /*
559+ * Devices with the same VID/PID must share the same physical
560+ * device path, while those with different VID/PID must share
561+ * the same physical parent device path.
562+ */
563+ if (hdev -> vendor == sibling -> vendor && hdev -> product == sibling -> product ) {
564+ if (!compare_device_paths (hdev , sibling , '/' ))
565+ return false;
566+ } else {
567+ if (!compare_device_paths (hdev , sibling , '.' ))
568+ return false;
542569 }
543570
544- if (vid != sibling -> vendor || pid != sibling -> product )
571+ /* Skip the remaining heuristics unless you are a HID_GENERIC device */
572+ if (features -> type != HID_GENERIC )
573+ return true;
574+
575+ /*
576+ * Direct-input devices may not be siblings of indirect-input
577+ * devices.
578+ */
579+ if ((features -> device_type & WACOM_DEVICETYPE_DIRECT ) &&
580+ !(sibling_features -> device_type & WACOM_DEVICETYPE_DIRECT ))
545581 return false;
546582
547- /* Compare the physical path. */
548- n1 = strrchr (hdev -> phys , '.' ) - hdev -> phys ;
549- n2 = strrchr (sibling -> phys , '.' ) - sibling -> phys ;
550- if (n1 != n2 || n1 <= 0 || n2 <= 0 )
583+ /*
584+ * Indirect-input devices may not be siblings of direct-input
585+ * devices.
586+ */
587+ if (!(features -> device_type & WACOM_DEVICETYPE_DIRECT ) &&
588+ (sibling_features -> device_type & WACOM_DEVICETYPE_DIRECT ))
589+ return false;
590+
591+ /* Pen devices may only be siblings of touch devices */
592+ if ((features -> device_type & WACOM_DEVICETYPE_PEN ) &&
593+ !(sibling_features -> device_type & WACOM_DEVICETYPE_TOUCH ))
594+ return false;
595+
596+ /* Touch devices may only be siblings of pen devices */
597+ if ((features -> device_type & WACOM_DEVICETYPE_TOUCH ) &&
598+ !(sibling_features -> device_type & WACOM_DEVICETYPE_PEN ))
551599 return false;
552600
553- return !strncmp (hdev -> phys , sibling -> phys , n1 );
601+ /*
602+ * No reason could be found for these two devices to NOT be
603+ * siblings, so there's a good chance they ARE siblings
604+ */
605+ return true;
554606}
555607
556608static struct wacom_hdev_data * wacom_get_hdev_data (struct hid_device * hdev )
557609{
558610 struct wacom_hdev_data * data ;
559611
612+ /* Try to find an already-probed interface from the same device */
613+ list_for_each_entry (data , & wacom_udev_list , list ) {
614+ if (compare_device_paths (hdev , data -> dev , '/' ))
615+ return data ;
616+ }
617+
618+ /* Fallback to finding devices that appear to be "siblings" */
560619 list_for_each_entry (data , & wacom_udev_list , list ) {
561620 if (wacom_are_sibling (hdev , data -> dev )) {
562621 kref_get (& data -> kref );
0 commit comments