hal draft spec

David Zeuthen david at fubar.dk
Wed Sep 10 00:47:19 EEST 2003


At http://www.ometer.com/hardware.html Havoc Pennington writes:
> Making Hardware Just Work
> This is a draft document last updated July 10, 2003. Please send 
> comments to Havoc.
>
> That I know of, nobody is working on implementing this yet. You 
> should do it!

I'm a first-time poster to OSS lists. If this is the wrong list, I
apologize. 

I also apologize, in advance, for this long mail...

So, I have been playing around with working on a ''hardware abstraction
library'' over the last week. I was inspired by Havoc's paper.

The reason I'm sending this mail is to get some feedback on the
architecture and design before working on a real implementation. Is
anyone else working on this?

I'm hoping this can result in some kind of work leading up to a 
freedesktop.org specification and subsequent perhaps a freedesktop.org
implementation.

I got a prototype implementation with some short cuts relative to my
draft spec below.. I'm prepared, at some point (e.g. when it conforms to
some specification), to release this under a free software license.

Let me try to explain what my prototype currently does. It's supposed,
at best, to be some kind of draft spec..

OVERVIEW

First a definition: A device is encapsulated by a Device object,
containing the following two entities

  o  a textual id that uniquely identifies the device. This must be
     an ASCII string.

  o  a set of (key, value) pairs. Key is an ASCII string, while value
     is an UTF8 string

PROGRAMS AND LIBRARIES

My prototype is built using D-Bus and it contains the following elements

 o  libhal - hardware abstraction library
    This is the hardware abstraction library, in short it provides
    functions named hal_list_devices, hal_device_set_property,
    hal_device_get_property as well as notifications when device
    a device changes state and when properties change cf. Havoc's
    paper.

    It communicates with hald, the hardware abstraction layer daemon,
    using D-Bus. It gets all the devices and their properties using a
    single method call. Changes in the hardware list is broadcast from
    hald (using org.freedesktop.DBus.broadcast) and received by
    processing linking with libhal.

    Caveat: Uses a separate thread.
    Caveat #2: Could potentially use a lot of memory per process 
               using it

 o  hal_hotplug - hardware abstraction library hotplug helper
    This is a process that reports when a device is added or removed.
    Currently it only support USB devices and Linux. To use it I
    change /proc/sys/kernel/hotplug to point to the executable.

 o  hald - hardware abstraction library daemon
    This is a daemon that handles communication with a) processes
    linking to libhal; and b) hotplug agents.
    For hotplug agents, like USB, it gets the standard USB information.
    This information is simply stored as properties in the Device*
    object. 
    A device-driver is searched for, and if one is found additional
    properties are merged into the Device* object. Based on these
    properties certain things happen as specified in section 
    PROPERTIES below.
    Caveat: My current implementation of hald only works with hotplug
    devices. It could be integrated to probe hardware using existing
    hardware libraries.
    Caveat #2: see DEVICE DESCRIPTIONS
    Caveat #3: Device lists are store in-memory

 o  lshal
    A very simple application using libhal; it simply shows the list of
    devices and their properties. This is updated when it changes. This 
    is my main testbed.

The prototype implementation is currently tied to Linux but moving it to
other OS's should be straightforward. The only real dependency I
explicitly have is dbus-1 (which, btw, is very nice software)

PROPERTIES

The following properties are always present for a device and must
conform to the the values and semantics below

 Bus = usb | pci | bluetooth ...  ; Physical bus-type the device is
                                  ; attached to. Is Bus the right 
                                  ; word to use? (think bluetooth)
  
 State = unplugged  |  ; the device is unplugged (only possible with
                       ; Persistent==true)
         disabled   |  ; the device is disabled (active choice by the
                       ; user)
         booting    |  ; the device is booting (e.g. uploading firmware
                       ; or mounting itself into the filesystem)
         shutdown   |  ; the device is shutting down (e.g. unmounting
                       ; itself from the filesystem)
         enabled    |  ; the device is enabled and ready to use
         enabled_req_user | ; the device is enabled but requires some
                            ; user configuration (e.g. where to mount
                            ; a storage device etc.) to function
                            ; properly.
                            ; (see property ConfigureProgram, 
                            ;  ConfigureRequiredProperties)
         error_kernel |   ; there was an error loading kernel drivers
                          ; when booting the device
         error_bootprog | ; there was an error invoking the Bootprogram
                          ; when booting the device
         needs_driver     ; the device needs a device-info file.
                          ; Implies, and is implied by, Driver==false

  Driver     = true  |   ; A driver was identified for this device
                         ; If this is set to true, then the property
                         ; DriverIdentifier must exist and the value
                         ; must be a unique id of the driver.
                         ; (reverse domainname style)
               false     ; No driver was identified for this device.
                         ; Desktop Environments should react to this
                         ; and provide means for the user to locate/
                         ; install/force a driver etc.
                         ; (blacklists / whitelists)

For a device with State==enabled|enabled_req_user, the following 
fields must be present and conform to the values and semantics below

  Vendor       = <string>  ; Name of the vendor of the device
  Product      = <string>  ; Name of the product this device represents
  DriverVendor = <string>  ; Name of the vendor of the device driver
  Category = Storage | ;For devices that a filesystem can be mapped onto
             Camera  | ; Still Imaging, camera-like devices
             Input   | ; Devices that allows the user to interact with
                       ; the host computer
             ...       ; (need to expand on this.. should we fix this
                       ;  or can new devices introduce new Categories?
                       ;  I think the latter...)
      
  
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

 Serial = <string>      ; 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 list with
                        ; state unplugged. All properties for the device
                        ; will remain persistent (this is useful for
                        ; 'personal' devices such as PDA's, MP3 players
                        ;  or cameras)
              false     ; the device and all it's properties will be
                        ; removed once the device is not present. This
                        ; is the default behaviour.

 RequireDisable = true  |  ; The device requires the user explicitly
                           ; to 'stop' (disable) the device before
                           ; removing it. (This might be useful for 
                           ; storage devices)
                           ; 
                           ; Desktop environments SHOULD offer a 
                           ; 'stop icon' in the notification area if 
                           ; any devices with State==enabled* and
                           ; RequireDisable==true is in the device list
  
                   false   ; The device doesn't require to be stopped.
                           ; This is the default (think USB HID devices)
  
 BootProgram = /path/to/executable

When a device is just plugged in or enabled, this program is executed.

While the program is running the State property of the device is set to
booting.

If the return code is 0 the property State will be set to enabled. This
means that the device is ready to use. If the return code is 1 the
property State will be set to enabled_req_user. This means that input is
required from the user to function properly. Otherwise it will be set
to  error_bootprog. This means there was an error booting/configuring
the device

The two arguments to this program is a) the unique id of the
device; and b) the string 'boot'. This way the program can populate the
necessary properties for using the device (using libhal) and create the
necessary /dev files, major/minor numbers, permissions etc.

This program MUST NOT attempt to integrate with the Desktop Environment.
If user intervention is required, then the program can return 1 (to set
the State property to enabled_req_user) and then the Desktop Environment
will prompt the user for configuration. 

Optionally, the property ConfigureProgram can be set to HINT the DE
of a program for configuration.. When the DE have gathered input from
the user and added the requried properties from the device, the DE can
prompt hald to run ConfigureProgram again.

Optionally, and orthogonal to setting ConfigureProgram the property
ConfigureRequiredProperties can be set HINT the DE of what the user
needs to configure..

Devices with Bootprograms that return 1, e.g. requires user
intervention, SHOULD set the property Persistent to true

(TODO: security, privileges?)


 ShutdownProgram = /path/to/executable 

When a device is removed or disabled, this program is executed. While
the program is running the State property of the device is 'shutdown'

The two arguments to this program is a) the unique id of the device and
b) the string 'shutdown'

(TODO: Should an application using libhal be able to veto a shutdown?)

(TODO: can this fail? how should
       we handle it?)
(TODO: security, privileges?)


 KernelModules = mod1 mod2 ...        

A whitespace separated list of kernel modules that will be loaded in
order once the device is inserted just prior to running the Bootprogram.
When the drivers are loading the State property is set to booting

If the loading of the kernel modules fails the State property will be
set to error_kernel

Once the ShutdownProgram is finished these modules will be removed in
the reverse order. (TODO: can this fail?)


 ConfigureProgram = /path/to/executable

A program the DE can run if a the State property is set to
enabled_req_user. It is usually supplied by the device vendor. Device
vendors should be discouraged to supply proprietary configuration
programs if a solution not requiring such a program exist.

 ConfigureRequiredProperties = Property1 ... 

A list of properties that needs to be set before the device is fully
configured. This is normally set when Bootprog returns 1 since this sets
property State to enabled_req_user

If Bus==usb the following properties are always present. See the USB
standard for semantics
 
 usb.idVendor                      ; hexadecimal
 usb.idProduct                     ; hexadecimal
 usb.bcdDevice                     ; hexadecimal
 usb.bDeviceClass                  ; decimal
 usb.bDeviceSubClass               ; decimal
 usb.bDeviceProtocol               ; decimal
 usb.bInterfaceClass               ; decimal
 usb.bInterfaceSubClass            ; decimal
 usb.bInterfaceProtocol            ; decimal

If Bus==usb and if usbfs (formerly usbdevfs) is enabled (this is
linux-centric I realize)

 usb.devfs                ; Where the USB "drivers" list lives
 usb.device               ; The path to the usbfs node for this device

Required properties for devices where Category=Storage when
State=enabled (Note: is it too oldschool to require that a storage
device can be mounted in the UNIX filesystem?)

 UnixMountpoint = /path/to/mount     ; Location in the local file-
                                     ; system where the device is
                                     ; mounted

Optional properties for devices where Category=Storage

  GnomeVfsUrl = <URL>        ; Gnome VFS URL where the storage on
                             ; the device can be accessed
  
  KdeVfsUrl = <URL>          ; KDS VFS URL (is it called that?) where
                             ; the device can be accessed

  UnixDevice = /path/to/dev  ; UNIX device that is mounted

I could go on here, but I hope you get the picture. This should really
be in a specification somewhere.


USE CASE

Suppose you are inserting an USB Compact Flash Reader into your computer
for the first time

 o  hal_hotplug is invoked by the kernel and sends usb.* and 
    Bus property to hald.

 o  hald finds a device (it matches on usb.* properties) and merges
    a lot of properties including (but not limited to)

     Type            = Storage
     KernelModules   = usb-storage
     RequireDisable  = true
     BootProgram     = /some/handler/program
     ShutdownProgram = /some/handler/program
     Persistent      = true

 o  usb-storage is successfully inserted into kernel

 o  BootProgram is invoked, it sets 

     ConfigureRequiredProperties = UnixMountpoint

    and returns 1. It, ofcourse, needs input from the user where it
    should mount the device.

 o  hald sets

     State = enabled_req_user

    and sends a notification to libhal users (the desktop environment)

 o  The gnome_hal_watcher (or kde_hal_watcher), a desktop application
    using libhal, receives the notification and prompts the user for
    a mount path. The user selects the location

     ~/CompactFlash

    hal_watcher sets the property (assuming that the user is david)

     UnixMountPoint = /home/david/CompactFlash 

    The hal_watcher sends a message to hald to try to boot the device
    again.

 o  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

 o  hald sets

     State = enabled

    and broadcast a notification to libhal users that a device is now
    in enabled state.

 o  The hal_watcher sees that State==enabled and RequireDisable==true
    so it puts a "Stop Device" icon in the notification area.

If Nautilus links with libhal it can show the device (in the side pane
with different roots perhaps?)  - the same goes for Konqueror etc.

The next time the device is inserted, the user doesn't have to go
through where to mount it because Persistent==true. The DE should just
notify him, through a balloon in the notification area, that the device
is now mounted.

I hope this clarifies the intentions with having a well-defined set of
properties to manage the process of handling devices. There are many
other use cases (no driver, driver doesn't work etc.) that should be
verified.

DEVICE DESCRIPTIONS

This I haven't worked on yet. My prototype simply has some C code in
hald that fills the appropriate properties for my USB devices:

        if( strcmp(device_store->device_get_property(device, 
                   "usb.bInterfaceClass"),
                   "8")==0 &&
            strcmp(device_store->device_get_property(device, 
                   "usb.bInterfaceSubClass"),
                   "6")==0 &&
            strcmp(device_store->device_get_property(device, 
                   "usb.bInterfaceProtocol"),
                   "80")==0 )
        {
            device_store->device_set_property(device, 
                                              "Driver", 
                                              "true");
            device_store->device_set_property(device, 
                                              "DriverIdentifier",
                                              "my_lexar");
            // TODO: should use USB vendor and product info
            device_store->device_set_property(device, 
                                              "Vendor", 
                                              "Lexar");
            device_store->device_set_property(device, 
                                              "Product", 
                                              "CF Card Reader");
            device_store->device_set_property(device, 
                                              "DriverVendor", 
                                              "Tux");
            device_store->device_set_property(device, 
                                              "Category", 
                                              "Storage");
            // TODO: Change this to a program that will mount this disk
            device_store->device_set_property(device, 
                                              "BootProgram", 
                                              "/bin/true");
            device_store->device_set_property(device,
                                              "RequireDisable",
                                              "true");
            device_store->device_set_property(device, 
                                              "KernelModules", 
                                              "usb-storage");
        }

We can probably define some clever XML files that match different
devices and works over several versions of several operating systems.

This is really the killer - hardware vendors could ship a single .fdi
(free device information) file along with their windows drivers. 

This would, for simple devices like CF readers (for which
OS-vendor-drivers are available), make the device work on many operating
systems.

The discover library from Progeny might be used for this - it looks
great, but I haven't looked too much into this.


USING DEVICES

I haven't thought much about this. 

I suppose that we really need a specification about the well-know
properties for well-known device types like my attempt above with
Type==Storage. 

For Type==Camera we might talk with the gphoto2 authors etc.


FINAL THOUGHTS

I agree with Havoc - someone should really work on this. 'Making
Hardware Just Work' seems, IMHO, to be one of the only real hindrances
for free desktops. 

I'm prepared to work on it (disclaimer: I can only work on it in my
spare time). How should we proceed?

Comments are appreciated.

Best regards,
David


-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-    David Zeuthen             pgp key:     http://fubar.dk/pgpkey.asc
-  david(at)fubar.dk           pgp key id:                    b89bab82
-                              

    "We are upping our standards ... so up yours." - Pat Paulsen
    for President, 1988.




More information about the xdg mailing list