Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e36f88c4 authored by Roy Luo's avatar Roy Luo
Browse files

Support identifying usb midi device using usb sysfs

Out-of-tree ACK patches previously enabled MIDI device identification
via the "/sys/class/android_usb/android0/f_midi/alsa" sysfs node.
This change introduces a new, upstream-compliant method for MIDI
device identification. This method requires the upstream patch [1]
within the underlying ACK.

[1] https://patchwork.kernel.org/project/linux-usb/patch/20240307030922.3573161-1-royluo@google.com/

Flag: android.hardware.usb.flags.enable_usb_sysfs_midi_identification
Bug: 333778731
Test: exercise usb midi with the flag on/off
Change-Id: I64635f083541bfc59bfa4857d0fc5f20a5f3c2f5
parent 2246bcc5
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -29,3 +29,10 @@ flag {
    description: "Enables signal API with staking"
    bug: "287498482"
}

flag {
    name: "enable_usb_sysfs_midi_identification"
    namespace: "system_sw_usb"
    description: "Enable identifying midi device using USB sysfs"
    bug: "333778731"
}
+64 −11
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ import android.service.usb.UsbDeviceManagerProto;
import android.service.usb.UsbHandlerProto;
import android.util.Pair;
import android.util.Slog;
import android.text.TextUtils;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
@@ -110,6 +111,8 @@ import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * UsbDeviceManager manages USB state in device mode.
@@ -135,6 +138,11 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
     */
    private static final String NORMAL_BOOT = "normal";

    /**
     *  UDC controller for the ConfigFS USB Gadgets.
     */
    private static final String USB_CONTROLLER_NAME_PROPERTY = "sys.usb.controller";

    private static final String USB_STATE_MATCH =
            "DEVPATH=/devices/virtual/android_usb/android0";
    private static final String ACCESSORY_START_MATCH =
@@ -932,6 +940,42 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
            sEventLogger.enqueue(new EventLogger.StringEvent("USB intent: " + intent));
        }

        private void getMidiCardDevice() throws FileNotFoundException {
            String controllerName =  getSystemProperty(USB_CONTROLLER_NAME_PROPERTY, "");
            if (TextUtils.isEmpty(controllerName)) {
                throw new FileNotFoundException("controller name not found");
            }

            File soundDir = new File("/sys/class/udc/" + controllerName + "/gadget/sound");
            if (!soundDir.exists()) {
                throw new FileNotFoundException("sound device not found");
            }

            // There should be exactly one sound card
            File[] cardDirs = FileUtils.listFilesOrEmpty(soundDir,
                                                         (dir, file) -> file.startsWith("card"));
            if (cardDirs.length != 1) {
                throw new FileNotFoundException("sound card not match");
            }

            // There should be exactly one midi device
            File[] midis = FileUtils.listFilesOrEmpty(cardDirs[0],
                                                      (dir, file) -> file.startsWith("midi"));
            if (midis.length != 1) {
                throw new FileNotFoundException("MIDI device not match");
            }

            Pattern pattern = Pattern.compile("midiC(\\d+)D(\\d+)");
            Matcher matcher = pattern.matcher(midis[0].getName());
            if (matcher.matches()) {
                mMidiCard = Integer.parseInt(matcher.group(1));
                mMidiDevice = Integer.parseInt(matcher.group(2));
                Slog.i(TAG, "Found MIDI card " + mMidiCard + " device " + mMidiDevice);
            } else {
                throw new FileNotFoundException("MIDI name not match");
            }
        }

        private void updateUsbFunctions() {
            updateMidiFunction();
            updateMtpFunction();
@@ -941,6 +985,14 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
            boolean enabled = (mCurrentFunctions & UsbManager.FUNCTION_MIDI) != 0;
            if (enabled != mMidiEnabled) {
                if (enabled) {
                    if (android.hardware.usb.flags.Flags.enableUsbSysfsMidiIdentification()) {
                        try {
                            getMidiCardDevice();
                        } catch (FileNotFoundException e) {
                            Slog.e(TAG, "could not identify MIDI device", e);
                            enabled = false;
                        }
                    } else {
                        Scanner scanner = null;
                        try {
                            scanner = new Scanner(new File(MIDI_ALSA_PATH));
@@ -955,6 +1007,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
                            }
                        }
                    }
                }
                mMidiEnabled = enabled;
            }
            mUsbAlsaManager.setPeripheralMidiState(