Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions include/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ extern "C" {

#define Z_DEVICE_MAX_NAME_LEN 48

/**@defgroup DEVICE_EXT_API_FLAGS Flags identifying extension APIs.
* @{
*/

/** @brief onoff service supported by the device. */
#define DEVICE_EXT_API_ONOFF BIT(0)

/** @brief foo API supported by the device. */
#define DEVICE_EXT_API_FOO BIT(1)

/**@} */

/**
* @def DEVICE_INIT
*
Expand Down Expand Up @@ -264,6 +276,18 @@ struct device_config {
const void *config_info;
};

/** @brief Extension API's structure/
*
* @param capabilities Mask of supported APIs, see DEVICE_EXT_API_FLAGS.
* @param data If driver has only one capability then it is a pointer
* to data associated with API. Otherwise it is an array
* of pointer.
*/
struct device_ext_api {
u32_t capabilities;
void *data;
}

/**
* @brief Runtime device structure (In memory) Per driver instance
* @param device_config Build time config information
Expand All @@ -275,6 +299,7 @@ struct device {
const struct device_config *config;
const void *driver_api;
void *driver_data;
struct device_ext_api *ext_api;
};

void z_sys_device_do_config_level(s32_t level);
Expand All @@ -293,6 +318,51 @@ void z_sys_device_do_config_level(s32_t level);
*/
__syscall struct device *device_get_binding(const char *name);

/** @brief Check if given extension is supported.
*
* @param dev Device.
* @param api_mask Bit mask identifiing an extension.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use API ID number instead. 32 possibilities are not so much. Independently form fact how compatibility information is stored in drivers properties record.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes api id would allow extension beyond 32 bits and if 32 is too low at some point it can be internally extended without change of any API. I would like to keep it as bitmask internally to reduce overhead. Currently with device supporting only one api extension it is almost instant. Question is if we foresee devices with multple extensions (probably yes).

*
* @return True if supported, false otherwise.
*/
static inline bool z_device_ext_api_supported(struct device *dev, u32_t api_mask)
{
if (dev->ext_api == NULL) {
return false;
}

return dev->ext_api->capabilities & api_mask ? true : false;
}

/** @brief Get extension specific data.
*
* If device supports multiple extensions then assosiated data is stored in
* array. Data is ordered starting from LSB extension bit. If only one extension
* is supported then pointer to associated data instead of array of pointers is
* used.
*
* @param dev Device.
* @param api_mask Bit mask identifiing an extension.
*
* @return Extension data
*/
static inline void *z_device_ext_api_get_data(struct device *dev,
u32_t api_mask)
{
u32_t mask;
u32_t idx;

if (!(dev->ext_api->capabilities & (dev->ext_api->capabilities - 1))) {
return dev->ext_api->data;
}

/* clean all higher bits to get numer of bits set up to current bit. */
mask = (api_mask - 1) & dev->ext_api->capabilities;
idx = __builtin_popcount(mask);

return dev->ext_api->data[idx];
}

/**
* @}
*/
Expand Down
46 changes: 46 additions & 0 deletions include/sys/onoff.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,52 @@ static inline void onoff_client_init_callback(struct onoff_client *cli,
};
}

/** @brief Get onoff service from the device.
*
* @param dev Device.
* @param srv Location where service handler is stored.
*
* @retval 0 on success.
* @retval -ENOTSUP is API is not supported by the device.
*/
static inline int device_get_onoff_service(struct device *dev,
struct onoff_service **srv)
{
if (!z_device_ext_api_supported(dev, DEVICE_EXT_API_ONOFF)) {
return -ENOTSUP;
}

*srv = (struct ononff_service *) z_device_ext_api_get_data(dev,
DEVICE_EXT_API_ONOFF);
return 0;
}

/** @brief Get onoff service from the device subsystem.
*
* Used when device has more than one onoff service.
*
* @param dev Device.
* @param subsys Subsys id.
* @param srv Location where service handler is stored.
*
* @retval 0 on success.
* @retval -ENOTSUP is API is not supported by the device.
*/
static inline int device_subsys_get_onoff_service(struct device *dev,
u32_t subsys,
struct onoff_service **srv)
{
void **data;
if (!z_device_ext_api_supported(dev, DEVICE_EXT_API_ONOFF)) {
return -ENOTSUP;
}

data = (void **)z_device_ext_api_get_data(dev, DEVICE_EXT_API_ONOFF);
*srv = (struct ononff_service *)data[subsys];

return 0;
}

/**
* @brief Request a reservation to use an on-off service.
*
Expand Down
23 changes: 22 additions & 1 deletion samples/hello_world/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,29 @@

#include <zephyr.h>
#include <sys/printk.h>
#include <device.h>
#include <sys/off.h>

void main(void)
{
printk("Hello World! %s\n", CONFIG_BOARD);
struct device *clock = device_get_binding("CLOCK");
struct device *spi = device_get_binding("SPI");
struct onoff_client client;
struct onoff_service *srv;
int err;

err = device_subsys_get_onoff_service(clock, subsys, &srv);
if (err < 0) {
LOG_ERR("Failed to get device onoff service (err: %d)", err);
}

err = onoff_request(srv, &client);

/* hypothetical another api supported by the device */
err = device_get_op_mngr(spi, &op_mngr);
if (err < 0) {

}

err = op_mngr_schedule(op_mngr, transaction);
}