Subject: Device Properties: The Next Generation
To: None <tech-kern@netbsd.org>
From: None <eeh@netbsd.org>
List: tech-kern
Date: 02/15/2001 19:15:38
Here's a revamped vversion of the device properties proposal:



				Device Properties


1	Summary

I propose adding properties and accessors to device nodes.  There are a number
of cases where drivers need to pass information to other drivers or acquire
information that is not available to them and accessible only through machine
dependent code.  To solve these sorts of problems I propose adding a property
framework to allow arbitrary data to be associated with particular device nodes.

Examples of data that are currently problematical but could easily be passed
as properties are device locators, which require and arbitrary bus-specific
structure to pass betwen the parent bus node and the child device node, and
MAC addresses for ethernet devices, which on some machines are available by a
simple firmware call, but on others require the driver to dig bits out of an
EPROM.

The most useful aspects of device properties occur when the parent driver is
able to add properties which a child device uses during its attach routine.
The current infrastructure makes this impossible since the child device
structure is not available to the parent until after it has finished
attaching.


2	Synopsis


2.1	Flags

PROP_WAIT	-- Specify that the call can sleep.
PROP_INHERIT	-- Inherit properties from parent.
PROP_ALL	-- Operate on all properties.


2.2	Functions


   struct device *config_found_smd(struct device *dev, void *aux, 
			cfprint_t print, cfmatch_t submatch, 
			struct device *propdev);
   struct device *dev_config_found(struct device *parent, 
			struct device *propdev, cfprint_t print, 
			cfmatch_t submatch);
   struct cfdata *dev_config_search(cfmatch_t fn, struct device *parent, 
			void *aux, struct device *propdev);
   struct device *dev_config_attach(struct device *parent, struct cfdata *cf, 
			void *aux, cfprint_t print, struct device *propdev)


   struct device *dev_create(void);
   void dev_destroy(struct device *);
   int dev_setprop(struct device *dev, const char *name, void *val, 
			size_t len, int flags);
   int dev_copyprops(struct device *source, struct device *dest, 
			int flags);
   size_t dev_getprop(struct device *dev, const char *name, void *val, 
			size_t len, int flags);
   int dev_delprop(struct device *dev, const char *name, int flags);

   size_t md_getprop(struct device *dev, const char *name, void *val, 
			size_t len, int flags);


3	Description

A property is a tuple that consists of a pointer to a device node (struct
device *), string, and an arbitrary amount of data.  This tuple is established
by dev_setprop(), retrieved by dev_getprop(), and destroyed by dev_delprop().  In
addition, there is a machine dependent hook, md_getprop()[1] that is called if
attempting to retrieve a property fails.  md_getprop() can then use any
arbitrary method to generate property data if it so desires, or cause a failure
to be reported.

This functionality will be implemented in two phases.  The first phase will
add these functions, but retain the existing behavior for compatilbility.
dev_create(9) will generate a dummy device node that the parent can use to 
attach properties to.  config_attach*(9) functions will then create the real
device node and migrate properties to it.

The second phase will separate the `struct device' from the device's softc.
dev_create(9) will create the true device node, which config_found*(9) will
attach to the device tree.  If the device probes successfully,
config_attach*(9) will allocate a separate device softc structure and link it
to `struct device'.  If devices are detached, the `struct device' will remain
with all its properties but the softc will be destroyed.  This change will
cause breakage in practically all existing device drivers, so it will be
relegated to some future date.


3.1	New Functionality

int dev_setprop(struct device *dev, const char *name, void *val, size_t len, 
			int flags);

Create a property `name' and attach it to `dev' with a `len' byte value 
copied from location `val'.  If PROP_WAIT is not specified then dev_setprop(9)
will not sleep for resource shortage.  Returns 0 on success or an error value.


int dev_copyprops(struct device *source, struct device *dest, int flags);

Copy all properties associated with `source' device to `dest' device
structure.  If PROP_WAIT is not specified then dev_copyprops(9) will not sleep
for resource shortage.  Returns 0 on success or an error value.


size_t dev_getprop(struct device *dev, const char *name, void *val, 
			size_t len, int flags);

Retrieve a property called `name' associated with `dev'.  If the property is
not found dev_getprop(9) will call md_getprop(9).  If the flag PROP_INHERIT is
set, and there is no property with that name associated with this device node,
it will try to retrieve the property from any parent device nodes.  Returns -1
if the property cannot be found, otherwise it returns the length of the value
data and if `val' is not NULL it copies up to `len' bytes of the property data
to the location pointed to by `val'.


int dev_delprop(struct device *dev, const char *name, int flags);

Remove a property from a device node.  If the flag PROP_INHERIT is set it will
look for that property in any parent device nodes.  If the flag PROP_ALL is
set it will remove the property from that device node and all parent device
nodes.  If a NULL is supplied for the name, dev_delprop(9) will remove all
properties from a device node.  If a NULL is supplied for the name and
PROP_ALL is set, dev_delprop(9) will remove ALL properties from a device node
and all its parents.  It returns 0 on success or an error value.


size_t md_getprop(struct device *dev, const char *name, void *val, 
			size_t len, int flags);

If defined an a machine dependent header file, this function is called when
ever an attempt is made to retrieve a property from a device node but the
property is not found.  It allows machine dependent code to look up properties
from other locations.  It should be implemented to behave the same way as
dev_getprop(9) does.  It does not need to traverse parent device nodes.


struct device *dev_create(int flags);

Properties require a device structure to contain them, so dev_create(9) is
used to create a temporary device to which properties can be attached.  It can
be passed in to config_found_smd(9) to make these properties available to the
child device as it probes and attaches.  If PROP_WAIT is not specified then
dev_create(9) will not sleep for resource shortage.  Returns a pointer to a
`struct device' on success, and NULL on error.


void dev_destroy(struct device *);

This is used to destroy the temporary device once it is no longer required.
It will not work on devices that are attached to part of the device tree.


struct device *config_found_smd(struct device *dev, void *aux, 	cfprint_t print, 
			cfmatch_t submatch, struct device *propdev);

In addition to config_found(9), and config_found_sm(9), config_found_smd(9)
can be used to supply device properties to child devices during probe and 
attach.  The `propdev' parameter is passed down to config_search(9) and
config_attach(9).


struct device *dev_config_found(struct device *dev, struct device *propdev,
		 	cfprint_t print, cfmatch_t submatch);

dev_config_found(9) is intended as an interface for bus drivers that no longer
need to supply an `aux'.  The `propdev' parameter will initally be a dummy
container but later will be the real child device node.


struct cfdata *dev_config_search(cfmatch_t fn, struct device *parent, void *aux, 
			struct device *propdev);

dev_config_search(9) takes an additional parameter `propdev' which is a
pointer to a device which provides a set of properties for devices to use
during probe.  If `propdev' is not NULL, locator data are attached to it as
properties, it is passed to the probe routine as the `aux' parameter and
the value passed in as `aux' is ignored.  The probe routine needs to know to
cast `aux' to a pointer to a device and extract properties rather than use it
as a pointer to configuration data.

struct device *dev_config_attach(struct device *parent, struct cfdata *cf, 
			void *aux, cfprint_t print, struct device *propdev)

If a non-NULL `propdev' is passed in to dev_config_attach(9), all properties
attached to it are moved to the newly created device node for the device
being attached.



[1] Providing md_setprop() and md_delprop() would be possible but make the
framework much more complicated.  If permanent storage of properties is
desired it should use some machine dependent method since non-volatile
storage is not necessarily available on all architectures.