Linux Kernel Gerätetreiber entwickeln

Juli 17th, 2009

Ich möchte an dieser Stelle einen kleinen Einblick in den Linux Kernel geben. Und zwar anhand der Entwicklung eines simplen Gerätetreibers.

Allerdings setze ich in diesem Beitrag den Umgang mit Linux, Editoren, dem Kernel und natürlich der Programmiersprache C voraus, da ich momentan nich die Zeit besitze, da auch noch einzuführen.

Was wir brauchen sind also die Header-Dateien unseres laufenden Kernels, einen Editor, C-Compiler und Make. Make ist  nicht zwingend erforderlich, aber sehr hilfreich.

Ich persönlich empfehle den Editor Vi.

Da mein Treiber nicht besonders viel macht, habe ich ihn einfach erstmal lu_driver benannt. Der Quelltext besteht aus einer einzelnen Datei (lu_driver.c), welche ganz am Anfang Header-Dateien einbindet.

In unserem Fall:

#include <linux/fs.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/init.h>

Als nächstes nutzen wir zwei Makros, um bestimmte Formalien festzulegen. An dieser Stelle nur die beiden:

MODULE_AUTHOR(”Lukas Elsner”);
MODULE_LICENSE(”GPL”);

Sehr wichtig ist hier die Wahl der Lizenz, was ich hier aber auch nicht näher ausführen kann.

Jeder Treiber wird durch eine eindeutige Nummer angesprochen. Die legen wir zur besseren Übersicht auch schon hier fest:

#define DRIVER_MAJOR 125

Damit haben wir auch schon das Grundgerüst fast fertig. Jetzt lege ich einfach mal fest, dass der Treiber ein Character Device darstellen wird und durch den Syscall ‘read’ und gesteuert werden kann.

Ein ‘read’ soll uns ein “Hello World” zurückgeben.

Das “Hello World” legen wir in einen statischen Puffer:

static char msg[] = “Hello World\n”;

Im header <linux/init.h> ist die Struktur ‘file_operations definiert, die wir hier nutzen um die Einstiegspunkte zu unseren Funktionen festzulegen.

static struct file_operations fops = {
.open = driver_open,
.read = driver_read,
.release = driver_close,
};

Das bedeutet, dass wir vier Methoden implementieren müssen, wobei die beiden ‘driver_open’ und ‘driver_close’ hier nicht weiter behandelt werden. Sie werden bei jedem Zugriffsbeginn und -ende aufgerufen.

Hier müssen wir beachten, dass die Methoden vor der Struktur stehen müssen, da diese ja sonst noch nicht bekannt sind ;)

Die Methode ‘driver_read’ wird nun bei unserem Syscall ‘read’ aufgerufen.

ssize_t driver_read(struct file *instanz, char __user *userbuf, size_t count, loff_t *offset) {
int not_copied = 0;
count = min(count, strlen(msg) + 1);
if((not_copied = copy_to_user(userbuf, msg, count))) {
printk(”Driver was unable to copy %d byte\n”, not_copied);
}
return count – not_copied;
}

Als Parameter bekommen wir den Pointer auf den Puffer in den wir schreiben können und die Länge, die wir schreiben dürfen übergeben. Die anderen beiden Parameter interessieren uns vorerst nicht.

‘count’ überschreiben wir nun mit dem Rückgabewert aus ‘min(count, strlen(msg) + 1)’, um genau zu wissen wieviele Bytes wir in den Userspace schreiben müssen.

Nun können wir auch schon mit ‘copy_to_user’ unseren statuschen Puffer ‘msg’ in an die Adresse kopieren, die uns der Benutzer übergeben hat. Zurück bekommen wir die Anzahl der Bytes, die nicht kopiert werden konnten. Wenn der Rückgabewert größer als 0 ist, schreiben wir eine entsprechende Meldung mit ‘printk’ ins Syslog.

Nun wird nur noch die Anzahl der wirklich gelesenen Bytes zurückgegeben.

Zum Schluss brauchen wir noch zwei Methoden, die aufgerufen werden, wenn das Modul geladen, respektive entladen wird.

static int __init lu_module_init(void) {
printk(”loading lu_driver\n”);
if (register_chrdev(DRIVER_MAJOR, “lu_driver”, &fops)) {
printk(”couldn’t load module lu_driver\n”);
return -EIO;
}
return 0;
}

static void __exit lu_module_exit(void) {
unregister_chrdev(DRIVER_MAJOR, “lu_driver”);
printk(”lu_driver unloaded\n”);
}

module_init(lu_module_init);
module_exit(lu_module_exit);

Die beiden letzten Zeilen sind Makros, die es uns ermöglichen die beiden Methoden individuell zu benennen, welches wir auch hier genutzt haben.

Wichtig sind hier eigentlich nur die beiden Methoden

register_chrdev(DRIVER_MAJOR, “lu_driver”, &fops)

und

unregister_chrdev(DRIVER_MAJOR, “lu_driver”);

Welche unser Modul in das System ein- bzw. aushängen.
Somit ist unser Treiber auch schon fertig. Damit er automatisch übersetzt werden kann, gibt es eine passende Makefile dazu:

ifneq ($(KERNELRELEASE),)
obj-m := lu_driver.o

else
KDIR := /lib/modules/$(shell uname -r)/build
PWD  := $(shell pwd)
DEVNAME := /dev/lu
DRVNAME := lu_driver.ko

default:
$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
rm -f *~ lu_driver *.o

devices:
rm -f $(DEVNAME)
mknod $(DEVNAME) c 125 0
chmod 666 $(DEVNAME)

install:
insmod $(DRVNAME)

uninstall:
rmmod $(DRVNAME)

reinstall:
rmmod $(DRVNAME)
insmod $(DRVNAME)

endif

Mit dem Befahl ‘make’ wird der Treiber übersetzt und man erhält eine lu_driver.ko im selbigen Verzeichnis.

‘make clean’ bereinigt unseren ordner

‘make devices’ erstellt mit Hilfe von mknod eine Gerätedatei um auf unserem Treiber zuzugreifen (wir erinnern uns an die Nummer 125)

und

‘make install’ läd unser Modul neu in den Kernel.

Nachdem wir nun das Modul übersetzt, die Gerätedatei erstellt und das Modul geladen haben, können wir über /dev/lu den String “Hello world” auslesen.

Entweder ganz einfach per ‘cat /dev/lu’, was aber solange liest, bis man per STRG+C abbricht, oder mit einem eigenen Programm, welches den Syscall ‘read’ auf die Datei /dev/lu aufruft.
Mit ‘make uninstall’ lässt sich das Modul wieder entladen. ;)
Quelltextdownload:
lu_driver (59)

Großer Dank geht an Jürgen Quade, welcher gerade an der Uni Passau einen super Workshop hierzu gemacht hat.

R.I.P Entchen

Juni 24th, 2009

Letzte Nacht ist total plötzlich und durch ungeklärte Ursache unser geliebtes Entchen von uns gegangen. :(

Wir werden dich nie vergessen und immer an die schönen Stunden denken, die du uns bereitet hast.

Ruhe in Frieden.

Entchen, die zweite! ;)

Juni 24th, 2009

This video was embedded using the YouTuber plugin by Roy Tanck. Adobe Flash Player is required to view the video.

Duckmovie

Juni 21st, 2009

This video was embedded using the YouTuber plugin by Roy Tanck. Adobe Flash Player is required to view the video.

Entenmodel :)

Juni 19th, 2009

Alle meine Entchen…

Juni 15th, 2009

Passend zu den Erlebnissen gestern müssen wir diese Woche in Rechnerarchitektur ein MIPS Assembler Programm schreiben, welches das Lied alle meine Entchen spielt. Basierend auf der API, die der MARS bietet, kann man MIDI-Töne abspielen. Die Noten und deren Längen sind vorgegeben. Mein Programm widme ich dem kleinen Entchen! ;)

.data

notes:        .byte    60, 6, 62, 6, 64, 6, 65, 6, 67, 12, 67, 12,
69, 6, 69, 6, 69, 6, 69, 6, 67, 18, -1, 6,
69, 6, 69, 6, 69, 6, 69, 6, 67, 18, -1, 6,
65, 6, 65, 6, 65, 6, 65, 6, 64, 12, 64, 12,
67, 6, 67, 6, 67, 6, 67, 6, 60, 24, -1, 0

sndcall:    .byte    31
sleep:        .byte    32
sndlen:        .word    62
instrument:    .byte     5
volume:        .byte    127

.text
main:
lw $t1, sndlen
lb $a2, instrument
lb $a3, volume
la $t0, notes

loop:
lb $a0, 0($t0)
lb $a1, 1($t0)
mulo $a1, $a1, $t1
beq $a0, $0, endprog
bgezal $a0, playsound
bltzal $a0, pause
addi $t0, $t0, 2
j loop

playsound:
lb $v0, sndcall
syscall
move $a0, $a1
lb $v0, sleep
syscall
jr $ra

pause:
move $a0, $a1
lb $v0, sleep
syscall
jr $ra

endprog:
li $a0, 0
li $a1, 0
li $a2, 0
li $a3, 0
li $t0, 0
li $t1, 0
j endmain

endmain:
li $v0, 10
syscall

Der Übersicht halber sind hier die Comments entfernt. Im Download sind sie selbstverständlich vorhanden ;)

(Bitte liebe Kommilitonen, kopiert es nicht einfach so, sondern erarbeitet euch die Lösung selber. Wenn ihr Fragen habt, stehe ich gerne zur Verfügung)

MARS ist ein in Java geschriebener MIPS Simulator und kann hier herunter geladen werden:
http://courses.missouristate.edu/KenVollmar/MARS/

Das Programm gibt es hier: (Es unterliegt keiner Lizenz, kann also mit der oben genannten Einschränkung nach belieben weiter verwendet werden)
Ducksong (24)

Viel Spaß beim Anhören! ;)

Entchen ;)

Juni 15th, 2009

Gestern war ich mit Martha und ihrer Hündin Baffy in Österreich bei Dandy, damit die beiden sich mal richtig austoben können. Leider hat Baffy eine Entenmama mit ihren Kindern aufgeschreckt und eins von den Kleinen leicht verletzt. Wir haben es mit nach Hause genommen und aufgepäppelt. Am Anfang war unklar, ob es durchkommen wird. Aber es scheint über dem Berg zu sein. Es frisst ohne Ende und hat die neue Mama akzeptiert! ;) Die Familie haben wir bisher leider nicht mehr wiedergefunden. Aber wir bleiben dran. Süß, oder?

Entchen

Entchen

HP Mini 2133 Grafikprobleme mit Ubuntu 9.04

Juni 3rd, 2009

Heute morgen kam eine SMS von Nora, dass ihr HP Mini 2133 nach dem Upgrade von Ubuntu Intrepid 8.10 auf Jaunty 9.04 nicht mehr funktionierte. Es hielt während des Bootvorgangs bei einem schwarzen Bildschirm mit blinkendem Cursor einfach an. Es war nichts zu machen. Man konnte nicht einmal auf eine Konsole wechseln. Erster Gedanke war ein fehlerhaft konfigurierter X-Server. Also vom Live-USB-System gebootet und per chroot in das kaputte System gewechselt:

1. Festplatte mounten, wenn noch nicht geschehen:
# mount /dev/sda1 /mount/point

2.  /proc /sys /dev in /mount/point mounten
# mount -o bind /proc /mount/point/proc
# mount -o bind /dev /mount/point/dev
# mount -o bind /dev/pts /mount/point/dev/pts
# mount -o bind /sys /mount/point/sys

3. resolv.conf nach /mount/point/etc/ kopieren, damit die Namensauflösung funktioniert
# cp /etc/resolv.conf /mount/point/etc/resolv.conf

4.chrooten
# chroot /mount/point

Jetzt wo man im neuen System ist, kann man erst einmal checken ob das Upgrade wirklich geklappt hat. Also mit:

# aptitude update && aptitude full-upgrade

Das schien auch nicht das Problem gewesen zu sein. Als nächstes habe ich die /boot/grub/menu.lst analysiert.
Hier war der forcevesa Schalter aktiviert. Also forcevesa entfernt und zur Sicherheit auch aus quiet splash ein einfaches nosplash gemacht.

Dann:

# update-grub && reboot

Nach dem Neustart startete der X-Server wieder Normal, aber ich habe nur die obere linke Ecke des Desktops, bzw. Login-Screens gesehen.

Nach ein wenig Recherche habe ich herausgefunden, dass der proprietäre WLAN-Treiber von VIA daran schuld ist. Wie soll man denn auf so was kommen??

Also Treiber deaktiviert und das Paket b43-fwcutter installiert.

Nach einem weiteren Neustart sah der Desktop wieder normal aus. Die WLAN-Karte funktionierte auch wunder bar und Nora kann weiter arbeiten! ;)

Danke an die Ubuntu Portale:

http://www.ubuntuforums.org

und

http://www.ubuntuusers.de

Windows CE .NET development

Juni 3rd, 2009

Gestern rief mich ein Arbeitskollege an und beklagte sich, dass das Visual Studio 2008 das .NET Framework nicht korrekt auf dem mobilen Gerät bereit stellt.

Scheinbar wird der Atlanta PDA mit Windows CE 4.0 nicht korrekt erkannt und es wird eine CAB-Datei für eine andere Prozessorarchitektur auf das Gerät Kopiert.
Abhilfe schafft ein alter Blog-Eintrag von mir in unserem geliebten th0ffice, den ich hier jetzt zitiere (incl. Smileys).

Die .NET Compact Framework Anwendungen laufen jetzt auf den Mobilen Windows CE 4.x Geräten.

Microsoft kopiert automatisch das Framework auf die “intelligenten Geräte”.
Leider ist Microsoft nicht so intelligent wie deren Geräte. Sie kopieren nämlich das falsche .NET Framework und so funktioniert garnix.

Zu lösen ist es folgendermaßen:

    -> Automatisches Kopieren des Frameworks in den Projekteigenschaften deaktivieren
    -> Das richtige Framework auf dem Gerät installieren.
    (…\Programme\Microsoft.NET\SDK\CompactFramework\v2.0\WindowsCE\wce400\armv4\NETCFv2.wce4.ARMV4.cab)

Fazit:
Wenn Microsoft was automatisch machen lässt, geht das sowieso in die Hose.
Aber was solls, der Kunde ist ja sowieso meist Beta-Tester… ;)

Kabel Deutschland

Juni 3rd, 2009

Seit einem guten Monat bin ich Kunde bei Kabel Deutschland. Ich habe viele Vorurteile gehabt und man hört nur Schlechtes. Allerdings ist hier in Passau das DSL Netz ziemlich schlecht ausgebaut und sehr langsam. Somit habe ich mich dazu entschlossen selber meine Erfahrung zu machen. Nach einigen Problemen mit der Technikerfirma P&P Service Passau, welche ich hier jetzt nicht weiter erläutern werde, lief alles glatt. Internet rasend schnell, keine Ausfälle, Telefon auch ohne Probleme. Jetzt eine weitere Story der Servicewüste Kabel Deutschland, im Folgenden mit ‘KD’ Abgekürzt. (Diese Mail ging eben an einen Vertrauten, der nah an KD arbeitet und mich bei Problemen immer gut beraten hat)

Ich habe eine weitere in meinen Augen Skandalstory erlebt.
Ich finde es einfach unheimlich frech was KD sich erlaubt und
meine Meinung bestätigt sich immer wieder.

Am Samstag rief mich eine angebliche KD-Mitarbeiterin an.
Allerdings denke ich, dass es eine Mitarbeiterin aus einem Callcenter war, die von KD wenig Ahnung hat.

Sie pries ein dreimonatiges Testabo vom Kabel Digital TV Paket an.

Ich erzählte ihr, dass ich darauf nur unter zwei Voraussetzungen eingehen kann:

1. Der Receiver hat einen HDMI Ausgang (Ich habe nämlich keinen herkömmlichen Fernseher)

2. Ich muss nicht kündigen, sondern NUR wenn ich EXPLIZIT angebe, dass ich es weiternutzen möchte verlängert es sich auch.

Beides hat sie mir mehrfach bestätigt, woraufhin ich zugesagt habe.

Am Sonntag habe ich dann ein wenig recherchiert und erfahren, dass der von KD ausgelieferte HDD-Recorder ein Humax DVR 9900C ist, welcher keinen HDMI Ausgang benutzt. Zudem ist es so, dass KD immer noch keinen HDMI-Receiver zertifiziert hat.

Wie sollen die dann einen ausliefern können???

Das war also die erste Lüge.

Die zweite kam heute mit der Post:

Diverse Unterlagen, aus der einen ich jetzt zitiere:

“Wenn Sie das Abonnement nicht 2 Wochen vor Ablauf der 3 Testmonate kündigen verlängert sich das Abonnement automatisch um 12 Monate”

Wie kann ich am wirkungsvollsten Beschwerde einreichen? Am liebsten soweit, dass die Dame ihre Verkaufsprovision nicht erhält.

Es kann einfach nicht angehen, dass Kunden so an der Nase herumgeführt werden…

Nehmt euch in Acht vor falschen Versprechungen am Telefon. Das kann mächtig in die Hose gehen…