uaudio: Fix confusion between interface numbers and interface indexes
authorratchov <ratchov@openbsd.org>
Tue, 23 Jul 2024 08:59:21 +0000 (08:59 +0000)
committerratchov <ratchov@openbsd.org>
Tue, 23 Jul 2024 08:59:21 +0000 (08:59 +0000)
There is rare hardware for which the interface numbers and indexes are
not equal. Such devices couldn't attach because the driver claimed the
wrong interface.

sys/dev/usb/uaudio.c

index b213c5e..8e8fd3f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uaudio.c,v 1.174 2023/12/10 06:32:14 ratchov Exp $    */
+/*     $OpenBSD: uaudio.c,v 1.175 2024/07/23 08:59:21 ratchov Exp $    */
 /*
  * Copyright (c) 2018 Alexandre Ratchov <alex@caoua.org>
  *
@@ -2702,6 +2702,22 @@ uaudio_fixup_params(struct uaudio_softc *sc)
        }
 }
 
+int
+uaudio_iface_index(struct uaudio_softc *sc, int ifnum)
+{
+       int i, nifaces;
+
+       nifaces = sc->udev->cdesc->bNumInterfaces;
+
+       for (i = 0; i < nifaces; i++) {
+               if (sc->udev->ifaces[i].idesc->bInterfaceNumber == ifnum)
+                       return i;
+       }
+
+       printf("%s: %d: invalid interface number\n", __func__, ifnum);
+       return -1;
+}
+
 /*
  * Parse all descriptors and build configuration of the device.
  */
@@ -2711,6 +2727,7 @@ uaudio_process_conf(struct uaudio_softc *sc, struct uaudio_blob *p)
        struct uaudio_blob dp;
        struct uaudio_alt *a;
        unsigned int type, ifnum, altnum, nep, class, subclass;
+       int i;
 
        while (p->rptr != p->wptr) {
                if (!uaudio_getdesc(p, &dp))
@@ -2736,7 +2753,8 @@ uaudio_process_conf(struct uaudio_softc *sc, struct uaudio_blob *p)
 
                switch (subclass) {
                case UISUBCLASS_AUDIOCONTROL:
-                       if (usbd_iface_claimed(sc->udev, ifnum)) {
+                       i = uaudio_iface_index(sc, ifnum);
+                       if (i != -1 && usbd_iface_claimed(sc->udev, i)) {
                                DPRINTF("%s: %d: AC already claimed\n", __func__, ifnum);
                                break;
                        }
@@ -2748,7 +2766,8 @@ uaudio_process_conf(struct uaudio_softc *sc, struct uaudio_blob *p)
                                return 0;
                        break;
                case UISUBCLASS_AUDIOSTREAM:
-                       if (usbd_iface_claimed(sc->udev, ifnum)) {
+                       i = uaudio_iface_index(sc, ifnum);
+                       if (i != -1 && usbd_iface_claimed(sc->udev, i)) {
                                DPRINTF("%s: %d: AS already claimed\n", __func__, ifnum);
                                break;
                        }
@@ -2768,10 +2787,19 @@ done:
         * Claim all interfaces we use. This prevents other uaudio(4)
         * devices from trying to use them.
         */
-       for (a = sc->alts; a != NULL; a = a->next)
-               usbd_claim_iface(sc->udev, a->ifnum);
+       for (a = sc->alts; a != NULL; a = a->next) {
+               i = uaudio_iface_index(sc, a->ifnum);
+               if (i != -1) {
+                       DPRINTF("%s: claim: %d at %d\n", __func__, a->ifnum, i);
+                       usbd_claim_iface(sc->udev, i);
+               }
+       }
 
-       usbd_claim_iface(sc->udev, sc->ctl_ifnum);
+       i = uaudio_iface_index(sc, sc->ctl_ifnum);
+       if (i != -1) {
+               DPRINTF("%s: claim: ac %d at %d\n", __func__, sc->ctl_ifnum, i);
+               usbd_claim_iface(sc->udev, i);
+       }
 
        return 1;
 }