Serial Ports (Was Re: Common Power Management : NUT and HAL (stage 1))

David Zeuthen david at fubar.dk
Mon Aug 7 10:27:04 PDT 2006


On Thu, 2006-08-03 at 21:28 +0200, Arnaud Quette wrote:
> > > > * serial and snmp drivers are not yet managed,
> 
> you once proposed me to sketch that one Dave ;-)

Indeed I did! So here goes:

So my proposal isn't really confined to serial ports but any port where
we cannot automatically detect a device. Here's a few statements

 a) we need user input on configuring the port - this means the user
    needs to choose what device sits on the port, be it a UPS, a
    GPS receiver, modem, smart card reader, input device and so on.
    After the user chooses the device type, we should check that the
    device he chose is actually on the port before it is configured.

 b) the stock install of HAL should leave the ports unconfigured

 c) it needs to be easy for a program to configure the port - OS
    installers and desktop programs come to mind.

 d) once configured we should remember the configuration on hal restarts

 e) the configuration is bound to the system scope, e.g. it doesn't
    change when the user changes

 f) the configuration is bound to the physical machine, e.g. if you
    move the system disk to another system the port should be
    unconfigured when you boot into the new system
    (use-case: boot from USB)

 g) it must be easy for external packages (like nut, gpsd etc.) to tell 
    HAL that it wants to participate in configuring a port. 

 h) we should provide a textual hal utility for configuring a port

So the serial port on my desktop system looks like this

udi = '/org/freedesktop/Hal/devices/pnp_PNP0501_serial_platform_0'
  info.udi = '/org/freedesktop/Hal/devices/pnp_PNP0501_serial_platform_0'  (string)
  linux.device_file = '/dev/ttyS0'  (string)
  linux.subsystem = 'tty'  (string)
  linux.hotplug_type = 2  (0x2)  (int)
  info.product = '16550A-compatible COM port'  (string)
  serial.type = 'platform'  (string)
  serial.port = 0  (0x0)  (int)
  serial.device = '/dev/ttyS0'  (string)
  serial.physical_device = '/org/freedesktop/Hal/devices/pnp_PNP0501'  (string)
  info.capabilities = {'serial'} (string list)
  info.category = 'serial'  (string)
  info.parent = '/org/freedesktop/Hal/devices/pnp_PNP0501'  (string)
  linux.sysfs_path = '/sys/class/tty/ttyS0'  (string)

The proposal involves

 1. all device objects representing legacy ports are tagged with the
    capability "legacy_port". This is easy to do.

 2. we introduce new properties

     legacy_port.type             (string)

    that indicates the type of the port, e.g. "serial". Later on we can
    add e.g. "parallel" or other types.

     legacy_port.is_configured    (bool)

    this property is TRUE if, and only if, the port is configured.

     legacy_port.configured_type  (string)

    if is_configured==TRUE, this is the ''type'' of device the device
    is configured as. The ''type'' is defined below.

     legacy_port.probers.type         (strlist)
     legacy_port.probers.capabilities (strlist)
     legacy_port.probers.programs     (strlist)

    These three properties are filled by either in-tree HAL programs or
    external packages like e.g. NUT that wants to participate in
    configuring legacy ports. It may look like this

     legacy_port.probers.type         = {"nut-serial-ups",        "gpsd-serial-gps",   "hal-serial-modem", ...}
     legacy_port.probers.capabilities = {"battery.ups",           "gps",               "modem", ...}
     legacy_port.probers.programs     = {"nut-hal-serial-prober", "gpsd-serial-probe", "hal-serial-modem-probe", ...}

    where .type contains a opaque type specific to the provider, 
    .capabilities contains HAL capabilities that will be provided if
    bound, and .programs is a program to actually test to see if there
    is a device.

    This is easy to provide for e.g. NUT, it simply includes a HAL FDI
    file that looks somewhat like this

                <deviceinfo version="0.2">
                  <device>
                    <match key="legacy_port.type" string="serial">
                      <append key="legacy_port.probers.type"         type="strlist">nut-serial-ups</append>
                      <append key="legacy_port.probers.capabilities" type="strlist">battery.ups</append>
                      <append key="legacy_port.probers.programs"     type="strlist">nut-hal-serial-prober</append>
                    </match>
                  </device>
                </deviceinfo>
                
 3. With the legacy_port.* properties we can now provide a sane UI
    (both API and UI-wise) to provide probing for serial devices. Said
    configuration programs would look at legacy_port.probers.
    capabilities which contains well-defined HAL capabilities that can
    be translated into the users language. So in addition to the
    legacy_port capability we'd export an interface with methods called

     org.freedesktop.Hal.Device.LegacyPort

    with methods

     UnconfigurePort()

    to simply unconfigure a port and,

     ConfigurePort (IN int proberNumber) 
       throws AlreadConfiguredException,
              NoSuchProberException, 
              ProberDidNotFindDeviceException

    where the latter method, ConfigurePort, will try to run the
    requested prober. If that fails (e.g. return code is != 0) then
    this exception is thrown. If it succeeds, then the properties
    legacy_port.is_configured and legacy_port.configured_type
    is set accordingly.

    It should be trivial to write a textual based program that does
    exactly this and we will do this and include it in tools/ along
    with other smallish tools such as lshal. Similary, programs
    such as gnome-volume-manager (which really should be gnome-hardware-
    manager) would be able to provide the UI for this etc. etc.

 4. To preserve the value of the properties

     legacy_port.is_configured,
     legacy_port.configured_type

    across HAL restarts, the ConfigurePort() method simply saves
    the values somewhere in /var/run/hald/blah and we have a callout
    on the device object pick them up. The file name chosen to save
    it under will include system.product and system.product from the
    /o/fd/Hal/d/computer object to satisfy requirement f) above.

So now we have provided infrastructure for the user to configure the
legacy port. To actually do something with this, software such as NUT
simply includes an FDI file like this

        <deviceinfo version="0.2">
          <device>
            <match key="legacy_port.configured_type" contains="nut-serial-ups">
              <append key="info.addons" type="strlist">nut-addon-for-serial-ups</append>
            </match>
          </device>
        </deviceinfo>
        
and since this is on the device object for the UDI

 /org/freedesktop/Hal/devices/pnp_PNP0501_serial_platform_0

that I listed above you are guaranteed to have the device file in the
property serial.device and you can go from there.

There's a few gotchas in the implementation, but this is pretty much how
I envision we should do this. I'm pretty sure this would work and if
there is consensus I'm happy to do the work for this infrastructure as
well for the serial modem stuff (I don't have a serial UPS). 

Of course, if someone wants to hack on this, I'm happy to review patches
also :-)

Thoughts?

     David




More information about the hal mailing list