HAL Draft Specification 0.1 (work in progress) Version 0.1-wip September 12, 2003 David Zeuthen
david@fubar.dk
Introduction This is a specification of a hardware abstraction layer (HAL) that allows applications to enumerate and use devices present in a typical desktop system. A device, in the context of the HAL, is identified by a unique string, it got a state variable (e.g. enabled, or booting) and a set of properties (key/value pairs). This document specify a set of known properties and give them well-defined meaning. This enables applications and desktop environments to make a distinction between the different device objects and use the devices based on certain well-known properties. For instance, the Category property specifies what kind of device it is (such as a digital camera or an audio device), and the Storage.Mountpoint property specifies where in the filesystem a storage device is mounted. For audio devices, the volume and bass/trebble settings could be controlled by the a set of properties that would be monitored by a sound server. Other well-defined properties specify what programs to invoke (loading kernel modules, mounting filesystem etc.) when a device is plugged in or removed. This specification also make recommendations on how desktop environments (such as GNOME or KDE) should behave when a device is added or removed. The specification itself is desktop environment neutral. Finally, this specification is concerned with so called device information files that should be shipped with devices on standard media or made available on the vendors web-site. A device info file matches a subset of devices (from properties derived from the physical bus the device is on) and populates them with other, often well-defined, properties. Device info files are by no means substitute for driver software, they are simply hints to the desktop environment / applications about what the device is, what it does, how to bootstrap it and what drivers are required. Note that this document is not concerned with implementation details; it is merely a specification. Therefore, whenever possible, we refrain from referring to specific technology used such as IPC frameworks, support libraries, programming languages, desktop environments, operating systems and so on. We assume UNIX-like systems like Linux and FreeBSD. There is also an implementation here that tracks the specification. Version control Version Date Comment 0.1 September 12, 2003 Version 0.1 is not finalised yet! Some changes from the initial proposal posted to xdg-list. Biggest change is the removal of KernelModules Acknowledgement Havoc Penningtons article "Making Hardware Just Work" motivated this specification. HAL Architecture The hardware abstraction layer shall comprise the following executables and libraries hald a system-wide daemon that maintains a database of device objects, ie. device id, state and properties. A property is a key/value pair where both key and value is UTF8 strings. Keys must not contain whitespace. The device id must be an ASCII string without whitespace. libhal a shared library that applications use to query and modify the device database by communicating with hald. Receives notifications from hald when the device database is changed. hal_hotplug a program invoked, usually by the operating system kernel or /sbin/hotplug, when a hardware device is added or removed. Captures bus- and device specific information and passes it on to hald along with the add/remove message and a computed unique id. libdeviceinfo a shared library that can select a set of device info files that matches positive given a device object. lshal, hal_set_property, ... Various commandline tools to query and modify the device database. It is outside the scope of this specification to discuss these, since they are trivial applications of libhal. Required Properties The following properties are always present for a device and must conform to the the values and semantics below. Note that device state is also stored as a property. Depending on which bus a device is attached, there may be additional required properties. Key Value(s) Description Bus legacy | pci | usb | ieee1394 | infrared | bluetooth Physical bus type the device is attached to. Bus identifiers MUST documented in this specification, and must be named in small ASCII letters without any whitespace State This property specifies the current state of the device regarding availability (plugged, or unplugged) and whether it is operational. unplugged The device is unplugged disabled The device is disabled booting The device is booting shutdown The device is shutting down enabled The device is enabled and ready to use req_user The device can possibly be enabled, but it requires user interaction to do so. error The device experienced an error booting need_device_info There is no device info file that match the device Required Properties for enabled, req_user For a device with a state that is enabled or req_user, the following properties must be present and conform to the values and semantics below Key Value(s) Description Vendor Name of the vendor of the device Product Name of the device DeviceInfoFileVendor Name of the vendor of the device info file Category Storage The device is a storage device that can be mounted in a file system ... Other categories. New categories MUST be documented in this specification. Categories must be in InterCaps and only contain ASCII letters and no whitespace. Optional Properties One or more of the following properties may be present for a device. if they are, they must conform to the values and semantics below Key Value(s) Description Serial A string unique to the instance of the device plugged in Persistent true Even though the device is not plugged in it will still appear in the device database with State unplugged. All properties for the device will remain persistent. false The device and all it's properties will be removed from the device database once the device is not present. This is the default behaviour if the Persistent property is not available RequireDisable true The device requires the user explicitly to disable the device before removing it. false The device doesn't require to be disabled before it is removed. This is the default behaviour if the RequireDisable property is not available. RequireEnable true The device requires the user explicitly to enable the device before using it. false The device will automatically boot when added. This is the default behaviour if the RequireEnable property is not available. BootProgram example: "modprobe usb-storage; hal_mount_usb_storage" A semicolon separated list of programs (with arguments separated by white space) that is sequentially executed by hald when a device starts to boot. No shell substitution or other shell features is being performed. The intention is that these programs are used to load kernel drivers, mount devices, upload firmware etc. These program MUST NOT interact with the Desktop Environment - there are other mechanisms for doing that. If one of the programs exit with an exit code that is not 0 or 1 the sequential execution stops. The state of the device changes to error and a notification is broadcast to applications using libhal. If one of the programs exit with an exit code that is 1, the sequential execution stops. The state of the device changes to req_user and a notification is broadcast to applications using libhal. If all of the programs exit with an exit code that is 0, the state of the device changes to enabled, and a notification is broadcast to applications using libhal. The programs execute in an environment where all the present device properties are available as environment variables with the keys prefixed with HAL_. These UTF8 strings are encoded, as specified here, to support legacy applications. Other available environment variables includes DEVICE (set to the unique id of the device) and ACTION set to boot. PATH is set to /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin The programs can modify device properties either through libhal or supplied commandline tools linking with libhal. Specifically, the programs can set the properties ConfigureProgram or ConfigureRequiredProperties. ShutdownProgram example: "hal_unmount_usb_storage; rmmod -a" A semicolon separated list of programs (with arguments separated by white space) that is sequentially executed by hald when a device enters the shutdown state or is removed without prior being disabled (e.g. if the user unplugs an unlocked device). The intention is that these programs are used to unload kernel drivers, unmount devices etc. These program MUST NOT interact with the Desktop Environment - there are other mechanisms for doing that. The programs execute in an environment where all the present device properties are available as environment variables with the keys prefixed with HAL_. These UTF8 strings are encoded, as specified here, to support legacy applications. Other available environment variables includes DEVICE (set to the unique id of the device) and ACTION set to shutdown. PATH is set to /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin If the device is plugged out when being in state enabled, rather than being explicitly disabled first, then the environement variable UNCLEAN_REMOVAL is set to true - otherwise it is set to false. The programs can modify device properties either through libhal or supplied commandline tools linking with libhal. ConfigureProgram example: "proprietary_vendor_app" A program, potentially with a graphical user interface, that can be run for a device when the state is req_user. Note that hald does not invoke this program, but expect applications in a, e.g., Desktop Environment to link with libhal and let them invoke them. This facility SHOULD NOT be used, if a solution using ConfigureRequiredProperties can be used instead. ConfigureRequiredProperties example: "Storage.Mountpoint, Storage.SomeProprietaryProperty" A comma-separated list of properties that needs to be set before the device can be enabled. This is normally set by either one of the programs specified by the BootProgram property or inherited from a device info file. USB Bus Specific Properties For each bus type in a computer, property Bus, there can be a set of required properties that provide information about the device attached. These properties MUST start with the name of the bus following a dot. The following properties are required for usb devices Key Value(s) Description usb.idVendor example: "46d" USB Vendor Id in hexadecimal usb.idProduct example: "c012" USB Product Id in hexadecimal usb.bcdDevice example: "1320" USB bcdDevice number coded in BCD usb.bDeviceClass 3 USB device class in decimal usb.bDeviceSubClass 1 USB device subclass in decimal usb.bDeviceProtocol 2 USB device protocol in decimal usb.bInterfaceClass USB interface class in decimal, only available if usb.bDeviceClass is 0 usb.bInterfaceSubClass USB interface subclass in decimal, only available if usb.bDeviceClass is 0 usb.bInterfaceProtocol USB interface protocol in decimal, only available if usb.bDeviceClass is 0 usb.linux_devfs example: "/proc/bus/usb" Where the USB "drivers" list lives. Only available on Linux with usbfs. Unavailable in Linux 2.5 and later usb.linux_device example: "/proc/bus/usb/002/008" The path to the usbdevfs node for this device. Only available if usbfs is enabled usb.linux_devpath example: "/sys/must/install/2.6/hehe" Only in Linux 2.5 and later kernels; /sys/$DEVPATH is the sysfs directory for this device or interface The following properties are optional for usb devices Key Value(s) Description usb.VendorString example: "Logitech Inc." Name of the vendor, conforming to the USB registry. Is a function of only usb.idVendor usb.ProductString example: "DeskJet 880c/970c" Name of the product, conforming to the USB registry. Is a function of only usb.idProduct Storage Category Specific Properties For each category of a device, there may be a set of required properties that provide information about the how to use the device. These properties MUST start with the name of the category following a dot. The following properties are required for Storage devices: Key Value(s) Description Storage.MountPoint example: "/home/david/CompactFlash" Location in file system where to mount the device The following properties are optional for Storage devices: Key Value(s) Description Storage.Device example: "/dev/sda1" Device that is representing the device Storage.MountOption.<fstype>.<mountoption> example: Storage.MountOption.fat.uid := "david" Set mount options for device Specification of libhal libhal is a shared library that appplications link with. The application initialise libhal and gives a pointer to a block of callback functions. They include HalFunctions hal_functions = { mainloop_integration, device_property_changed, device_added, device_remove, device_booting, device_shutting_down, device_disabled, device_need_device_info, device_boot_error, device_enabled, device_req_user }; Upon initialisation, libhal communicates with hald through IPC mechanisms to get the list of devices available. When a property of a device change, libhal must get notified by hald and invoke a user generated callback. Similar when a device change state, the appropriate callback is invoked. The IPC mechanism used MUST be able to easily integrate with the main loop of popular support libraries. libhal MUST NOT spawn new threads. The following functions must be available in libhal int hal_initialize(const HalFunctions* functions); int hal_shutdown(); unsigned int hal_get_num_devices(); int hal_get_devices(HalDevice** devices, unsigned int num_devices); char* hal_device_get_id(HalDevice* device); char* hal_device_get_property(HalDevice* device, const char* key); int hal_device_set_property(HalDevice* device, const char* key, const char* value); int hal_device_get_num_properties(HalDevice* device); int hal_device_get_properties(HalDevice* device, char** keys, unsigned int num_keys); HalDevice* hal_find_device_by_id(const char* id); int hal_device_enable(HalDevice* device); int hal_device_disable(HalDevice* device); libhal MUST have as few dependencies as possible. libhal function specification TODO Specification of device info files TODO Recommendations for Desktop Environments TODO Use case: Hot plugging USB Storage Suppose an user is inserting a USB Compact Flash Reader into the computer for the first time hal_hotplug is invoked by the kernel or /sbin/hotplug and sends usb.* and Bus properties along with a unique id to hald. hald, using libdeviceinfo, finds a device (it matches on usb.* properties) and merges a number of properties including (but not limited to) Category = Storage RequireDisable = true BootProgram = modprobe usb-storage; hal_mount_usb_storage ShutdownProgram = hal_unmount_usb_storage; rmmod -a Persistent = true ConfigureRequiredProperties = Storage.MountPoint hald executes BootProgram and usb-storage is inserted into the running kernel. hal_mount_usb_storage is invoked and it returns 1 because Storage.MountPoint is not set. hald changes a property for the device State = req_user and sends a notification to running applications linked with libhal. The hal_watcher, an application (using libhal) that is part of a desktop environment, receives the notification and prompts the user for a mount path. Note that the hal_watcher is implemented with respect to this specification, so it knows the semantics of the well-know property Storage.MountPoint and the fact it is required because it knowns ConfigureRequireProperties. The user selects the location ~/CompactFlash and hal_watcher sets the property (assuming that the user is david, but the desktop environment know this) to Storage.MountPoint = /home/david/CompactFlash The hal_watcher sends a message to hald to try to enable the device again. (Note: desktop environment might also use predefined hidden mount points and instead give access through a virtual file system URI, so the user doesn't need to be asked). Again, BootProgram is invoked by hald; it successfully mounts the device at at the specified location (note this is possible! hald runs with root privileges). This time it returns 0. hald sets State = enabled and broadcast a notification to running applications linked with libhal that a device is now in enabled state. The hal_watcher sees that state is enabled and RequireDisable is true, so it puts a "Stop Device" icon in the notification area and informs the user (through a balloon) that her device is ready to use, and that the "Stop Device" icon must be clicked before unplugging it. If file managers link with libhal they can show the device - if the property Storage.Device is set they can report available space etc. TODO: use case for unplugging the device, flowchart The next time the device is inserted, the user doesn't have to go through user interaction (where to mount it) because Persistent==true. Issues The following is a list of issues that need to be addressed in this draft specification at some point. multiple device info files How should we handle when multiple device info files matches a device? Priority field, most recent, let the user pick? non-pluggable devices / probing The HAL should handle devices that are not pluggable and is known by the operating system prior to the invocation of hald. This could be achieved through a boot script "cold plugging" the devices through probing. support for legacy devices For x86-compatible machines this may be serial, PS/2 and hardware ports. security model / privileges We need to have a security model. Some devices may not be available to certain user / groups (think locked down kiosk mode) and we need to specify what privileges are required for reading or writing certain properties. Furthermore, we need to guard our selves against the obvious local root exploit where a malicious user writes a device-info file himself and sets BootProgram to execute code of his own choice that execute with the privilege of root. network transparency We need to figure out what to do here. One interesting thing to target at first, might be terminal servers with X terminals that has USB ports. Ideally, users of such terminals should be able to plug-in their USB hardware and use it in the desktop environments as it were a local desktop. Also, a subset of the hardware in the X terminal, such as a sound card (if available) should be available in the desktop environment running on the terminal server. multi user systems this is somewhat related to network transparency issues, but there needs to be a way to lock down access to devices for users not at the console. relation to other projects This specification should be discussed with existing projects (such as linux-hotplug) regarding integration and cooperation. The implementation must, as far as possible, build on top of existing software. Both the specification and implementation should, as far as possible, be operating system agnostic.