device: Provide generic API to handle synchronous calls in drivers
Introduce the device_sync_call_t object type and its API. This object type allows one thread to perform synchronous calls into a driver. Only one thread can do such calls per instance of the device_sync_call_t object since it makes a global record of what type of thread is waiting on it. Based on an idea from Dmitriy Korovkin and Peter Mitsis, moving their proposal to a more generic API provides the solution for all device drivers that exposes synchronous API in an interrupt based implementation. Change-Id: I793fac76645396bf4eb6be38b5a130ac6bde8f73 Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
parent
86a0ab478b
commit
55fdd1fd33
3 changed files with 163 additions and 0 deletions
105
include/device.h
105
include/device.h
|
@ -85,4 +85,109 @@ struct device {
|
|||
void _sys_device_do_config_level(int level);
|
||||
struct device* device_get_binding(char *name);
|
||||
|
||||
/**
|
||||
* Synchronous calls API
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <nanokernel.h>
|
||||
#ifdef CONFIG_MICROKERNEL
|
||||
#include <microkernel.h>
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Specific type for synchronizing calls among the 2 possible contexts
|
||||
*/
|
||||
typedef struct {
|
||||
/** Nanokernel semaphore used for fiber context */
|
||||
struct nano_sem *f_sem;
|
||||
#ifdef CONFIG_MICROKERNEL
|
||||
/** Microkernel semaphore used for task context */
|
||||
struct _k_sem_struct _t_sem;
|
||||
ksem_t t_sem;
|
||||
bool caller_is_task;
|
||||
#endif
|
||||
} device_sync_call_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize the context-dependent synchronization data
|
||||
*
|
||||
* @param sync A pointer to a valid devic_sync_call_t
|
||||
*/
|
||||
static inline void synchronous_call_init(device_sync_call_t *sync)
|
||||
{
|
||||
nano_sem_init(sync->f_sem);
|
||||
#ifdef CONFIG_MICROKERNEL
|
||||
sync->_t_sem.waiters = NULL;
|
||||
sync->_t_sem.level = sync->_t_sem.count = 0;
|
||||
sync->t_sem = (ksem_t)&sync->_t_sem;
|
||||
sync->caller_is_task = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MICROKERNEL
|
||||
|
||||
/**
|
||||
* @brief Wait for the isr to complete the synchronous call
|
||||
* Note: In a microkernel built this function will take care of the caller
|
||||
* context and thus use the right attribute to handle the synchronization.
|
||||
*
|
||||
* @param sync A pointer to a valid devic_sync_call_t
|
||||
*/
|
||||
static inline void synchronous_call_wait(device_sync_call_t *sync)
|
||||
{
|
||||
if ((sys_execution_context_type_get() == NANO_CTX_TASK) &&
|
||||
(task_priority_get() < CONFIG_NUM_TASK_PRIORITIES - 1)) {
|
||||
sync->caller_is_task = true;
|
||||
task_sem_take_wait(sync->t_sem);
|
||||
} else {
|
||||
sync->caller_is_task = false;
|
||||
nano_sem_take_wait(sync->f_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Signal the caller about synchronization completion
|
||||
* Note: In a microkernel built this function will take care of the caller
|
||||
* context and thus use the right attribute to signale the completion.
|
||||
*
|
||||
* @param sync A pointer to a valid devic_sync_call_t
|
||||
*/
|
||||
static inline void synchronous_call_complete(device_sync_call_t *sync)
|
||||
{
|
||||
if (sync->caller_is_task) {
|
||||
task_sem_give(sync->t_sem);
|
||||
} else {
|
||||
nano_isr_sem_give(sync->f_sem);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* @brief Wait for the isr to complete the synchronous call
|
||||
* Note: It will simply wait on the internal semaphore.
|
||||
*
|
||||
* @param sync A pointer to a valid devic_sync_call_t
|
||||
*/
|
||||
static inline void synchronous_call_wait(device_sync_call_t *sync)
|
||||
{
|
||||
nano_sem_take_wait(sync->f_sem);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Signal the caller about synchronization completion
|
||||
* Note: It will simply release the internal semaphore
|
||||
*
|
||||
* @param sync A pointer to a valid devic_sync_call_t
|
||||
*/
|
||||
static inline void synchronous_call_complete(device_sync_call_t *sync)
|
||||
{
|
||||
nano_isr_sem_give(sync->f_sem);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MICROKERNEL || CONFIG_NANOKERNEL */
|
||||
|
||||
#endif /* _DEVICE_H_ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue