Konfigurieren der Parameter des LED-Triggers aus dem Kernel-Space

9

Ich arbeite an einem eingebetteten Projekt. Unser Board benutzt Linux Kernel v3.16.7. Ich arbeite daran, ein paar periphere LEDs zu unterstützen, die die Aktivität überwachen. Ich habe den Bootvorgang erfolgreich auf laden Sie die Treiber und erstellen sysfs Einträge in /sys/class/leds/ , was großartig ist. Ich habe auch eine angehängt oneshot trigger auf die LEDs, damit ich echo 1 > shot von /sys/class/leds/actled1\:green/ und die LED blinkt. Genau das, was ich will.

Ich möchte jedoch die Verzögerungen für jede LED konfigurieren, wenn ich den Treiber während des Bootvorgangs instanziiere, und mir ist nicht klar, wie das geht. Der Treiber erstellt sysfs-Einträge in /sys/class/leds/actled1\:green/ namens delay_on und delay_off , und ich kann aus dem Benutzerbereich in sie schreiben, um die Verzögerungen zu konfigurieren. Es sollte jedoch möglich sein, ihre Anfangswerte während der Instanziierung aus dem Kernel-Space zu setzen. Ich möchte auch in der Lage sein, den invert -Parameter (der nur ein weiterer sysfs-Eintrag ist, genau wie die Verzögerungen) zu setzen.

Wie kann ich die Parameter eines LED-Triggers konfigurieren, wenn ich den Treiber aus dem Kernelbereich instanziiere?

Unten ist, wie ich die LED GPIOs instanziiere. Zuerst richte ich die benötigten Strukturen ein:

%Vor%

Dann rufe ich diese Funktion auf, um die Plattformgeräte zu erstellen:

%Vor%

Die Definition für die gpio_led struct lautet in include/linux/leds.h line 327 , und die Definition für gpio_led_platform_data ist in Zeile 341 der gleichen Datei . Die Definition von platform_device_add_data ist in drivers/base/platform.c line 284 .

Es kann nützlich sein, sich die Quelle für den Oneshot-Trigger anzusehen ( drivers/leds/trigger/ledtrig-oneshot.c ) um die Frage zu beantworten. Relevant ist auch der Treiber "leds-gpio" ( drivers/leds/leds-gpio.c ).

Ich vermute, die Antwort ist irgendwo in drivers/base/platform.c und dem zugehörigen > Dokumentation , aber ich Ich sehe keine Funktionen, die mit den Daten umgehen, die ich brauche.

Um einige der Informationen zu adressieren, die ich versehentlich weggelassen habe:

  1. Der Bootloader legt die Kernelargumente fest, und wir können den Bootloader nicht ändern. das ist gut; Die Werte, die ich setzen möchte, sind Konstanten, und ich kann sie fest codieren.
  2. Der Treiber wird zum Kompilierungszeitpunkt in den Kernel eingebunden (und ich nehme an, er wird vom Bootloader geladen), anstatt später einen .ko mit modprobe zu laden.
  3. Ich würde gerne einen allgemeinen Weg finden, um willkürliche Trigger-Parameter zu setzen, nicht nur oneshots delay_on / delay_off . Zum Beispiel, oneshots invert -Parameter.
  4. Ich bin völlig in Ordnung, oneshot zu modifizieren / neue Trigger zu erstellen. Sobald ich mit onSchot arbeite, brauche ich , um einen neuen Trigger zu erstellen, der auf oneshot expandiert (was auch der Grund ist, dass ich willkürliche Parameter einstellen muss).
Woodrow Barlow 23.10.2015, 19:41
quelle

3 Antworten

3

Es gibt ein paar Probleme und ich denke, ich habe die Lösungen gefunden, aber obwohl Sie eine Menge Informationen zur Verfügung gestellt haben, gab es einige Dinge, die ich für alle möglichen Szenarien aufzählen werde. .

(1) Abrufen der Anfangswerte, die Sie festlegen möchten. Ich nehme an, Sie haben das schon herausgefunden, aber ... Sie können diese aus dem Kernel cmdline Parsing bekommen (zB fügen Sie die Werte zu /boot/grub2/grub.cfg als myleds.delay_on=... hinzu. Wenn Sie über modprobe laden setzen Sie einen Modulparameter, dies könnte auch eine Konfigurationsdatei sein wie in myleds.config_file=/etc/sysconfig/myleds.conf

(2) Sie könnten sie in Ihre setup_my_leds setzen [außer der Wideraufrufung von oneshot_trig_activate - mit der wir uns bald befassen werden]. Von drivers/base/platform.c :

%Vor%

Also, in diesem Sinne, lassen Sie uns Ihre Setup-Funktion leicht ändern:

%Vor%

(3) Da Sie .default_trigger = "oneshot" verwenden, werden die obigen Daten leider um oneshot_trig_activate in drivers/leds/trigger/ledtrig-oneshot.c gestreut. Also müssen wir damit umgehen.

Option (A): Angenommen, Sie können den gesamten Kernel wie gewünscht neu erstellen, ändern Sie einfach oneshot_trig_activate in ledtrig-oneshot.c und entfernen Sie die Zeilen, die DEFAULT_DELAY verwenden. Dies ist nur dann nützlich, wenn Sie wissen , dass nicht von etwas anderem in Ihrem System verwendet wird, das die Standardwerte benötigt.

Option (B): Wenn Sie ledtrig-oneshot.c nicht ändern dürfen, aber neue Trigger zu drivers/leds/trigger hinzufügen können, kopieren Sie die Datei in (z. B.) ledtrig-oneshot2.c und nehmen Sie die Änderungen dort vor. Sie müssen .name in .name = "oneshot2" ändern. Der einfache Weg [in vi, natürlich :-)] ist :%s/oneshot/oneshot2/g . Sie müssen dazu auch einen neuen Eintrag in Kconfig und Makefile hinzufügen. Ändern Sie dann Ihre Strukturdefinition, um den neuen Treiber zu verwenden: .default_trigger = "oneshot2"

Option (C): Wenn Sie das Verzeichnis drivers/leds/trigger nicht berühren können oder wollen, kopieren Sie ledtrig-oneshot.c in Ihr Treiberverzeichnis [umbenennen]. Führen Sie die Änderungen aus der obigen Option (B) aus. Mit ein paar Tricks in Ihrem Makefile, können Sie es sowohl my_led_driver.ko als auch ledtrig-oneshot2.ko erstellen. Sie müssen Ihre Kconfig ändern und möglicherweise einen depends on LED_TRIGGERS für den LED-Trigger-Treiber hinzufügen. Sie könnten die beiden auch in separate Unterverzeichnisse einfügen und das einzelne Makefile / Kconfig könnte einfacher sein: my_led/my_driver und my_led/my_trigger

Option (C) wäre mehr Arbeit im Voraus, könnte aber auf lange Sicht sauberer und tragbarer sein. Natürlich könntest du die Option (A) für den Proof-of-Concept machen, dann die Option (B) machen und das "letzte Schiff" als Option (C) machen.

Ein alternativer Weg, wenn Sie die Anfangswerte festlegen: Erinnern Sie sich an den Kommentar für my_leds_get_init_values war possibly storing away for later use . Sie könnten oneshot2_trig_activate ändern, um sie aufzurufen, anstatt DEFAULT_DELAY zu verwenden. Ich mag das nicht so sehr und bevorzuge die Lösungen, die das offensive Verhalten einfach kastrieren. Aber mit einigen Tests können Sie feststellen, dass dies die Art ist, wie Sie es tun müssen.

Hoffentlich funktioniert das obige. Wenn nicht, bearbeite deine Frage mit zusätzlichen Informationen und / oder Einschränkungen [und sende mir einen Kommentar], und ich werde meine Antwort [Ich habe schon seit 40+ Fahrer] aktualisiert haben.]

UPDATE: Okay, hier ist ein komplett annotierter und modifizierter LED-Trigger-Treiber, den Sie als Ersatz für oneshot_trig_activate verwenden können.

Weil der Parameter drivers/led/trigger/ledtrig-oneshot.c nicht direkt über eine Standardstruktur übergeben werden kann, auf die Sie in Ihrer Setup-Funktion Zugriff haben [d. h. es ist in einer privaten Struktur innerhalb des Auslösertreibers gespeichert], entfernen Sie die "Auswahl (1)" und "Auswahl (2)". Wir werden sie alle gleichzeitig in der [modifizierten] invert setzen.

Außerdem müssen die gewünschten Init-Parameter eingerichtet und als globals von oneshot_trig_activate gespeichert werden, damit der Trigger-Treiber sie finden kann. Das heißt, es gibt keine Möglichkeit, dies sauber zu machen (z. B. mit einem Zeiger auf eine private Struktur, die herumgereicht wird), da die Strukturen, auf die Sie im Setup Zugriff haben, kein Feld dafür haben. Weitere Informationen hierzu finden Sie im oberen Teil des Auslösertreibers.

Mein erster Schritt war, den Basistreiber mit beschreibenden Kommentaren zu kommentieren. Es gab keine Kommentare, außer für den K & R Stil für das Urheberrecht und einen einzelnen Einzeiler. Meine Anmerkungen sind ANSI ("//") Kommentare.

Wenn ich den Treiber übernehmen würde, würde ich diese hinzufügen und sie zurücklassen. Allerdings könnte mein Niveau von Kommentaren gemäß dem Kernel-Style-Guide als "over-commenting" betrachtet werden und könnte besonders für "cruft" gelten ein Treiber, der so einfach ist.

Der nächste Schritt bestand darin, die notwendigen Änderungen hinzuzufügen. Alle Orte, die Ergänzungen / Änderungen haben, sind mit einem Kommentarblock markiert, der mit "C:" beginnt. Dies sind die wichtigen Orte, um zu sehen. Beachten Sie, dass diese Kommentare berechtigte Kandidaten sind, in zu belassen. Bei anderen komplexeren Treibern hängt der Grad der Kommentare vom Autor ab. Das "C:" dient nur dazu, die Orte für dich hervorzuheben.

Mit den Anmerkungen könnte eine gerade durchgelesene Zeile jetzt einfacher sein. Auch ein my_leds_get_init_values könnte helfen. Wenn du alles unter diff -u hast, umso besser.

Aus diesem Grund würde ich die "Option (A)" [direkte Änderung der Originaldatei] entfernen und nur "Option (B)" oder "Option (C)" machen.

Der Triggertreiber verwendet alle git -Definitionen, so dass die globale Bearbeitung, die ich zuvor vorgeschlagen habe, nicht ist. Ich habe static gemacht, also musst du das mit .name = "myled_oneshot"; vergleichen. Fühlen Sie sich frei, .default_trigger = "myled_oneshot"; zu verwenden, um mit Ihrer bestehenden Namenskonvention übereinzustimmen. Wenn ich das für mich mache, verwende ich normalerweise meine Initialen, so dass es my_leds_whatever - YMMV

wird

Wie auch immer, hier ist der gesamte modifizierte Trigger-Treiber. Beachten Sie, dass ich die Bearbeitung vorgenommen habe, aber ich nicht habe versucht, sie zu kompilieren / zu erstellen.

%Vor%     
Craig Estey 26.10.2015, 22:46
quelle
0

Wie Sie in ledtrig-oneshot.c sehen können >, wird die Verzögerung immer mit DEFAULT_DELAY initialisiert. Wenn Sie beim Start einen anderen Wert konfigurieren möchten, ist dies leider ein Mechanismus, den Sie implementieren müssen.

    
Alexandre Belloni 23.10.2015 20:42
quelle
0

Wie Craig geantwortet hat, sollte es von Kernel-Befehlszeilenoptionen kommen, aber es könnte ein Problem mit eingebetteten Systemen geben, wo der Boot-Loader die Befehlszeilenparameter übergibt und die Bootloader nicht modifiziert werden können, normalerweise OTP. In diesem Fall sehe ich nur 2 Optionen

  1. harte Codierung in der Kernel-Init-Funktion

  2. Da die MAC-Adresse in eeprom gespeichert ist, kann der nic-Treiber gelesen werden, wenn die Werte im Flash gespeichert werden können (nor) und der Wert beim Booten gelesen wird. Dies kann nach dem Erstellen der MTD-Partitionen während des Systemstarts erfolgen.

Surajit 27.10.2015 15:09
quelle