2.3.2 Devices access

2.3.2.1 Device classes  

MutekH use different APIs to provide access to different types of device. A device class API is defined by a set of specific function pointers. APIs are defined in device class headers and are implemented by device drivers.

A device driver may actually implement multiple device classes when the device has multiple functions. Additionally, device drivers must implement the dev_init_t, dev_use_t and dev_cleanup_t functions.

The following device classes are available:

Driver implementation of classes may or may not need to access the hardware:

  • A driver may access memory mapped registers of a device directly.

  • A driver may not access the hardware directly, relying on an other device like an I2C or SPI bus controller.

  • A driver may just wrap access to an other device in order to provide additional features like cached accesses, stream multiplexing, memory partitioning...

  • A pure software implementation of a device driver with no dependencies may exist as well. Cryptographic algorithms, or data sinks implementations are common examples.

2.3.2.2 Device status  

A device must go through several initialization steps in order to be usable.

First, the instance of the struct device_s object must be linked to a struct driver_s object. When the device is created by dynamic enumerations, the driver registry is searched for a matching driver automatically. When the device is declared statically by the DEV_DECLARE_STATIC macro, a pointer to the driver is specified.

The initialization of the device by the driver is not started until all dependencies expressed in the device resources are satisfied. This mean that all device path references in the resources of the device must be valid and point to an other device which is at least partially initialized.

Once a driver is available and its dev_init_t function has been called successfully, the device can accessed by other modules, including the application.

However, a driver may not be able to complete initialization of a device immediately:

  • When the driver has started an asynchronous operation as part of the device initialization. The completion of the initialization will be signaled by the driver from a deferred execution context. This requires definition of the CONFIG_DEVICE_INIT_ASYNC token.

  • The driver may put the device in a partially initialized state. This can be temporary or permanent. Some classes of the driver may be usable at this point. This happens for various reasons: when not all dependencies are satisfied yet or when an error condition is detected. This requires definition of the CONFIG_DEVICE_INIT_PARTIAL token.

  • Partial and asynchronous initialization can be combined. Some more driver classes may become available over time in this case.

When the CONFIG_DEVICE_CLEANUP token is defined, the dev_cleanup_t function of drivers is responsible for

The device_status_e enum specifies the possible initialization states of a device.

2.3.2.3 Device accessor  

Accessing a device require setting up a struct device_accessor_s object. A specific type of accessor actually exist for each device class API. Accessor type names of are of the form struct device_classname_s.

As device drivers may implement multiple classes, it is required to initialize a device accessor object for the right class. A device accessor has two roles: it is a live reference to the device object and a shortcut to one of the API implemented by the driver. When the driver provides access to multiple sub-devices with the same functions, a numerical id must also be provided.

struct device_timer_s t;
err = device_get_accessor(&t.base, timer_dev, DRIVER_CLASS_TIMER, 0);

It is also possible to initialize a device accessor from the device path in the tree:

err = device_get_accessor_by_path(&t.base, NULL, "/timer[0]", DRIVER_CLASS_TIMER);

When running from an scheduler context the device_wait_accessor and device_wait_accessor_by_path functions can be used to wait for a device initialization to complete.

Classes specific functions can then be invoked on the device by using the DEVICE_OP macro:

dev_timer_value_t date;
err = DEVICE_OP(&t, get_value, &date, 0);

device_put_accessor(&t.base); /* release the device */

See also DEVICE_HAS_OP, DEVICE_OP, struct device_accessor_s, device_copy_accessor, device_get_accessor and device_get_accessor_by_path.

Valid XHTML 1.0 StrictGenerated by diaxen on Wed Oct 17 21:18:37 2018 using MkDoc