Hallo,
Der Kernel ist ein modularer Monolith,
Werden Treiber im Kernel- oder im Userspace ausgeführt?
Den grundlegenden Teil des VFS bilden die Treiber (Driver). Ein Treiber wird vom System anhand eines menschenlesbaren Namens identifiziert und kann Fähigkeiten (Capabilities) bereitstellen.
Der Begriff "Fähigkeit" passt nicht, weil du hier Geräteklassen identifizierst. Fähigkeiten wären eher "kann gelesen werden", "kann geschrieben werden" oder "kann Audio ausgeben", "kann Bilder einlesen".
dass z.B. ein Treiber für die serielle Schnittstelle ja sowohl HID als auch Video-Gerät ist und man so nicht zwei Treiber zu registrieren muss
Eine serielle Schnittstelle ist eine serielle Schnittstelle, nicht Eingabegerät und nicht Kamera. Es ist auch nicht zielführend, mehrere Treiber an eine serielle Schnittstelle zu binden, weil da nur ein Gerät dranhängen kann. (Wenn mehrere Geräte dranhängen, kann man z.B. einen Multiplex-Treiber dazwischen schieben, der von der Beschaltung abhängt. Beispielsweise serielle IR-Sender, die eine Rx-Leitung anbieten, weil der Pin noch frei war: Der Multiplexer bindet dann an die serielle Schnittstelle und stellt eine "serielle Schnittstelle" (nur lesen) und eine "IR-Sendediode" (nur schreibend) zur Verfügung.)
Außerdem hat er eine Liste von Geräten, die von diesem Treiber verwaltet werden.
Ich sehe den Treiber als notwendiges Übel, um mit einem Gerät zu kommunizieren. Dann ist es sinnvoller, die Liste der Treiber zu haben, die für die verschiedenen Geräte zuständig sind.
Ein Gerät wird vom System anhand zweier ID-Nummern identifiziert. Diese müssen nicht unbedingt benutzt werden (0 ist default), und ich denke, dass zwei ausreichen. Bei einem ATA-Treiber kann z.B. die erste für die Platte und die zweite für die Partition stehen, bei Grafikkarten eins für die Karte und eins für den Bildschirm usw.
Was machst du mit Subpartitionen (vgl. Minix, BSD, Solaris)? Bei Grafikkarten gibt es ebenfalls mehr Ebenen: Grafikkarte, Framebuffer, CRTC, Encoder, Output. Mit "nur zwei" schränkst du dich da sehr unnötig ein.
Vollständige Pfade beginnen mit dem Namen des Treibers.
Woher weiß ich, welcher Treiber für ein bestimmtes Gerät zuständig ist?
An dem ersten Beispiel sieht man auch, dass Dateisysteme nicht über den Dateisystemtreiber, sondern über den Massenspeichertreiber angesprochen werden, der den zu benutzenden Treiber ermittelt (und natürlich zwischenspeichern darf).
Das macht das Layering kaputt:
- Woher weiß der Massenspeichertreiber, welche Dateisystemtreiber es gibt und welche er benutzen darf?
- Warum sollte ein Anwendungsprogramm mit der Festplatte reden wollen, wenn es doch nur Dateien aus dem Dateisystem verarbeiten will?
- Was machst du mit virtuellen Dateisystemen, für die es keine Massenspeicher gibt ("Netzwerkumgebung" als Beispiel)?
Noch weiß ich nicht genau, wie ich das Businterface gestalten soll, da damit sowohl z.B. PCI als auch USB verwaltet werden soll
Im Prinzip musst du zwei grundsätzlich verschiedene Ansätze identisch abbilden können: autokonfigurierende Systeme (PCI, USB, ...) und manuell konfigurierte Systeme (ISA, I²C, serielle/parallele Schnittstelle, PS/2, ...). Letztere erfordern Vorwissen über die angeschlossene Hardware.
Das heißt, du musst einen Treiber manuell an einen Bus anhängen können (z.B. "ne2000 @ ISABUS io 0x280 irq 9"), aber der Bus muss das auch selbst können (z.B. "found 10ec:8029 => ne2000"). Letzteres ist für Hotplugging wichtig, kann aber auch von einem Userspace-Programm erledigt werden. Ansonsten muss der Bustreiber nur die Ressourcenverwaltung machen, je nach Bus gibt es da verschiedene Ressourcen, die auch systemweit sein können (ISA/PCI: io/irq/drq/mmio, I²C: Adresse, seriell: nix).
ebenso wie das HID-Interface da man damit auch sowohl Zeigegeräte als auch Tastaturen etc. verwenden können soll
Das wird schon schwieriger. Am besten ist es vermutlich, wenn du dich am Linux-evdev-System orientierst. Praktisch wirst du wenigstens "Tasten", "relative Achse" (Maus) und "absolute Achse" (Joystick, Touchscreen) und "sonstiges/herstellerspezifisch/Konfiguration" unterstützen wollen. Für genug Langeweile kannst du dir mal einen USB-HID-Descriptor zusammenzimmern. Da steckt unglaublich viel Komplexität hinter.
Ich habe das Gefühl, dass deine Treiber eigentlich "nur" ein Verzeichnis bereitstellen, in dem dann verschiedene treiberspezifische Dateien auftauchen, ähnlich wie bei /sys (oder teils noch /proc) unter Linux. Mit dem Unterschied, dass es bei dir keine allgemeine Wurzel gibt, sondern jedes Gerät eine eigene Wurzel hat. Statt vom VFS die Struktur vorzugeben, würde ich eher den Treibern die Möglichkeit geben, Dateien (und Ordner) in dieser Ordnerstruktur anzulegen und die Zugriffe auf diese Dateien als einzelne Callbacks zu definieren. Sonst hast du in jedem Treiber eine einzelne Funktion mit einem großen switch/case drin, was unhandlich ist. Mache den Kernel lieber etwas komplizierter und die Treiber einfacher.
Welche Dateien es gibt und wie diese benutzt werden, sollte per Konvention festgelegt werden; eine Info-Datei mit den wichtigsten Informationen ("Driver: ata", "Interface-Version: 1", "Device: hdd0", "Device: hdd1") ist auch sehr praktisch. Versionierte Schnittstellen sind anfangs vielleicht übertrieben, aber sicherlich auch keine schlechte Idee.
Vielleicht hilft es.
Gruß,
Svenska