Prima, wenn das Betriebssystem beim Booten Hardware findet und sogar neu eingesteckte Geräte richtig einbindet. Dumm nur, wenn die gerade laufende Anwendung das nicht bemerkt. Ohne einen Neustart des Programms kommt man in solchen Fällen nicht weiter. Wer etwa eine Videokamera ansteckt, während das Schnittprogramm läuft, braucht kaum zu hoffen, dass es davon etwas mitbekommt. Das HAL-Framework (Hardware Abstraction Layer) bietet die passende Infrastruktur zur Lösung des Problems [1]. Dieser Artikel erklärt, wie man es in eigenen Programmen nutzt.
Im Zentrum der HAL-Architektur steht der Daemon »hald«, der Informationen über Hardware einerseits vom Kernel, andererseits von so genannten Device Information Files (Endung ».fdi«) bekommt (siehe Artikel [2]). Mit ihm kommunizieren Anwendungsentwickler über die Libhal, die alle wichtigen Funktionen dafür bereitstellt.
Zwar wollen sich die Entwickler bis zur Version 1.0 nicht endgültig auf das API festlegen, doch langsam scheint die Häufigkeit der Änderungen abzunehmen. Die Beispiele des Artikels lassen sich mit HAL 0.5.7 unter Fedora Core 5 kompilieren, die Entwicklungsbibliotheken »hal-devel« und »dbus-devel« vorausgesetzt. Die HAL-Version von Ubuntu Dapper Drake ist die gleiche, jedoch heißen die nötigen Entwicklungspakete »libdbus-1-dev«, »libdbus-glib-1-dev« sowie »libhal-dev«.
Gegenüber älteren HAL-Versionen haben sich zum Teil nur die Funktionsnamen geändert, zum Beispiel tragen viele Funktionen nun den Namen »libhal_Funktion()« statt »hal_Funktion()«.
Verbindung zum D-Bus
Im Hintergrund kommunziert jede Anwendung, die HAL verwendet, über D-Bus. Zwar kapselt die Libhal einen großen Teil dieser Kommunikation, ein paar Handgriffe bleiben dem Programmierer aber noch zu tun. An erster Stelle steht die Verbindung zum Systembus, den die Funktion »dbus_bus_get()« mit dem Argument »DBUS_BUS_SYSTEM« herstellt (Listing 1, Zeile 16).
Im Listing steht davor nur noch die Initialisierung der D-Bus-spezifischen Fehlervariablen »dbus_error«. Beispielhaft zeigt der nach der Verbindungsanfrage folgende Code die Fehlerverarbeitung (Zeilen 17 bis 21), bei weiteren Funktionsaufrufen fehlt sie. In richtigen Programmen ist selbstverständlich jeder möglicherweise auftretende Fehler zu behandeln.
In Zeile 23 fordert »libhal_ctx_new()« einen HAL-Kontext an, der im Hintergrund den Zustand und einige Variablen führt, die der Programmierer somit nicht für jede Anfrage angeben muss. Die eigentliche Verbindung zum D-Bus stellt »libhal_ctx_set_dbus_connection()« her.
Lshal selbst gemacht
Das Beispiel in Listing 1 ist eine stark gekürzte Variante des meist schon installierten Tools »lshal«. Sie gibt nur die Geräte auf der obersten Hierarchiestufe aus und geht nicht den ganzen Baum durch, in dem HAL die verfügbaren Geräte strukturiert. Prinzipiell unterscheidet HAL nicht zwischen logischen und physischen Geräten. Es kann also gut sein, dass ein bestimmtes Stück Hardware auf mehreren HAL-Geräte abgebildet ist.
01 #include <stdio.h>
02 #include <hal/libhal.h>
03 #include <dbus/dbus.h>
04 #include <dbus/dbus-glib.h>
05
06 int main(int argc, char **argv)
07 {
08 static LibHalContext *ctx;
09 DBusError dbus_error;
10 DBusConnection *dbus_conn;
11 char **devices;
12 int i_devices, i;
13 char *udi;
14
15 dbus_error_init(&dbus_error);
16 dbus_conn = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error);
17 if (dbus_error_is_set(&dbus_error)) {
18 g_warning("Could not connect to system bus %sn", dbus_error.message);
19 dbus_error_free (&dbus_error);
20 return 1;
21 }
22
23 ctx = libhal_ctx_new();
24 if (ctx == NULL) {
25 g_warning("Could not create HAL contextn");
26 }
27
28 libhal_ctx_set_dbus_connection(ctx, dbus_conn);
29
30 if (!(devices = libhal_get_all_devices (ctx, &i_devices, &dbus_error))) {
31 warn ("HAL not running: %s", dbus_error.message);
32 dbus_error_free (&dbus_error);
33 libhal_ctx_shutdown (ctx, NULL);
34 libhal_ctx_free (ctx);
35 return 1;
36 }
37
38 for (i = 0; i < i_devices; i++) {
39 printf("%sn", devices[i]);
40 }
41
42 dbus_error_free (&dbus_error);
43 libhal_ctx_free(ctx);
44 }
|