Using HAL
This chapter gives a quick tour of HAL (Hardware Abstraction Layer). For in-depth background information, technical documentation and a specification, consult http://www.freedesktop.org/wiki/Software/hal.
Background
The purpose of HAL is to provide means for storing data about hardware devices, gathered from multiple sources and to provide an interface for applications to access this data. In essence, HAL provides a list of devices, and a way to add configuration values for each device. As a concrete example of what kind of information HAL contains, the command line application 'lshal' can be used to query the HAL daemon for all device objects that it is aware of. Here is some example output from Internet Tablet device:
Dumping 54 device(s) from the Global Device List:
-------------------------------------------------
udi = '/org/freedesktop/Hal/devices/computer'
info.addons = {'hald-addon-cpufreq'} (string list)
info.bus = 'unknown' (string)
info.callouts.add = {'hal-storage-cleanup-all-mountpoints'} (string list)
info.capabilities = {'cpufreq_control'} (string list)
info.interfaces = {'org.freedesktop.Hal.Device.SystemPowerManagement',
'org.freedesktop.Hal.Device.CPUFreq'} (string list)
info.product = 'Computer' (string)
info.subsystem = 'unknown' (string)
info.udi = '/org/freedesktop/Hal/devices/computer' (string)
org.freedesktop.Hal.Device.SystemPowerManagement.method_argnames =
{'num_seconds_to_sleep', 'num_seconds_to_sleep', '', '', '', 'enable_power_save'}
(string list)
org.freedesktop.Hal.Device.SystemPowerManagement.method_execpaths =
{'hal-system-power-suspend', 'hal-system-power-suspend-hybrid', 'hal-system-power-hibernate',
'hal-system-power-shutdown', 'hal-system-power-reboot', 'hal-system-power-set-power-save'}
(string list)
org.freedesktop.Hal.Device.SystemPowerManagement.method_names =
{'Suspend', 'SuspendHybrid', 'Hibernate', 'Shutdown', 'Reboot', 'SetPowerSave'}
(string list)
org.freedesktop.Hal.Device.SystemPowerManagement.method_signatures =
{'i', 'i', '', '', '', 'b'} (string list)
power_management.can_hibernate = false (bool)
power_management.can_suspend = true (bool)
power_management.can_suspend_hybrid = false (bool)
power_management.can_suspend_to_disk = false (bool)
power_management.can_suspend_to_ram = true (bool)
power_management.is_powersave_set = false (bool)
system.firmware.name = 'NOLO' (string)
system.firmware.product = 'N800' (string)
system.firmware.version = '1.1.6' (string)
system.formfactor = 'unknown' (string)
system.hardware.product = 'RX-34' (string)
system.hardware.serial = '0000000000000000' (string)
system.hardware.uuid = '24202524' (string)
system.hardware.vendor = 'Nokia' (string)
system.hardware.version = '1301' (string)
system.kernel.machine = 'armv6l' (string)
system.kernel.name = 'Linux' (string)
system.kernel.version = '2.6.21-omap1' (string)
udi = '/org/freedesktop/Hal/devices/computer_mtd_0_8'
info.bus = 'mtd' (string)
info.parent = '/org/freedesktop/Hal/devices/computer' (string)
info.product = 'MTD Device' (string)
info.subsystem = 'mtd' (string)
info.udi = '/org/freedesktop/Hal/devices/computer_mtd_0_8' (string)
linux.device_file = '/dev/mtd4ro' (string)
linux.hotplug_type = 2 (0x2) (int)
linux.subsystem = 'mtd' (string)
linux.sysfs_path = '/sys/class/mtd/mtd4ro' (string)
mtd.host = 0 (0x0) (int)
...
udi = '/org/freedesktop/Hal/devices/platform_mmci_omap_1_mmc_host_mmc_card_rca58916_storage'
block.device = '/dev/mmcblk0' (string)
block.is_volume = false (bool)
block.major = 254 (0xfe) (int)
block.minor = 0 (0x0) (int)
block.storage_device =
'/org/freedesktop/Hal/devices/platform_mmci_omap_1_mmc_host_mmc_card_rca58916_storage'
(string)
info.capabilities = {'storage', 'block'} (string list)
info.category = 'storage' (string)
info.parent =
'/org/freedesktop/Hal/devices/platform_mmci_omap_1_mmc_host_mmc_card_rca58916'
(string)
info.udi =
'/org/freedesktop/Hal/devices/platform_mmci_omap_1_mmc_host_mmc_card_rca58916_storage'
(string)
linux.hotplug_type = 3 (0x3) (int)
linux.sysfs_path = '/sys/block/mmcblk0' (string)
storage.automount_enabled_hint = true (bool)
storage.bus = 'mmc' (string)
storage.drive_type = 'sd_mmc' (string)
storage.hotpluggable = true (bool)
storage.media_check_enabled = false (bool)
storage.model = '' (string)
storage.no_partitions_hint = false (bool)
storage.originating_device =
'/org/freedesktop/Hal/devices/platform_mmci_omap_1_mmc_host_mmc_card_rca58916' (string)
storage.partitioning_scheme = 'none' (string)
storage.physical_device =
'/org/freedesktop/Hal/devices/platform_mmci_omap_1_mmc_host_mmc_card_rca58916' (string)
storage.removable = false (bool)
storage.removable.media_available = true (bool)
storage.removable.media_size = 125960192 (0x7820000) (uint64)
storage.requires_eject = false (bool)
storage.size = 125960192 (0x7820000) (uint64)
storage.vendor = '' (string)
As can be seen in the output, the configuration data for each device, identified by a UDI (Unique Device Identifier), is stored as key-value pairs. Similar information can be queried about each device known to HAL. For instance, the type and size of an MMC memory card can be found in the HAL database, as well as other essential information (see the last device in the above example). HAL also contains information about disk volumes, such as file system types, mount points, volume sizes etc. The 'category' and 'capabilities' fields of the configuration describe what the device is and what it does. For a complete description of the device properties, see HAL specification.
The following example illustrates data contained in HAL about the Internet Tablet's camera device. The example demonstrates an important aspect of HAL: its ability to monitor the state of each device in real-time. State changes in devices known to HAL are broadcast to D-BUS. Thus, the state of each interesting device from an application's point of view can be asynchronously monitored. Notice how the database keeps track of the exact state of the camera in the following example: whether the camera is active, and whether it has been turned 180 degrees.
udi = '/org/freedesktop/Hal/devices/platform_cam_turn'
button.has_state = true (bool)
button.state.value = true (bool)
button.type = 'activity' (string)
info.addons = {'hald-addon-omap-gpio'} (string list)
info.bus = 'platform' (string)
info.capabilities = {'button'} (string list)
info.linux.driver = 'gpio-switch' (string)
info.parent = '/org/freedesktop/Hal/devices/platform_gpio_switch' (string)
info.product = 'Platform Device (cam_turn)' (string)
info.subsystem = 'platform' (string)
info.udi = '/org/freedesktop/Hal/devices/platform_cam_turn' (string)
linux.hotplug_type = 2 (0x2) (int)
linux.subsystem = 'platform' (string)
linux.sysfs_path = '/sys/devices/platform/gpio-switch/cam_turn' (string)
platform.id = 'cam_turn' (string)
udi = '/org/freedesktop/Hal/devices/platform_cam_act'
button.has_state = true (bool)
button.state.value = true (bool)
button.type = 'activity' (string)
info.addons = {'hald-addon-omap-gpio'} (string list)
info.bus = 'platform' (string)
info.capabilities = {'button'} (string list)
info.linux.driver = 'gpio-switch' (string)
info.parent = '/org/freedesktop/Hal/devices/platform_gpio_switch' (string)
info.product = 'Platform Device (cam_act)' (string)
info.subsystem = 'platform' (string)
info.udi = '/org/freedesktop/Hal/devices/platform_cam_act' (string)
linux.hotplug_type = 2 (0x2) (int)
linux.subsystem = 'platform' (string)
linux.sysfs_path = '/sys/devices/platform/gpio-switch/cam_act' (string)
platform.id = 'cam_act' (string)
It is important to notice, that the devices in HAL database do not necessarily have a one-to-one correspondence with a physical device. For instance, in the previous example the camera has two separate devices in HAL for two different functionalities. This is intentional: the purpose of HAL is to abstract the entire set of physical devices into a functional categorization. The devices in HAL represent the smallest addressable unit.
C API
In order to make developers' life easier, the communication to the HAL daemon has been wrapped into a C library. Thus, applications can easily use the services provided by the library to monitor and query different devices. For a complete description of the API, see libhal.h (in package libhal-dev). Here, the basic steps to set up a connection to HAL and some basic functions are described. Error checking etc. are omitted from the examples, for the sake of clarity.
Setting up a connection to HAL is performed as follows:
include <libhal.h>
void set_up(void)
{
LibHalContext *ctx;
DBusConnection *dbus_connection;
DBusError error;
ctx = libhal_ctx_new();
dbus_error_init(&error);
dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
libhal_ctx_set_dbus_connection(ctx, dbus);
/* ... */
After setting up a connection, listener callbacks can be registered:
libhal_ctx_set_device_added (ctx, _device_added);
libhal_ctx_set_device_removed (ctx, _device_removed);
libhal_ctx_set_device_property_modified(ctx, _property_modified);
Finally, initialize the connection and start listening to HAL:
libhal_ctx_init(ctx, &error);
libhal_device_property_watch_all(ctx, &error);
The listener functions and the application in general can obtain information about devices using functions in libhal. For instance, as a device gets connected, the following functions can be used to obtain information about it:
/* If UDI is known (the callbacks provide a UDI for added/removed devices),
existence of specific capabilities can be queried with the following function: */
if(libhal_device_query_capability(ctx, udi, "volume", NULL)) {
/* Capability "volume" exists */
...
}
/* The library also provides plenty of get/set functions for querying specific
information about a device by its UDI. For instance, querying the storage.
drive_type property of the device, which is created by HAL when a memory card
is inserted into the Internet Tablet device, returns 'sd_mmc', indicating an
active memory card reader for SecureDigital/MultiMediaCard memory cards. */
libhal_device_get_property_string (ctx, udi, "storage.drive_type", NULL);
All the query functions follow the same pattern. The HAL specification describes the type of each property. The types can optionally be queried with the 'lshal' tool, which adds type information into its output. For each type, libhal provides a get/set function, such as libhal_device_get_property_string(), libhal_device_get_property_int(), etc. The library also provides functions for listing all devices and their properties: libhal_get_all_devices(), _device_get_all_properties(), if more user-controlled filtering is needed.