diff --git a/include/device.h b/include/device.h index 8f556058203c6..dfd9b4ea1698a 100644 --- a/include/device.h +++ b/include/device.h @@ -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 * @@ -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 @@ -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); @@ -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. + * + * @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]; +} + /** * @} */ diff --git a/include/sys/onoff.h b/include/sys/onoff.h index 363e62d08d4ac..49c5a9a4d6409 100644 --- a/include/sys/onoff.h +++ b/include/sys/onoff.h @@ -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. * diff --git a/samples/hello_world/src/main.c b/samples/hello_world/src/main.c index 6c5c8a27dc698..dd63c34370ef5 100644 --- a/samples/hello_world/src/main.c +++ b/samples/hello_world/src/main.c @@ -6,8 +6,29 @@ #include #include +#include +#include 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); }