RevisionID in IOHDACodecDevice ändern (PropertyInjector.kext)

  • Hallo!


    Stand


    Ich habe bereits hier mein System / Installation vorgestellt.

    Ich hab soweit erstmal alles zum Laufen gebracht, alles bis auf den Sound. Des Problems Lösung beschreibt Brumbaer hier.

    Um seinen Thread nicht weiter "voll zu müllen" und weil ich es bisher nicht geschafft habe es zu lösen, wollte ich hier um Hilfe bitten.


    Wissensbasis


    Ich hab mir seine Erklärungen durchgelesen zu Kext im Allg. und zum PropertyInjector selbst.



    Problem & Lösung


    Es soll also die Revision ID durch die eigentlich ersetzt werden. So wie ich das verstanden habe, wird hier das falsche Gerät von MacOS erkannt, oder zumindest die falsche Revision.

    Sprich, es muss in der DSDT der richtige Wert der Revision meiner Soundkarte eingetragen/ersetzt werden. Dieser ist lt. IORegistryExplorer 0x100101

    Im Wiki von AppleALC wird zu meiner Karte (ALC1220) folgendes gelistet:


    Realtek ALC1220 0x100003, layout 1, 2, 5, 7, 11, 13 15 (10.11)


    Ich geh also davon aus das die korrekte RevisionID 0x100003 lautet.


    Um diesen Wert zu ändern wollte ich den Lösungsansatz über den PropertyInjector(kext) gehen.


    Also habe ich die kext entsprechend modifiziert, so wie ich es verstanden habe (siehe Bilder im Anhang).


    Leider führte das dann dazu, dass MacOS nicht mehr booten wollte....

    Was mach ich also falsch? Wo ist der Denkfehler?

  • Es geht schon mal damit los, dass die Struktur falsch ist.


    Wenn du einen Eintrag namens Audio erzeugst, musst du dessen Untereinträge auch "unter" bzw. "in" den Audio Eintrag legen.

  • Oh Gott. Traurig aber war.. es war schon sehr spät.


    -


    Ist mein Match die CodecVendorID oder die Device/VendorID?


    device: 48a3

    vendor: 8680

    -> 0x48a38680


    Jetzt wurde gebootet (verständlich bei dem Kraut davor). Allerdings hat sich die Revision nicht geändert.


    Was mich wundert: Der ValueType ist "Number". Sollte das nicht "String" sein?

  • Der PropertyInjector ändert das Property eines "Gerätes".

    Bei welchem Gerät lässt du den propertyInjector die Eigenschaft ändern ?

    Bei welchen Gerät soll die Eigenschaft geändert werden ?

  • So, ich denke laut:


    Das Devices dessen Property ich ändern möchte ist der müsste HDEF@1F,3 (in meinem Fall) sein? Also nicht der Codec (ist kein "Device" für mich, oder doch?).


    Also:

    vendor-id 8680

    device-id 48a3


    Somit: 0x48a38680


    PS: Wobei ich nirgends direkt finden konnte was HDEF bedeutet...

  • 0xa3488086 müsste es sein, wenn du Properties in das Device HDEF injizieren möchtest.

  • HDEF - High Definition (HD Audio)

    ASUS PRIME X299-DELUXE i9-9940X • DDR4 64GB • SSD 960 PRO 1TB • Thunderbolt3 Titan Ridge • 2x AMD Radeon RX Vega 64 • BMD Intensity Pro 4K

    ASUS WS X299 SAGE/10G i9-10980XE • DDR4 64GB • SSD 970 PRO 1TB • Thunderbolt3 Titan Ridge • 2x AMD Radeon VII • BMD DeckLink 4K Extreme 12G


    Ordnung ist die primitivste Form von Chaos. (Hans-Jürgen Quadbeck-Seeger)

  • Gerät bedeutet nicht zwangsweise ein Gerät im Umgangssprachlichen Sinne.

    Um genau zu sein hätte ich den Audruck Service verwenden sollen.

    Bei welchem Service (Eintrag im IORegistry Baum im Anzeigemode Service) kommt das Feld, das du ändern willst, vor ?

    Wenn du den kennst, brauchst du seinen Klassennamen. Den zeigt dir der IORegistryexplorer auch an.

  • Naja, dann so gesehen, ist es für mich, wie eben ursprünglich gedacht, eigtl. der Audiocodec(Device), der "falsch" ist.

    Der, dessen Revisions nicht die ist, die von AppleALC unterstützt wird.

    a) richtig

    b) falsch

    c) vergiss es..

  • Du hast einen IORegistry-Auszug gepostet. Indem kommt der Eintrag IOHDACodecRevisionID vor.

    Das ist der der geändert werden muss.

    In welchem Service kommt er vor und wie heisst die Klasse ?

    Wo im Fenster des IORegistryExplorers steht der Service ?

    Wo im Fenster des IORegistryExplorers steht die Klasse ? Du weisst wie die Klassen eines PCIDevices heisst, also könntest du ein PCI Device anwählen und schauen wo die Klasse im Fenster zu finden ist.

  • 1. Ich habe einfach Probleme die Begriffe richtig einzuordnen..

    2. Ich verstehe nicht wie ich mich auf den Codec beziehe, wenn ich das (PCI)Gerät angeben soll, da für mich der "IOPCIPrimayMatch" als einziger Punkt erscheint an dem ich den Ort des Geschehens festlegen kann.


    Nach nochmaliger kurzer Studie deiner anderen Beiträge..


    Richtig lesen, richtig umwandeln


    Hier HDEF

    Vendor-id 86 80 00 00 -> 0x8086

    Device-id 48 a3 00 00 -> 0xa348


    -> Match: 0xa3488086

    endlich verstanden..



    Richtig verstehen: “Service”

    Service, Programm, Treiber…


    IOProviderClass = Name eines Services als Startsignal

    D.h. wird ein Service dieses Namens oder eine Subklasse davon geladen, dann startet die Überprüfung.


    CFBundleIdentifier = Programmcode des Service

    "zB. com.apple.driver.usb.AppleUSBXHCIPCI"

    kann mehrere Services enthalten..


    IOClass = “spezifiziert den Service im Bundle”


    Richtig verstehen: “Klasse”

    Gerät, Klasse, Art…


    IOPCIClassMatch = “GeräteKLASSE”

    -> GeräteKLASSE = Name d. (PCI) Gerätes


    IOPCIPrimaryMatch = “GeräteID”



    IORegistry, verstehen..


    IOService (Plane): Auflistung der installierten Services! (Die an Geräte gebunden sind)


    Jede Zeile auf der linken Seite ist also ein "Service"?


    IOACPIPlane: Geräte..



    So:


    • Hilfreich

    Richtig verstehen: “Service”

    Service, Programm, Treiber…


    Dummerweise ist der Sprachgebrauch nicht eineindeutig. Wenn man von einem Service spricht kann es sein, dass man den Service im allgemeinen oder im Besonderen spricht.

    Vergleichen wir ihn mit einem Programm, was ganz gut passt, denn letztendlich ist er eins.

    Pages im allgemeinen ist ein Schreibprogramm mit folgenden Möglichkeiten ....... Es liegt in meinem Programme Ordner.

    Sobald ich Pages starte wird es geladen und ausgeführt und dieser laufende Code ist eine Instanz von Pages. Mit etwas Getrickse kann ich das Programm mehrmals starten und die Kopien parallel laufen lassen. Dann habe ich mehrere Instanzen von Pages gleichzeitig laufen.

    So ist es auch mit Services. Es gibt den Service im Allgemeinen und dann gibt es Instanzen davon, also Code der ausgeführt wird. Es kann mehrere Instanzen des selben Service gleichzeitig geben.


    Services werden programmtechnisch als Klassen realisiert. Entsprechend ist eine Instanz eines Service eine Instanz seiner Klasse.


    Eine Instanz eines Service kann unter einem anderen Namen laufen, als dem Klassennamen.


    IOProviderClass = Name eines Services als Startsignal

    D.h. wird ein Service dieses Namens oder eine Subklasse davon geladen, dann startet die Überprüfung.

    Ja, aber. Genau genommen ist es der Name der Klasse die den Service realisiert. Es ist denkbar, dass der Service und Klassenname sich unterscheiden. Und Instanzen eines Service müssen auch nicht den gleichen Namen haben wie der Service. Also muss man darauf bestehen, dass dies der Name der Klasse ist.


    CFBundleIdentifier = Programmcode des Service

    "zB. com.apple.driver.usb.AppleUSBXHCIPCI"

    kann mehrere Services enthalten..

    Richtig


    IOClass = “spezifiziert den Service im Bundle”

    Wieder das Namen-Problem. Es handelt sich um den Namen der Klasse, die den Service realisiert.


    Richtig verstehen: “Klasse”

    Gerät, Klasse, Art…

    Ergibt sich aus dem Zusammenhang. Eine PCI Klasse ist etwas anderes als eine Klasse (Konzept in der Object-orientierten-Programmierung) die einen Service realisiert.


    IOPCIClassMatch = “GeräteKLASSE”

    -> GeräteKLASSE = Name d. (PCI) Gerätes

    Nein. Das ist eine PCI-Geräte spezifische Klasseneinteilung. Sie dient dazu PCI Geräte einer Gruppe zuzuordnen. Grafikkarten, Kommunikationskarten etc.. Gibt es für eine Klasse von Geräten verbindliche Vorschriften für die Funktion und wie sie bereit gestellt wird, so kann man Treiber schreiben, die dann an Hand der Geräte Klasse geladen werden ohne dass man einen Treiber für jedes Gerät schreiben muss. man muss nicht einmal die Geräte-Id jedes einzelnen Gerätes kennen und eintragen.


    IOPCIPrimaryMatch = “GeräteID”

    Produkt und Hersteller ID eines PCI Gerätes. Wieder etwas was nur für PCI Geräte bzw. Services die PCI Geräten zugeordnet sind Bedeutung hat. Das gleiche Konzept gibt es u.a. bei USB Geräten.


    IORegistry, verstehen..


    IOService (Plane): Auflistung der installierten Services! (Die an Geräte gebunden sind)

    Jein. Für gewöhnlich schon, aber ein Service kann auch einfach nur ein Programmstück sein, das nicht an ein Gerät gebunden ist.


    Jede Zeile auf der linken Seite ist also ein "Service"?

    Ja


    IOACPIPlane: Geräte..

    Die Einträge in der linken Spalte, sind Einträge, die macos in der DSDT gefunden hat. Das können auch Einträge sein, für die später keine Services geladen werden.



    AppleALC verwendet die Eigenschaft IOHDACodecRevisionID um Patches zu identifizieren.

    Deren Wert wollen wir anpassen.

    Wir kennen den Namen der Eigenschaft.

    Nun müssen wir rausfinden in welcher Instanz die Eigenschaft vorkommt.


    Dann legen wir einen PropertyInjector Eintrag, der gestartet wird sobald diese Instanz erzeugt wird, an.

    Dazu müssen wir wissen, welche Instanz die Eigenschaft enthält und von welcher Klasse es eine Instanz ist - denn wir verwenden IOProviderClass um das Erzeugen der Instanz zu erkennen und IOProviderClass will den Klassennamen haben.

  • Update:


    Klasse ist dank dir + Wikipedia etwas verständlicher geworden. Für mich sind das aktuell "Gruppennamen" für Services...

    Ich frag mich trotzdem, an welcher Stelle wird die Klasse definiert?

    Jeder IOClass Eintrag? Somit gibt es dann auch Unterklassen?

    Also:

    AppleALC verwendet die Eigenschaft „IOHDACodecRevisionID“: um den richtigen Patch zu identifizieren.


    Startbedingung festlegen mit: IOProviderClass


    Und wie wäre das Matchkriterium/syntax, wenn ich mit der Annahme richtig bin, dass ich mich NICHT direkt auf das PCI Gerät beziehe?


    Gedanke a):


    Name der Eigenschaft: IOHDACodecRevisionID

    Instanz mit der Eigenschaft: IOHDACodecDevice

    Klassenname der Instanz: AppleHDAController

    Gedanke b):


    Name der Eigenschaft: RevisionID

    Instanz mit der Eigenschaft: AppleHDAController (/CodecList/0/RevisionID)

    Klassenname der Instanz: AppleHDAController



    PS: IORegistry Frage

  • Wie gesagt eine Klasse kann alles mögliche sein z.B. ein Gruppenname, aber die Klasse die einen Service realisiert ist eine Klasse im Sinner der Object Orientierten Programmierung.


    Ich habe über Stunden hinweg ohne auf Programmierkenntnisse zurückzugreifen versucht zu beschreiben was eine Klasse ist und ich bin gescheitert.


    Letztendlich ist eine Klasse ein Programmstück, das Instanzen von sich erzeugen kann und definiert was die Instanzen können (Interface) und wie sie es tun (Implementation).

    Da Klassen Programmstücke sind, werden sie von einem Programmierer erstellt, mit dem Ziel eine bestimmte Aufgabe zu erfüllen.

    Andere Klassen oder Programmstücke können auf Instanzen einer Klasse zugreifen und mit ihnen arbeiten, denn wie das geht sagt ihnen das Klassen Interface.

    Weiss man welcher Klasse eine Instanz angehört, weiss man wie man mit ihr arbeiten kann ohne zu wissen zu müssen wie sie es genau tut.


    Es gibt Mechanismen in macos, die Treiber laden. Die Treiber sind Instanzen von Treiberklassen.

    Die Instanzen werden erzeugt und melden dann dem Betriebssystem, dass sie da sind.

    Hat man nun ein Gerät, dass eine Instanz einer Klasse lädt, die macos nicht kannte als es erstellt wurde, sieht man alt aus, denn macos kennt ja das Klasseninterface nicht, da es die Klasse noch nicht gab als es erstellt wurde.


    Da kommt die Vererbung ins Spiel. Man erzeugt Klassen, die aufeinander aufbauen. Die erste Klasse ist zum Beispiel vom Typ Treiber und beschreibt in ihrem Interface alles was ein beliebiger Treiber kennen muss.

    Nun legt man für bestimmte Gerätegruppen Unterklassen an. Die Unterklasse (Subclass) erbt das Interface ihrer Superklasse(Superclass).

    Die Subclass erbt auch die Implementation (den Programmcode) ihrer Superklasse, kann die aber durch eigens auf sie angepassten Code ersetzen.

    Bei Treibern wären das z.B. Klassen für USB, Netzwerk, Grafik. Jeder dieser Treiber hätte wieder Unterklassen, bei den USB Klassen z.B. für verschieden Chipsätze unterschiedliche Treiber.


    Hat man nun einen Computer mit einem macos unbekannten USB Chipsatz und einem passenden Kext dazu, so wird über den vorhin erwähnten Mechanismus eine Instanz der Klasse erzeugt, die macos nicht kennt. Aber da es sich um einen USB Chipsatz Treiber handelt, ist er eine Unterklasse der USB Klasse und davon kennt macos das Interface und kann also damit arbeiten.


    Im IORegistryExplorer kann man die Superklassen einer Klasse sehen.



    Die Klasse AppleACPIPCI basiert auf IOPCIBridge das auf IOService basiert usw.

    Alle Treiber sind Unterklassen von IOService, das eine Unterklasse von IORegistryEntry, das eine Unterklasse von OSObject ist.


    OSObject stellt Standardfunktionalität für Objekte im Kernel zur Verfügung. Das betrifft hauptsächlich die Speicherverwaltung, also wie man Objekte anlegt und löscht.

    IORegistryEntry erweitert OSObject um Funktionen die ein Verwalten der Objekte in der IORegistry erlauben. Anlegen, verschieben und Löschen von Einträgen uä.

    IOService fügt dann alles hinzu was jeder Service können muss. das ist ein A-voll Zeug wens interessiert, der kann's googeln.



    Wir wissen das die Eigenschaft die wir ändern wollen IOHDACodecRevisionID heißt.

    Diese kommt in IOHDACodecDevice vor.


    Es besteht die Möglichkeit, dass die Eigenschaft von einem anderen Service übergeben wird. Aber das interessiert und erst, wenn das Ändern an der Stelle nicht funktioniert.




    So an der Stelle haben wir die Instanz und die Klasse.

    Die Klasse lautet ........... ?


    Verwendet man IOProviderClass für das matching so wird man über jeden Service informiert, der der Klasse oder eine Unterklasse davon entspricht.

    Gibt es mehrere Instanzen einer Klasse z.B. IOService, kann man die "Matches" weiter einschränken. Das ist dann der Schritt nachdem wir die Klasse bestimmt haben haben.



    Ich verstehe die IORegistry Frage nicht.

    HDEF@1F,3 und AppleHDAController@1F,3 sind unterschiedlicher Services.

    Was meinst du mit unterschiedlichen Ansichten ? Service vs. ACPI ?

  • Zitat

    Ich habe über Stunden hinweg ohne auf Programmierkenntnisse zurückzugreifen versucht zu beschreiben was eine Klasse ist und ich bin gescheitert.

    :kopfschüttel: ...


    Ich denke ich es jetzt wirklich gerafft. Hab mir auch noch mal nen Vortrag von einem studierten IT Freund geben lassen. Sorry, das war mühsam.


    Dank deines Screenshots ist mir die Beschreibung "Class Inheritance" und "Bundle Identifier" im oberen Teil der IORegistry jetzt erst aufgefallen, und da wird noch mal einiges klarer. Ich tendiere manchmal dazu zu oberflächlich die Dinge zu betrachten und übersehe dann wertvolle Details..


    Zudem hab ich Erklärung / Bestätigung der Sub- und Superklassen gebraucht! Danke auch hierfür!


    Allerdings zeigt mir IORegistry in seinem "Baum" auf der linken Seite nicht die tatsächliche Klassenhierarchie an. Sprich AppleHDAController ist gar keine Superklasse vom IOHDACodecDevice.



    So. Weiter. Die Klasse lautet somit glasklar:

    IOHDACodecDevice


    Allerdings, wie erkenne ich ob es mehrere Instanzen gibt, wenn (wie oben beschrieben) der "Baum" nicht aussagekräftig ist. Doch nur wenn ich nach der Klasse in der Suchleiste suche, richtig?


    So. Bei IOHDACodecDevice gibt es keine weiteren Instanzen. Somit macht ein matching wohl hier erstmal keinen Sinn.


    Somit ist meine Eintrag in der Info.plist doch ziemlich abgespeckt, sofern ich es jetzt richtig verstanden habe.

    Führt aber nicht zum Erfolg (Neustart-> immer noch die alte IOHDACodecRevisionID).


    Kann es also sein, dass wie du oben bemerkt hast, der Wert von einem anderen Service übergeben wird?


    (Und sorry, ignoriere die letzte Frage mit den "Ansichten". Mein unaufmerksamer (müder) Blick war verwirrt durch das aufgeblähte Feld "Type: Data". Anyway. Vergiss das einfach..)

  • Alles gut.

    Das Prinzip hast du erfolgreich umgesetzt.


    Wenn du dir im IORegistryExplorer anschaust welchen Datentyp IOHDACodecRevisionID hat, wirst du feststellen, dass du einen anderen verwendest.


    Ändere den Datentyp in den Properties entsprechend und poste dann was IORegistryExplorer für das IOHDACodecDevice anzeigt.

  • :) juhu


    das hatte ich ja schon in Post #3 angemerkt.


    String -> Number


    dann wird aus 0x100003 (HEX) -> 1048579 (INT)


    klappt nicht. Es wurde eher eine neue "Instanz" erstellt. Aber auch nicht mit der Revision die ich eingetragen hatte. Daher nicht verständlich...Siehe Anhang


    So. Nachdem ich nun den Kext aber noch mal ganz rausgenommen habe, also ohne PropertyInjector lade, sehe ich, dass es doch 2 Instanzen dieser Klasse gibt. Das also nicht mal ein "Fehler" dieser Zahlenumwandlung war, sondern scheinbar immer so war.


    Daher müsste ich also nun doch eingrenzen.

    Dafür fehlt mir aber irgendwie der passende Syntax. IOHDAPrimaryMatch?

    Es würde sich ja die IOHDACodecVendorID anbieten... oder?

  • Das ist das falsche Device. Ich wollte das IOHDACodecDevice unter HDEF sehen.


    Um deine Frage zu beantworten.

    PropertyInjector versucht den Wert für alle Services auf die die Match Bedingungen zutreffen zu ändern. Doof wenn man mehrere hat, aber nur einen ändern will.

    Die Einschränkung an Hand von IOHDACodecVendorID macht Sinn, damit man nur das eine IOHDACodecDevice ändert .

    Da wie aber keine Subklasse von IOPCIDevice haben funktioniert IOPrimaryMatch nicht.

    Es gibt aber die Möglichkeit auf einen beliebigen Eintrag zu matchen.

    Man legt zusätzlich zu IOProviderClass einen Eintrag Namens IOPropertyMatch an. Dieser muss vom Typ Dictionary sein.

    In diesem Dictionary listet man alle Eigenschaften mit dem Wert auf, den man erfüllt haben will.

    In unserem Fall IOHDACodecVendorID und der Wert 0x10ec1220. Den Datentyp beachten.


    Das sieht dann so aus:



    XCode macht aus der Hexzahl eine Dezimalzahl, deshalb steht da 283906592.


    Eine einfache Methode zu testen ob das Matching klappt ist es eine zusätzliche Eigenschaft zu definieren.

    Z.B.

    Name: Frank

    Typ: String

    Data: "was here"


    Wenn das matching funktioniert wird der Eintrag im IOHDACodecDevice zu sehen sein.

  • PropertyMatch macht Sinn...

    Gemacht.

    Und wie ich sehe, sehe ich nix. Sprich, kein "Frank.." Eintrag. Und auch nicht die richtige RevisionID.

    Bzw. würde ich nicht auch einfach sehen ob es geklappt hat, wenn die geänderte RevisionID eingetragen wäre