Wie schreibe ich einen einfachen Linux-Gerätetreiber?
Lesezeit: 11 Minuten
Sagar Jain
Ich muss einen SPI-Linux-Zeichengerätetreiber für Omap4 von Grund auf neu schreiben. Ich kenne einige Grundlagen zum Schreiben von Gerätetreibern. Aber ich weiß nicht, wie ich anfangen soll, plattformspezifische Gerätetreiber von Grund auf neu zu schreiben.
Ich habe einige grundlegende Zeichentreiber geschrieben und dachte, das Schreiben von SPI-Gerätetreibern wäre ähnlich. Char-Treiber haben eine Struktur file_operations die die im Treiber implementierten Funktionen enthält.
Jetzt gehe ich durch spi-omap2-mcspi.c Code als Referenz, um eine Idee zu bekommen, um mit der Entwicklung von SPI-Treibern von Grund auf neu zu beginnen.
Aber ich sehe keine Funktionen wie Öffnen, Lesen, Schreiben usw. Ich weiß nicht, wo das Programm beginnt.
Nur eine Frage: Warum willst du den SPI-Treiber umschreiben? Ich habe zuvor den OMAP4-SPI-Treiber verwendet und hatte keine Probleme damit.
– Nils Pipenbrinck
13. August 2014 um 9:45 Uhr
@NilsPipenbrinck: Der Hauptzweck beim Schreiben des Treibers ist das Lernen.
– Sagar Jain
13. August 2014 um 10:02 Uhr
mögliches Duplikat von stackoverflow.com/questions/22706570/… ?
– tauseef_CuriousGuy
3. August 2017 um 9:24 Uhr
Sie können die Zeiger und Verweise auf verschiedene Teile des Geräts sehen. Die Treiber „interagieren“ mit Hardware- und Kernel-Tools, sodass strenge „Öffnen“- oder „Schreiben“-Befehle nicht erforderlich sind.
– ILMostro_7
21. Oktober 2017 um 4:47 Uhr
s/commands/functions/
– ILMostro_7
21. Oktober 2017 um 4:56 Uhr
Nenad Radulović
Beginnen Sie zunächst mit dem Schreiben eines generischen Kernelmoduls. Es gibt mehrere Orte, an denen Sie nach Informationen suchen können, aber ich habe sie gefunden dieser Link sehr nützlich sein. Nachdem Sie alle dort aufgeführten Beispiele durchgegangen sind, können Sie mit dem Schreiben Ihres eigenen Linux-Treibermoduls beginnen.
Bitte beachten Sie, dass Sie nicht damit davonkommen, den Beispielcode einfach zu kopieren und zu hoffen, dass es funktioniert, nein. Die Kernel-API kann sich manchmal ändern und Beispiele funktionieren nicht. Die dort bereitgestellten Beispiele sollten als Anleitung betrachtet werden, wie etwas zu tun ist. Je nach verwendeter Kernel-Version müssen Sie das Beispiel anpassen, damit es funktioniert.
Erwägen Sie, die von der TI-Plattform bereitgestellten Funktionen so oft wie möglich zu verwenden, da dies wirklich eine Menge Arbeit für Sie erledigen kann, wie z. B. das Anfordern und Aktivieren benötigter Takte, Busse und Netzteile. Wenn ich mich richtig erinnere, können Sie die Funktionen verwenden, um speicherabgebildete Adressbereiche für den direkten Zugriff auf Register zu erwerben. Ich muss erwähnen, dass ich schlechte Erfahrungen mit von TI bereitgestellten Funktionen gemacht habe, da sie nicht alle erworbenen Ressourcen ordnungsgemäß freigeben/bereinigen, sodass ich für einige Ressourcen andere Kerneldienste aufrufen musste, um sie während des Entladens des Moduls freizugeben.
Bearbeiten 1:
Ich bin mit der Linux-SPI-Implementierung nicht ganz vertraut, aber ich würde damit beginnen, mir die Funktion omap2_mcspi_probe() in der Datei drivers/spi/spi-omap2-mcspi.c anzusehen. Wie Sie dort sehen können, registriert es seine Methoden beim Linux-Master-SPI-Treiber mit dieser API: Linux/include/linux/spi/spi.h. Im Gegensatz zum char-Treiber sind hier die Hauptfunktionen *_transfer()-Funktionen. Weitere Details finden Sie in den Strukturbeschreibungen in der Datei spi.h. Schauen Sie auch mal rein Dies auch alternative Gerätetreiber-API.
Ich habe neuere Versionen von “diesem Link” gefunden (Das Linux-Kernel-Modul-Programmierhandbuch ) hier
– JohanPI
17. September 2021 um 12:27 Uhr
m-ric
Ich nehme an, Ihr OMAP4-Linux verwendet eines von arch/arm/boot/dts/{omap4.dtsi,am33xx.dtsi} Gerätebaum, also kompiliert es drivers/spi/spi-omap2-mcspi.c (Wenn Sie nichts über den Gerätebaum wissen, lesen Sie dies). Dann:
der SPI-Master-Treiber ist fertig,
es registriert sich (höchstwahrscheinlich) beim Linux-SPI-Core-Framework drivers/spi/spi.c,
es funktioniert (wahrscheinlich) gut auf Ihrem OMAP4.
Um die braucht man sich eigentlich nicht zu kümmern Meisterfahrer Ihre zu schreiben Slave-Gerätetreiber. Wie soll ich wissen spi-omap2-mcspi.c ist ein Master-Fahrer? Es ruft spi_register_master().
SPI-Master, SPI-Slave?
Bitte beziehen Sie sich auf Documentation/spi/spi_summary. Das Dokument bezieht sich auf Controller-Treiber (Meister) und Protokolltreiber (Sklave). Ihrer Beschreibung entnehme ich, dass Sie a schreiben wollen Protokoll/Gerätetreiber.
SPI-Protokoll?
Um das zu verstehen, benötigen Sie das Datenblatt Ihres Slave-Geräts, das Ihnen sagen soll:
das SPI-Modus von Ihrem Gerät verstanden,
das Protokoll es erwartet auf dem Bus.
Im Gegensatz zu i2c definiert SPI kein Protokoll oder Handshake, SPI-Chiphersteller müssen ihre eigenen definieren. Also Datenblatt prüfen.
SPI-Modus
Aus include/linux/spi/spi.h:
* @mode: The spi mode defines how data is clocked out and in.
* This may be changed by the device's driver.
* The "active low" default for chipselect mode can be overridden
* (by specifying SPI_CS_HIGH) as can the "MSB first" default for
* each word in a transfer (by specifying SPI_LSB_FIRST).
Überprüfen Sie erneut das Datenblatt Ihres SPI-Geräts.
Ein Beispiel für einen SPI-Gerätetreiber?
Um Ihnen ein relevantes Beispiel zu geben, muss ich Ihren SPI-Gerätetyp kennen. Sie würden verstehen, dass a SPI-Flash-Gerätetreiber unterscheidet sich von a SPI-FPGA-Gerätetreiber. Leider gibt es nicht so viele SPI-Gerätetreiber. Um sie zu finden:
$ cd linux
$ git grep "spi_new_device\|spi_add_device"
rslemos
Ich weiß nicht, ob ich deine Frage richtig verstanden habe. Wie m-ric betonte, gibt es Master-Treiber und Slave-Treiber.
Normalerweise sind Master-Treiber mehr an die Hardware gebunden, ich meine, sie manipulieren normalerweise IO-Register oder führen einige speicherabgebildete IO durch.
Für einige Architekturen, die bereits vom Linux-Kernel unterstützt werden (wie omap3 und omap4), sind bereits Master-Treiber implementiert (McSPI).
Ich gehe also davon aus, dass Sie diese SPI-Einrichtungen von omap4 verwenden möchten, um einen Slave-Gerätetreiber zu implementieren (Ihr Protokoll, um mit Ihrem externen Gerät über SPI zu kommunizieren).
Ich habe das folgende Beispiel für BeagleBoard-xM (omap3) geschrieben. Der vollständige Code ist unter https://github.com/rslemos/itrigue/blob/master/alsadriver/itrigue.c (ansehenswert, aber mehr Initialisierungscode, für ALSA, GPIO, Modulparameter). Ich habe versucht, Code zu unterscheiden, der sich mit SPI befasst (vielleicht habe ich etwas vergessen, aber Sie sollten trotzdem auf die Idee kommen):
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spi/spi.h>
/* MODULE PARAMETERS */
static uint spi_bus = 4;
static uint spi_cs = 0;
static uint spi_speed_hz = 1500000;
static uint spi_bits_per_word = 16;
/* THIS IS WHERE YOUR DEVICE IS CREATED; THROUGH THIS YOU INTERACT WITH YOUR EXTERNAL DEVICE */
static struct spi_device *spi_device;
/* SETUP SPI */
static inline __init int spi_init(void) {
struct spi_board_info spi_device_info = {
.modalias = "module name",
.max_speed_hz = spi_speed_hz,
.bus_num = spi_bus,
.chip_select = spi_cs,
.mode = 0,
};
struct spi_master *master;
int ret;
// get the master device, given SPI the bus number
master = spi_busnum_to_master( spi_device_info.bus_num );
if( !master )
return -ENODEV;
// create a new slave device, given the master and device info
spi_device = spi_new_device( master, &spi_device_info );
if( !spi_device )
return -ENODEV;
spi_device->bits_per_word = spi_bits_per_word;
ret = spi_setup( spi_device );
if( ret )
spi_unregister_device( spi_device );
return ret;
}
static inline void spi_exit(void) {
spi_unregister_device( spi_device );
}
Der obige Code ist unabhängig von der Implementierung, das heißt, er könnte McSPI, Bit-Bang-GPIO oder jede andere Implementierung eines SPI-Master-Geräts verwenden. Diese Schnittstelle ist beschrieben in linux/spi/spi.h
Damit es in BeagleBoard-XM funktioniert, musste ich Folgendes zur Kernel-Befehlszeile hinzufügen:
#!/bin/sh
mount -t debugfs none /sys/kernel/debug
insmod /fops.ko
cd /sys/kernel/debug/lkmc_fops
## Basic read.
cat f
# => abcd
# dmesg => open
# dmesg => read
# dmesg => len = [0-9]+
# dmesg => close
## Basic write
printf '01' >f
# dmesg => open
# dmesg => write
# dmesg => len = 1
# dmesg => buf = a
# dmesg => close
cat f
# => 01cd
# dmesg => open
# dmesg => read
# dmesg => len = [0-9]+
# dmesg => close
## ENOSPC
printf '1234' >f
printf '12345' >f
echo "$?"
# => 8
cat f
# => 1234
## seek
printf '1234' >f
printf 'z' | dd bs=1 of=f seek=2
cat f
# => 12z4
Sie sollten auch ein C-Programm schreiben, das diese Tests durchführt, wenn Ihnen nicht klar ist, welche Systemaufrufe für jeden dieser Befehle aufgerufen werden. (oder Sie könnten auch verwenden strace und herausfinden :-)).
Das andere file_operations etwas aufwändiger sind, hier noch ein paar Beispiele:
Beginnen Sie mit Softwaremodellen vereinfachter Hardware in Emulatoren
Die Entwicklung der eigentlichen Gerätehardware ist „schwierig“, weil:
Sie können eine bestimmte Hardware nicht immer leicht in die Hand bekommen
Hardware-APIs können kompliziert sein
Es ist schwer zu erkennen, wie der interne Zustand der Hardware ist
Emulatoren wie QEMU ermöglichen es uns, all diese Schwierigkeiten zu überwinden, indem wir eine vereinfachte Hardwaresimulation in Software simulieren.
QEMU zum Beispiel hat ein eingebautes pädagogisches PCI-Gerät namens edu, die ich weiter erklärt habe unter: Wie füge ich ein neues Gerät im QEMU-Quellcode hinzu? und ist eine gute Möglichkeit, mit Gerätetreibern zu beginnen. Ich habe einen einfachen Treiber dafür gemacht hier verfügbar.
Sie können dann wie bei jedem anderen Programm printfs oder GDB auf QEMU setzen und genau sehen, was vor sich geht.
Nur eine Frage: Warum willst du den SPI-Treiber umschreiben? Ich habe zuvor den OMAP4-SPI-Treiber verwendet und hatte keine Probleme damit.
– Nils Pipenbrinck
13. August 2014 um 9:45 Uhr
@NilsPipenbrinck: Der Hauptzweck beim Schreiben des Treibers ist das Lernen.
– Sagar Jain
13. August 2014 um 10:02 Uhr
mögliches Duplikat von stackoverflow.com/questions/22706570/… ?
– tauseef_CuriousGuy
3. August 2017 um 9:24 Uhr
Sie können die Zeiger und Verweise auf verschiedene Teile des Geräts sehen. Die Treiber „interagieren“ mit Hardware- und Kernel-Tools, sodass strenge „Öffnen“- oder „Schreiben“-Befehle nicht erforderlich sind.
– ILMostro_7
21. Oktober 2017 um 4:47 Uhr
s/commands/functions/
– ILMostro_7
21. Oktober 2017 um 4:56 Uhr