$Progeny$
&author.branden; &author.jdaily;

# The &discover; Hardware Detection System

Discover
2002 Progeny Linux Systems, Inc.
2002 Hewlett-Packard Company
&license.mit;

Linux is a registered trademark of Linus Torvalds.

## What Is &discover;?

&discover; is a tool that reports information about a system's hardware. It uses operating system-dependent modules (selected at build time) to detect what hardware is actually on the system and provides system-independent interfaces for querying &xml; data sources about this hardware. These data sources contain specific information required to enable support for various devices via defined software interfaces. The tool can be accessed by linking to the &discover; library or by calling `discover` (which itself links to the &discover; library) and parsing its output. In the future, other interfaces (for example, modules for interpreted languages such as Perl and Python) may be included.

Why use &discover;? There are at least a few reasons:

- Flexibility. &discover; is designed from the ground up to be flexible. It is portable to a variety of operating environments, and its modular design supports the addition of arbitrary methods for querying the host operating system (OS) about installed devices. &discover; is also designed to be flexible in terms of the types of data that can be retrieved. &discover; does not tie the user to retrieving only one type of information, such as the name of the Linux kernel module that should be loaded to support a given device. Instead, &discover; supports the association of arbitrary data with hardware devices, typically through specification of an interface to the hardware in question, such as a Linux kernel module or an XFree86 server driver module.

- Updatability. Many hardware-autodetection programs suffer from an inherent limitation in that they are restricted to reading hardware lists or databases that are stored on the local filesystem. This is not an efficient approach in the fast-moving world of consumer computer hardware, with new devices constantly being introduced. A couple of months after the latest version of your OS of choice is released, it may fail to recognize that the latest revision of, for instance, a video chipset is compatible with an older one, and can use the same software interfaces. &discover; overcomes this problem by supporting the retrieval of hardware information via &http;

  Other protocols such as &ftp; are available but deprecated; &discover; uses integrity verification mechanisms such as MD5 checksums in the &http; protocol.

  (over the web). When &http; access is impossible, &discover; falls back to locally stored hardware lists.

- Portability. On top of its flexibility in terms of system interfaces to hardware, &discover; has been written to be broadly portable to all of today's popular POSIX-compliant systems. &discover; is not a Linux-only solution. &discover; is intended to provide operating system vendors, computer manufacturers, and third-party vendors of software and peripherals with a powerful tool for describing the hardware they support to the interfaces they care about. Because &discover;'s data sources can be anywhere on the Internet, the OS vendor need not be the sole provider of hardware catalogs.

- Usability. &discover; is not an in-house tool designed to solve a narrow class of problems. &discover; is designed to be easy to use from the perspectives of the individual system administrator, the applications programmer, and the hardware manufacturer or support staff. &discover;'s &xml; database structure, its command-line tools, and its library &api; are well documented and support extensions to meet diverse demands.

- Freely licensed. &discover; has a copyright license that is highly adaptable to the needs of the varied audiences to which &discover; is targeted. Under the so-called UCB/BSD or MIT/X Consortium terms, after the names of American universities and some very well known software projects that used these terms, anyone is free to copy, modify, and distribute the software, and to extend (or not) these same freedoms to those who receive the software. Progeny would like to see &discover; adopted by a wide variety of existing software products, such the various GNU/Linux distributions; the FreeBSD, NetBSD, and OpenBSD projects; the GNU Project of the Free Software Foundation; the XFree86 Project; system integrators; and the designers and manufacturers of computer hardware. We believe that &discover;'s design empowers those with the greatest knowledge of hardware and the software interfaces to that hardware to express that knowledge and make it available to the world, thereby ameliorating an entire class of computer configuration problems. Progeny does not want &discover;'s licensing to stand in the way of realizing that dream, which is why we have chosen these license terms.

We must take a moment to explain what &discover; is not: &discover; is not a replacement for the service — usually provided by the underlying operating system kernel or a user-space program that interfaces with it — of simply translating bus-specific vendor and model identifiers to human-readable names. &discover; performs its own translations of this data as a convenience for generating human-readable reports, but it does not attempt to enumerate all hardware devices that exist for a particular bus architecture. Rather, &discover; is intended only to catalog data for which there is some useful information to impart regarding software interfaces. Facilities already exist in modern operating systems for answering the questions What is the name of this device? and Who manufactured it? &discover;'s role is to answer questions like What Linux kernel module do I need to load for this device to work? More importantly, &discover; will enable you to provide answers in the future to questions you don't even expect to ask today.

&discover; is not intended to be a comprehensive hardware-management tool. It is an enabling technology, designed to provide data that a tool layered above it can use. Two applications are provided with &discover; to demonstrate how the library can be leveraged: the command-line utility &discover-command;, and a Linux kernel module loading script, `discover-modprobe`, designed to be invoked at system boot time.

This manual is divided into four parts. First, we examine the &discover; &xml; data file format, exploring the elements and attributes used to describe hardware and various interfaces to it. This part will enable you to read and understand a &discover; &xml; file. Next, we offer some recommendations for writing your own &discover; &xml; data. Knowing the syntax is valuable, but knowing how best to take advantage of it is even more useful. We then present the reference pages describing Progeny's &discover;-based command-line tools and the configuration files used to control their behavior. You may want to use these references as a guide when implementing your own &discover;-based applications. The final part describes the &discover; library &api; so that you can develop your own solutions based on &discover;. Appendices offer references to the formal descriptions of the &discover; &api; and &xml; &dtd;s.

## Data Structure

### Overview of the &discover; Data Format

Most modern computer peripherals contain self-identifying information in a format standardized for the hardware interface (bus). This enables the OS on the host system to query or scan a bus and catalog the devices. In general, the OS stores this information in the same basic format in which it is returned, without translating it more times than necessary for device drivers to communicate with the peripheral. However, this information varies by bus type and is often insufficiently clear for human consumption. Furthermore, many operating systems do not contain a comprehensive database that maps each peripheral to every subsystem running on the OS that may want to communicate with that peripheral. &discover; addresses these issues by providing flexible databases stored in &xml; format.

Extensible Markup Language (&xml;) is a highly flexible hypertext format. &discover; uses &xml; exclusively to store hardware information externally. Some familiarity with &xml; syntax is therefore assumed. For more information, see the W3C's &xml; website.

For a formal description of &discover;'s &xml; data format, see the &discover; Document Type Definition (&dtd;) document. The purpose of this document is to present the information in a form digestible by the novice.

Because each hardware bus type, such as &pci; or &usb;, communicates different details about the connected devices (essentially, each one solves the same problem in a different way), &discover; has a different set of lists for each bus type. For each bus, up to three lists are stored: a bus class list maps the bus specification's notion of a device type (hereinafter referred to as a device class to reduce confusion) to &discover;'s device types, which are used for running selective queries; a vendor list associates bus-specific vendor identification data with natural-language names for hardware vendors; and a device list contains information specific to individual devices.

### Master List

When &discover; is provided with a &url; for the retrieval of hardware information, the data retrieved is expected to be in &xml; format and to contain further &url;s for retrieval.

The root element must be discover-data, which has no attributes, and can only contain location elements.

The location element is always empty, and has three required attributes: bus, type, and url.

location Attributes

type

  This attribute can have one of these values: busclass, device, or vendor. See , , and .

url

  This must be a valid &url; containing one of the three types of data lists.

bus

  This is the bus to which the &url; applies. See for a list of valid bus names.

### Busclass Lists

As noted in the previous chapter, a busclass list provides a mapping between device classes recognized by the hardware bus and the device type names used by &discover;. Because every bus is different, sometimes there is no perfect, one-to-one correspondence between &discover; device types and the device classes recognized by a particular bus. This is one reason that the busclass lists, like other types of &discover; data lists, are updatable. Revisions in a bus specification may demand updates to the mapping.

The device classes recognized by a bus are typically determined by the specification for the bus as determined by a standards committee or other technical body, and do not change frequently (if at all).

The busclass_list element

    <?xml version="1.0"?>

    <busclass_list bus="usb">
      <busclass id="0202" name="modem"/>
      <busclass id="1030" name="broadband"/>
      <busclass id="0101" name="printer"/>
      <busclass id="ffff" name="imaging"/>
      <busclass id="0206" name="network"/>
      <busclass id="0300" name="humaninput"/>
      <busclass id="ff00" name="video"/>
      <busclass id="0000" name="unknown"/>
      <busclass id="0804" name="removabledisk"/>
    </busclass_list>

In the foregoing example, we can see one possible mapping of the &usb; bus's numeric device class IDs to &discover;'s device type names (see ). The file begins by declaring the version of the &xml; standard to which it conforms, and then presents data. The format should be fairly familiar to those accustomed to &html;-style structured markup languages.

Not all of &discover;'s supported device types are listed in the example; for example, `display` is missing. This is not a problem, since not all buses are used for all hardware applications. &usb; 1.1 would be a poor choice of bus for &vga;-compatible display controllers, for instance, because the available bandwidth on the &usb; 1.1 bus is insufficient to handle typical data loads for such devices.

Another infelicity in the above example is the association of the `ffff` device class ID with the &discover; device type `imaging`. In actuality, a device type class of `ffff` in the &usb; specification indicates a device of an unknown classification. In practice, most consumer-level devices with this device class are scanners, one of the first applications of &usb; technology in the consumer marketplace. It is possible that in certain deployments, the association of &usb;'s unknown device class ID with &discover;'s `imaging` device type is suboptimal — another reason the busclass lists are not hard-coded into the library.

#### The busclass_list element

A busclass_list element possesses a bus attribute and contains one or more busclass elements.

##### The bus attribute

The bus attribute of the busclass_list element is set to the name of the bus being described by the busclass list.

The bus attribute presently supports the following values:

&bus-classes;

We expect to support more buses in the future; `ieee1394` and `sbus` are possible candidates.

#### The busclass element

A busclass element possesses two attributes, id and name, and contains no elements.

##### The id attribute

The id attribute is set to a bus-specific device class identifier.

##### The name attribute

The name attribute is set to a &discover; device type. &discover;'s device types are an effort to balance a few criteria:

- Device types (bus classes in &discover; terminology) defined by the &pci; specification

- Bus classes defined by the &usb; specification

- Bus classes defined by the &scsi; specification

- Device types commonly conceived of by the personal computer user

&discover;'s definitions of device types will not meet with universal agreement; as happens in most categorization problems, some decisions had to be made arbitrarily. &discover; does not attempt to solve the general problem of grouping various peripherals into categories; rather, &discover; solves the problem for itself and uses bus-specific mappings to translate a device's own notion of its type to &discover;'s device type.

&device-types;

### Vendor Lists

Many buses have vendor identification numbers that are registered with that bus's standardization body and programmed into the devices when they are manufactured. These numbers generally are assigned arbitrarily, and typically have little meaning to the end user; therefore, most hardware detection tools provide a way to translate these numeric vendor IDs to human-readable strings. Thus, instead of knowing that your &pci; or &agp; video card was manufactured by 1002, you can determine that it was manufactured by ATI Technologies, Inc.

The vendor_list element

    <?xml version="1.0"?>

    <vendor_list bus="pci">
      <vendor id="0675" name="Dynalink"/>
      <vendor id="0e11" name="Compaq Computer Corporation"/>
      <vendor id="1004" name="VLSI Technology Inc"/>
      <vendor id="1025" name="Acer Incorporated [ALI]"/>
      <vendor id="102b" name="Matrox Graphics, Inc."/>
      <vendor id="109e" name="Brooktree Corporation"/>
    </vendor_list>

The foregoing example is similar in structure to the busclass list example; a numeric vendor ID maps to a vendor name, which can be used by &discover; for queries or reports generated for the user's benefit.

#### The vendor_list element

A vendor_list element possesses a bus attribute and contains one or more vendor elements.

##### The bus attribute

The bus attribute of the vendor_list element is set to the name of the bus being described by the vendor list.

The following bus attributes are supported:

&bus-classes;

#### The vendor element

A vendor element possesses two attributes, id and name, and contains no elements.

##### The id attribute

The id attribute is set to a bus-specific vendor identifier.

##### The name attribute

The name attribute is set to a human-readable vendor identifier, typically the official name of the corporation or other business entity that designed or manufactured that peripheral.

### Device Lists

The device lists are the heart of &discover;'s functionality. They are the most frequently updated lists and contain the information of greatest value.

&discover;'s device lists not only provide a way to identify individual peripherals by name, but also permit the specification of an arbitrary quantity of organized data for each device, supporting an arbitrary number of software interfaces.

The following is a fictitious example. The information within it is for illustrative purposes only. See for a discussion of the real hardware data as provided by Progeny, and for some suggested conventions on organizing the data namespace.

Sample device data

    <?xml version="1.0"?>

    <device_list bus="pci">
      <device busclass="1984" model="0101" model_name="Cerebral Reprogrammer" vendor="B16B">
        <data class="linux">
          <data class="module">
            <data class="name">winston</data>
            <data class="options">base_address=0x300 manual_override=0</data>
          </data>
        </data>
        <data class="win2k">
          <data class="hal_driver">
            <data class="StrUglyHungarianNotatedDriverName">settlement</data>
            <data class="flags">NSA_KEY=96b5f3e3283a62c85f6cb6f4017135c2</data>
          </data>
        </data>
      </device>
    </device_list>

The example above includes a device_list element containing device elements, and a device element that defines the device itself, but reserves any software- or interface-specific details to the data elements it contains.

The actual data provided in the example is accessed by means of data paths; see for further information.

#### The device_list element

A device_list element possesses a bus attribute and contains one or more device elements.

##### The bus attribute

The bus attribute of the device_list element is set to the name of the bus described by the device list.

The following bus attributes are supported:

&bus-classes;

#### The device element

A device element possesses four attributes:

- busclass

- vendor

- model

- model_name

All of these attributes must be specified for each device element. The busclass attribute is set to a busclass identifier, vendor to a vendor identifier, model to a bus-specific model identifier, and model_name to a human-readable vendor identifier, typically the name of the product under which the device reporting the model identifier is sold or otherwise distributed.

A device element contains zero or more data elements.

#### The data element

A data element possesses a mandatory class attribute, an optional version attribute, and zero or more data elements.

The ability to nest data elements inside other data elements affords interface designers and device driver authors the ability to specify a hierarchy of data, instead of being compelled to encapsulate only one piece of data per device for their interface.

##### The class attribute

A class attribute is set to an arbitrary value determined by an interface designer. For data elements whose parent element is a device element, this should be the name of the interface being described, such as `freebsd`, `linux`, or `xfree86`.

A data element whose parent element is a data element should set this attribute to a term reflecting the interface designer's intended data hierarchy. &discover; does not mandate any particular hierarchy for interface designers.

##### The version attribute

Data elements have an optional attribute named version. This indicates a version range applicable to the data contained within the element. The purpose of this attribute is to permit the specification of data that is valid only for a range of versions of the given interface. For example, the Linux kernel changed some of the names of its modules between the 2.2 and 2.4 series.

&discover;'s range syntax, common in mathematical writings, is expressed as an interval; that is, it consists of a pair of endpoints with a comma between them, and brackets or parentheses as qualifiers for inclusion or exclusion of the endpoints' exact values. For example, the version specification `[1.0, 2.0)` matches any version less than 2.0 and greater than or equal to 1.0. It is the responsibility of the calling environment to specify the version of the interface actually in use. In other words, the &discover; library does not take it upon itself to determine the currently running version of the Linux kernel, XFree86 X server, CUPS printing daemon, and so forth.

Due to the lack of consistent standards for version numbers (in fact, some version numbers aren't numbers at all), &discover; requires simplifications for the version attribute. The versions that express the range must be in dotted-decimal form, such as `7.1.0`. The version that is supplied to the &discover; library as part of a query (for example, via the `--data-version` argument to &discover-command;) may or may not comply with this requirement, but should be expressed such that it compares in a desirable way against version strings that do.

In place of the upper end of the range, `inf` (infinity) can be used if the information is still relevant and should be for forseeable versions.

#### Accessing the Device Data

&discover; data is grouped into hierarchical data elements. This data can be accessed via its data path. The data path is the concatenation of the class attribute values of a data element and all its parents, separated by slash (`/`) characters. In the following example, `quux` is accessed via the data path foo/bar:

    <data class="foo">
      <data class="bar">quux</data>
    </data>

In above, we would determine the name of the Linux kernel module (winston) for the Cerebral Reprogrammer device by referencing the data path `linux/module/name`; similarly, the data path `win2k/hal_driver/flags` returns `NSA_KEY=96b5f3e3283a62c85f6cb6f4017135c2`.

## Recommended Data Content Conventions

As discussed in the preface, &discover; is not intended to be a replacement for system utilities such as `lspci` on Linux. A device element should exist for a piece of hardware only if there is some interface information to communicate about the hardware; that is, some data elements to house within the device element. This part of the manual contains Progeny's recommendations on how to organize that information for maximum utility.

### Data Hierarchy

As discussed in , the &xml; structure around the data allows for a hierarchical view.

While &discover; does not mandate any particular hierarchy or namespace organization for data elements, the &xml; files provided by Progeny express — and some applications based on &discover; (such as `discover-modprobe`) expect — a certain structure for Linux kernel module and XFree86 configuration information.

At Progeny, we have often found it convenient to refer to a top-level data element's class attribute value as an interface (see the following example).

Defining an interface

    <device busclass="0300" vendor="de8d" model="90a9" model_name="Stingray">
      <data class="xfree86">
        <data class="server" version="[3, 4)">
          <data class="name">XF86_SVGA</data>
        </data>
      </data>
      <data class="openbsd">
        <data class="security_level">untrusted</data>
      </data>
    </device>

In , two interfaces have been defined for the Stingray device: `xfree86` and `openbsd`.

#### Linux Kernel Modules

A hardware device that requires a particular Linux kernel module should have nested data elements to describe that module. The top-level data element should have a class attribute with a value of linux. Underneath that should be a data element with a class of module.

Within that data element, there should be one or two more, one with a class of name, and an optional one with a class of options. The former has as content the name of the module; the latter, options to be passed to `modprobe`.

Linux interface

    /linux
        |
        |-/module
              |
              |-/name
              |
              |-/options

In , each component of the tree represents a data element; the label is the value of its class attribute.

If the kernel version affects the choice of module name or options, the top-level linux data element should have a version range attribute; see .

Using the linux interface

    <device busclass="0204" model="1702" model_name="IS64PH ISDN Adapter" vendor="0675">
      <data class="linux">
        <data class="module">
           <data class="name">hisax</data>
           <data class="options">io=0x300 irq=11</data>
        </data>
      </data>
    </device>

See for guidance on how to specify different Linux kernel modules for the same device, depending on the version of the Linux kernel in use.

#### XFree86 X Servers

The data hierarchy of a video card device (&discover;'s `display` type) should include a top-level data element with a class attribute of xfree86 (the interface) and likely with a version attribute as well; nested within that element will be a server data element containing a name data element identifying the name of the server executable. For XFree86 version 4.0 or greater, the name will always be XFree86, and the server data element will also contain a device data element, which contains one or more data elements communicating information to be stored in the `XF86Config` file. The children of the device data element are named in correspondence with the syntax of the `XF86Config` file's `Device` section; see the XF86Config manual page for further information. In particular, note that in many cases only a driver data element is necessary.

XFree86 interface

    /xfree86
        |
        |-/server
              |
              |-/name
              |
              |-/device
                    |
                    |-/driver
                    |
                    |-/chipid
                    |
                    |-/chipset
                    |
                    |-/ramdac
                    |
                    |-/dacspeed
                    |
                    |-/videoram
                    |
                    |-/options
                    |
                    |-...

illustrates the xfree86 interface. shows how you might write xfree86 interface information for a &discover; display device.

Using the xfree86 interface

    <device busclass="0300" vendor="1002" model="4654" model_name="Mach64 VT [264VT FT]">
      <data class="xfree86">
        <data class="server" version="[4, inf)">
          <data class="name">XFree86</data>
          <data class="device">
            <data class="driver">ati</data>
          </data>
        </data>
        <data class="server" version="(0, 4)">
          <data class="name">XF86_Mach64</data>
        </data>
      </data>
    </device>

#### Locally-Defined Interfaces

Progeny recommends that publicly distributed &discover; &xml; files avoid using the interface name `local`; that is, a class attribute value of `local` in a top-level data element. This means that data paths such as `local/foo/bar` should not be defined in a public &discover; &xml; file, but both `foo/bar/local` and `foo/local/bar` are okay.

The intention is to reserve this part of the namespace for users' experiments with defining their own — and possibly future, widely adopted — interface definitions for &discover; data. An interface definition could thus be beta tested by a person or organization to ensure that it is efficiently structured before it is unleashed upon the world elsewhere in the namespace, where people may write tools that expect to be able to resolve the interface definition's data paths.

Likewise, Progeny recommends that authors of applications that use &discover; avoid traversing into a top-level `local` data element, which may impose an undesirable support burden on the designers of the interface while they are still working out their design. (The application also may not find the data it desires, or may not get back what it expects.)

### Why Order Matters

When searching device elements, the first exact match will be selected. Subsequent matches are ignored.

Specifically, three comparisons are made:

1. The hardware must provide identification that matches attributes of the device element. As an example, a &pci; device supplies numeric vendor and model identifiers, which are used to match the model and vendor attributes.

2. The class attributes of child data elements must match the data path as given to the library for searching.

3. The first version range, if any, associated with the nested data elements must encompass any version provided by the client.

Matching device elements

Assume that the path `linux/module/name` is provided, along with a version of 2.4.2. The following is sample data; the device elements may be from the same or different data files.

    <device busclass="0000" vendor="102f" model="5555" model_name="100VG ethernet">
      <data class="linux" version="[2.4, inf)">
        <data class="modules">
            <data class="name">vg100</data>
        </data>
      </data>
      <data class="linux" version="[2.0, 2.2)">
        <data class="module">
            <data class="name">vg100</data>
            <data class="options">io=0x300</data>
        </data>
      </data>
    </device>

    <device busclass="0000" vendor="102f" model="5555" model_name="100VG ethernet">
      <data class="linux">
        <data class="module">
            <data class="name">vg100new</data>
        </data>
      </data>
      <data class="linux" version="[2.4, inf)">
        <data class="module">
            <data class="name">vg100old</data>
        </data>
      </data>
    </device>

This item is the first one scanned, and would match, except that the requested data path includes module as a component, not modules as specified here.

This item doesn't match because the provided range is outside the limits defined by the element. (2.4.2 is not greater than or equal to 2.0 and less than 2.2.)

This item matches because no range is given, so vg100new is the value returned.

This is the nearest match, but the &discover; library will never select it because its previous sibling has no version range, and thus will catch any version provided.

### Using Data Versioning

#### Specifying a Range

Because multiple versions of a software interface often are in simultaneous deployment, Progeny recommendeds that the upper bound of a data element's version attribute be defined as the first version that is inconsistent with the information provided within it, and that the upper end of the interval be open (terminated with a parenthesis). As an example, suppose we know that the name of the Linux kernel module to drive the RealTek RTL-8139 Ethernet device was `rtl8139` in the 2.2 kernel series and `8139too` in the 2.4 series. To express this, we would say the following:

Using the version attribute of the data element

    <device_list bus="pci">
    <device busclass="0200" model="8139" model_name="RTL-8139" vendor="10ec">
      <data class="linux" version="[2.4,inf)">
        <data class="module">
           <data class="name">8139too</data>
        </data>
      </data>
      <data class="linux" version="[2.2,2.4)">
        <data class="module">
           <data class="name">rtl8139</data>
        </data>
      </data>
    </device>
    </device_list>

In the first data element, for instance, we would not use a version attribute of `[2.2.0,2.2.19]` because it is needlessly specific. What happens if the Linux kernel developers release Linux kernel 2.2.20? By saying `[2.2,2.4)`, we catch everything in the kernel 2.2 series

We would say `[2.2,2.3)` instead, but, like many Free Software projects, the Linux kernel uses odd minor version numbers to denote unstable, development series of the software, and even minor version numbers to denote stable, production series of the software. In the example, then, we arbitrarily treat all 2.3 series kernels the same as 2.2 kernels.

— past, present, and future.

#### How the &discover; Library Matches a Range

The data files will be searched in order; the first data path that matches the version range or doesn't have a version range will be returned.

Recalling the discussion in , if you want the first data element matching the requested data path to also be the fallback element if no version range applies, you can duplicate that data element and place it at the end. However, a better practice is to make certain that all reasonable versions will match one of the ranges, and that the first range listed has an open-ended high end, such as `[2.4, inf)` for Linux kernel modules in . This will have the effect of assuming that all unversioned requests for `linux` data will be for Linux kernel 2.4 or later.

## Command-Line Tools

### `discover` Manual Page

&discover-1;

### `discover.conf` Manual Page

&discover-conf-5;

### `discover-modprobe` Manual Page

&discover-modprobe-8;

### `discover-modprobe.conf` Manual Page

&discover-modprobe-conf-5;

## Library

### The &discover; Library

#### Library Design Principles

Lazy allocation is used throughout &discover;. This means that there are no init functions, and no functions to scan the bus. Instead, retrieval functions scan or initialize as necessary. Each of these retrieval functions has an equivalent function for freeing the allocated memory. This is valuable to long-lived processes to aid in memory management, but even short-lived processes may want to use them to force reloading of the information.

#### &discover; Data Sources

&discover; knows about one data source by default: the local data from the `discover-data` package. Additional sources can be added with the `discover_conf_append_url` and `discover_conf_insert_url` functions. As their names suggest, they append or insert &url;s on the data source list. Earlier data overrides later data; to override the local data sources, insert &url;s.

#### The Bus Map

Most high-level operations begin at the bus map. Bus maps (discover_bus_map_t) are retrieved with calls to `discover_conf_get_bus_map` or `discover_conf_get_bus_map_by_name`. `discover_conf_get_bus_map` returns an array of maps, one for each supported bus, with the last element being all 0s. `discover_conf_get_bus_map_by_name` returns the map for the named bus. The map contains pointers to all the functions that operate on the bus, as well as the `scan_default` variable, which determines whether the bus is scanned by default. There is also a `scan_never` variable, but it is for internal use only. The name of the bus is stored in the `name` variable.

The following functions are available in the bus map. The get functions take a single discover_error_t argument and return a list of discover_device_t structures, while the free functions take no arguments and return no value.

`get_devices`

  Retrieve the list of devices found on this bus. Returns NULL if the bus is not present on the system, or if no devices are attached to it.

`xml_get_busclasses`

  Retrieve the list of busclasses for this bus (from the &xml; data sources).

`xml_get_devices`

  Retrieve the list of devices for this bus (from the &xml; data sources). Note that this is the list of devices that &discover; knows about, not the list of devices present on the system.

`xml_get_vendors`

  Retrieve the list of vendors for this bus (from the &xml; data sources).

`xml_get_busclass_urls`

  Retrieve the list of &url;s from which busclass data is retrieved. This function is probably not useful to most clients.

`xml_get_device_urls`

  Retrieve the list of &url;s from which device data is retrieved. This function is probably not useful to most clients.

`xml_get_vendor_urls`

  Retrieve the list of &url;s from which vendor data is retrieved. This function is probably not useful to most clients.

`free_devices`

  Free the list of devices.

`xml_free_busclasses`

  Free the list of busclasses.

`xml_free_devices`

  Free the list of devices (the &xml; data, not the list of devices found on the system).

`xml_free_vendors`

  Free the list of vendors.

`xml_free_busclass_urls`

  Free the list of busclass &url;s.

`xml_free_device_urls`

  Free the list of device &url;s.

`xml_free_vendor_urls`

  Free the list of vendor &url;s.

#### Scanning the System

&discover; provides a few ways to scan the system for information.

You can walk the bus map:

    for (i = 0; busmap[i].name; i++) {
        if (busmap[i].scan == DISCOVER_SCAN_DEFAULT) {
            devices = busmap[i].get_devices(&status);
            check_status(status);
            do_something_cool(devices);
        }
    }

You can scan a specific bus:

    devices = discover_get_pci_devices(&status);
    check_status(status);
    do_something_cool(devices);

Perhaps most usefully, you can scan for devices of a specific type:

    devices = discover_device_find("video", &status);
    check_status(status);
    do_something_video(devices);

#### Using discover_device_t Structures

Now that you have some device structures, what can you do with them? The most interesting operation is retrieving data with `discover_device_get_data`. Also available are `discover_device_get_vendor_name`, `discover_device_get_model_name`, `discover_device_get_model_id`, and `discover_device_get_vendor_id`.

`discover_device_get_data` takes a data path and a version number and searches for the first data structure that matches.

`discover_device_get_vendor_name` returns the human-readable name for the device's vendor.

`discover_device_get_model_name` returns the human-readable name for the device's model.

`discover_device_get_model_id` returns the bus-specific ID for the device model.

`discover_device_get_vendor_id` returns the bus-specific ID for the device vendor.

### System Dependencies

#### &api;

The system-dependent code (sysdeps) that must be custom-written for each operating system conforms to a very simple &api;. &discover; invokes `_discover_get_busname_raw()` with no arguments, and expects a linked list of discover_sysdep_data_t structures in return.

The discover_sysdep_data_t structures should contain as much descriptive information as they can regarding the devices discovered. Specifically, the three pieces of information desired are the busclass (device type), vendor identifier, and model identifier, which is a unique identification string that the vendor has provided for the given piece of hardware.

Linux &pci; sysdep code

    #include <config.h>

    #include <stdio.h>
    #include <stdlib.h>

    #include <sysdep.h>

    discover_sysdep_data_t *
    _discover_get_pci_raw(void)
    {
        FILE *f;
        char *line = NULL;
        size_t len = 0;
        discover_sysdep_data_t *head = NULL, *node, *last = NULL;
        unsigned int id;

        if ((f = fopen(PATH_PROC_PCI, "r"))) {
            while (getline(&line, &len, f) >= 0) {
                if (line[0] == '\n' || line[0] == '#') {
                    continue;
                }

                node = _discover_sysdep_data_new();
                sscanf(line, "%*04x\t%08x", &id);
                node->vendor = (id >> 16);
                node->model = id & 0xffff;

                if (head == NULL) {
                    head = node;
                    last = head;
                } else {
                    last->next = node;
                    last = node;
                }
            }
            free(line);
            fclose(f);
        }
        return head;
    }

## &discover; &api; Reference

The &api; reference is here.

## &discover; &dtd;

## &discover; Configuration File &dtd;

## Licensing Issue on the Linux Sysdeps

It should be noted that the Linux-specific files in the `sysdeps/linux` directory of the source distribution are derived from code written for the Detect library by MandrakeSoft SA, and are licensed under the GNU Project's General Public License (GPL).

Note that section 2 of the GPL places requirements on derived works that prevent licensees from exercising some of the permissions granted under the license on the rest of &discover;. However, not everyone who modifies or distributes &discover; will necessarily be subject to the terms of the GPL. If you do not compile, use, or distribute the Linux sysdeps (for instance, if you are building &discover; for FreeBSD), then the license terms on them do not attach.

We realize, however, that it is desirable that all of &discover; be under the the same license terms. There are a few possible solutions to this problem:

- If you do not need the Linux sysdeps, you can delete them from your copy of &discover;.

- You can rewrite the Linux sysdeps. The resulting code will be your work, so the only limitations on you will be those imposed by &discover;'s license. If you do so, we encourage you to license your rewrite under the same terms as the rest of &discover; — in that event, Progeny will be happy to incorporate your code into a future release of &discover;.

- You can contact MandrakeSoft SA and negotiate a different license to their code that is used in the Linux sysdeps.

- You can contact MandrakeSoft SA and attempt to persuade them to relicense their code that is used in the Linux sydeps under the terms used by the rest of &discover;. (MandrakeSoft SA would not have to abandon or assign their copyright.) If you succeed in this effort, please let Progeny know and we will update the license terms on our copy of the MandrakeSoft SA code.

- You can wait; eventually Progeny employees, or some volunteer, will rewrite the Linux sysdeps and license them under the terms that the rest of &discover; uses.

The foregoing discussing is not legal advice and makes no claim to be such. It is a layperson's understanding of the licensing issues from a software developer's perspective. Progeny makes no warranties or guarantees as to the accuracy of the above analysis in a legal context. If you require a professional legal opinion, consult attorneys specializing in copyright and licensed to practice in the jurisdictions of interest to you or to your organization.