tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

General device properties API



Over the last year or so, I’ve been playing around with ideas for a generic device properties API, and have been slowly adding some infrastructure to the kernel to enable it.  Enough of the infrastructure is now in place (or in the pipeline) and I think my design is now fully-formed enough in my head to float it here.

First, the problem statement.  Right now, there are two distinct domains in which device properties live: in the device’s properties dictionary (accessible using device_properties() and then using the proplib(3) APIs to manipulate them) and in the platform’s device tree (e.g. ACPI, OpenFirmware, FDT, Sun OpenBoot, etc.). There is code scattered all around to reflect device tree properties into the device_t’s dictionary, usually in device_register() functions provide by MD code.  There is no common API for accessing the properties provided by the platform device tree.  This, unfortunately, results in a bunch of duplicated-then-tweaked code, odd-ball hacks to attempt to push additional information from MD code to MI drivers, and other such unpleasantness.

I would like to change that.

The API I’m proposing unifies these two domains.  By default, getting a property will fall through to the “lower layer” (the device tree), unless a property has been explicitly set by software, in which case its value is interposed.  There is a separate set of functions that allow software to go directly to the device tree, if needed, using the device’s devhandle directly.

The interface to the device tree’s properties (called the “backing store” in the code) is done using the devhandle / device_call() infrastructure I added earlier.  Device tree back-ends register a set of methods that provide the property access interface, and those methods are looked up based on the device’s devhandle implementation (ACPI and FDT/OFW handles can co-exist in the same system, for example, and the code supports this).  The backing store is consulted if a requested property is not found in the device’s properties dictionary.  Clients should use the correctly-typed API calls to interact with properties, as the dictionary and some backing stores can / do have typing systems (e.g. ACPI), although some (notably the OpenBoot / OpenFirmware / FDT types) do not.  This places some limitations on how clients can interact with properties, but if all the clients follow the typing rules, then things should mostly work out OK.

I’ve modeled the API loosely on the classical OpenBoot / OpenFirmware client API, mainly because it allows for some fairly convenient calling patters that reduce boilerplate code in drivers.  There isn’t a lot of error reporting specificity (-1 is the “an error occurred” return value) mainly because there is very little difference in what the client would do depending on what kind of error occurred, and it’s always possible to disambiguate after the fact by querying other things about the property (e.g. if it exists, what its type is, etc.) for things that really care.  One principle I stuck to was that properties are always returned into caller-provided buffers… this is slightly different than the prom_getprop() function on the sparc port (which has the option to allocate the buffer the caller does not provide one) and is also different than what the FDT code does (which, if you’re using the low-level FDT APIs directly, returns pointers into the static FDT blob).

Anyway, the API:

==> int device_getproplen(device_t, const char *prop);
Returns the size of the specified property, or -1 if the property does not exist.  Properties may have a size of 0.  For strings and binary data, this is very straight-forward.  For integers and booleans, the size is backing-store dependent, but does not necessarily represent the range of the value (e.g. in ACPI, integers are always stored as 64-bit values, even if the largest value that property will ever have is e.g. 16).

==> bool device_hasprop(device_t dev, const char *prop);
This is a wrapper around device_getproplen().  It returns true if device_getproplen() is >= 0.

==>.int device_getpropencoding(device_t dev, const char *prop);
Returns the byte order encoding of the property as defined by the backing store from which the property was fetched (_BIG_ENDIAN or _LITTLE_ENDIAN), or -1 if the property does not exist.

==> prop_type_t device_getproptype(device_t dev, const char *prop);
Returns the type of the property: PROP_TYPE_DATA, PROP_TYPE_STRING, PROP_TYPE_NUMBER, PROP_TYPE_BOOL, or PROP_TYPE_UNKNOWN.  The accuracy of this return value is limited by the capability of the backing store from which the property was fetched.  The device’s property dictionary has full type information for each property.  ACPI has some (ACPI lacks a native BOOL type).  OpenBoot / OpenFirmware / FDT always return UNKNOWN because those backing stores have no typing information.

==> int device_getprop(device_t dev, const char *prop, void *buf, int buflen); 
Fetch the specified binary data property into buf, copying at most buflen bytes.  Returns the actual size of the property in the backing store or -1 if the property does not exist or if the property is not binary data.

==> int device_getprop_string(device_t dev, const char *prop, void *buf, int buflen);
Fetch the specified property as a string info buf, copying at most buflen bytes, **including the terminating NUL**.  If the backing store has typing information, ensures the property is a string.  Returns the actual size of the property in the backing store **including the terminating NUL** or -1 if the property does not exist or is not a string.

==> bool device_getprop_bool(device_t dev, const char *prop);
Fetch the specified property as a bool.  The behavior of this function is somewhat complicated by backing store capabilities.  If the property exists and a BOOL type, the value of the property is returned directly.  If the property is a NUMBER type, returns true if the number in the backing store is non-zero, and false if zero.  Otherwise, returns true if the property exists and false otherwise.

==> int device_getprop_uint32(device_t, const char *, uint32_t *);
==> int device_getprop_uint64(device_t, const char *, uint64_t *);
Fetch the specified property as a {32,64}-bit unsigned integer.  If the backing store supports it, typing will be enforced.  The value will also be range-checked to ensure it fits in the requested type.  For the OpenFirmware-style backing stores, a request for a 32-bit integer will fail if the prop size is not exactly 4 bytes; a request for a 64-bit integer will be allowed for 4 byte or 8 byte properties.  Values returned by these functions are transcoded into the host byte order as needed.

More complex arrangements of numbers and other data objects are extremely difficult to represent in a generic way, especially with untyped backing-stores like OpenFirmware / FDT, so I’m not trying with those (I’m looking at you, of_getprop_uint32_array()).  I think a better approach for those is to provide domain-specific interfaces to the property bindings for those platform device trees.

Here are the corresponding set prop operations… they set values only in the device’s property dictionary, and can override values from the device tree if needed.

int             device_setprop(device_t, const char *, const void *, int);
int             device_setprop_string(device_t, const char *, const char *);
int             device_setprop_bool(device_t, const char *, bool);
int             device_setprop_uint32(device_t, const char *, uint32_t);
int             device_setprop_uint64(device_t, const char *, uint64_t);

This deletes a property from the device’s property dictionary, possibly exposing a property from the device tree that was previously in its shadow.

int             device_delprop(device_t, const char *);

These are corresponding functions that go directly to the device tree backing store.

int             devhandle_getproplen(devhandle_t handle, const char *prop);
bool          devhandle_hasprop(devhandle_t handle, const char *prop);
int             devhandle_getpropencoding(devhandle_t handle, const char *prop);
prop_type_t devhandle_getproptype(devhandle_t handle, const char *prop);

int             devhandle_getprop(devhandle_t handle, const char *prop, void *, int); 
int             devhandle_getprop_string(devhandle_t handle, const char * prop, void *, int);
bool          devhandle_getprop_bool(devhandle_t handle, const char *prop);
int             devhandle_getprop_uint32(devhandle_t handle, const char *prop, uint32_t *);
int             devhandle_getprop_uint64(devhandle_t handle, const char *prop, uint64_t *);

No set prop functions are provided for the device tree layer at this time.

Thoughts / feedback?  Thx.

-- thorpej



Home | Main Index | Thread Index | Old Index