drivers: adc: add some missing system calls
Setting callbacks is forbidden from user mode. Some heavier code changes will be needed to support adc_read_async(), this patch just exposes the config and read functions for now. Test case updated to run partially in user mode. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
606e607a77
commit
02be448cc4
|
@ -6,3 +6,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_NRFX_ADC adc_nrfx_adc.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_ADC_NRFX_SAADC adc_nrfx_saadc.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ADC_INTEL_QUARK_SE_C1000_SS adc_intel_quark_se_c1000_ss.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ADC_INTEL_QUARK_D2000 adc_intel_quark_d2000.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE adc_handlers.c)
|
||||
|
|
64
drivers/adc/adc_handlers.c
Normal file
64
drivers/adc/adc_handlers.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <adc.h>
|
||||
#include <syscall_handler.h>
|
||||
#include <kernel.h>
|
||||
|
||||
Z_SYSCALL_HANDLER(adc_channel_setup, dev, user_channel_cfg)
|
||||
{
|
||||
struct adc_channel_cfg channel_cfg;
|
||||
|
||||
Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, channel_setup));
|
||||
Z_OOPS(z_user_from_copy(&channel_cfg,
|
||||
(struct adc_channel_cfg *)user_channel_cfg,
|
||||
sizeof(struct adc_channel_cfg)));
|
||||
|
||||
return z_impl_adc_channel_setup((struct device *)dev, &channel_cfg);
|
||||
}
|
||||
|
||||
static bool copy_sequence(struct adc_sequence *dst,
|
||||
struct adc_sequence_options *options,
|
||||
struct adc_sequence *src)
|
||||
{
|
||||
if (z_user_from_copy(dst, src, sizeof(struct adc_sequence)) != 0) {
|
||||
printk("couldn't copy adc_sequence struct\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dst->options) {
|
||||
if (z_user_from_copy(options, dst->options,
|
||||
sizeof(struct adc_sequence_options)) != 0) {
|
||||
printk("couldn't copy adc_options struct\n");
|
||||
return false;
|
||||
}
|
||||
dst->options = options;
|
||||
}
|
||||
|
||||
if (Z_SYSCALL_MEMORY_WRITE(dst->buffer, dst->buffer_size) != 0) {
|
||||
printk("no access to buffer memory\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Z_SYSCALL_HANDLER(adc_read, dev, user_sequence)
|
||||
{
|
||||
struct adc_sequence sequence;
|
||||
struct adc_sequence_options options;
|
||||
|
||||
Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, read));
|
||||
Z_OOPS(Z_SYSCALL_VERIFY_MSG(copy_sequence(&sequence, &options,
|
||||
(struct adc_sequence *)user_sequence),
|
||||
"invalid ADC sequence"));
|
||||
if (sequence.options != NULL) {
|
||||
Z_OOPS(Z_SYSCALL_VERIFY_MSG(sequence.options->callback == NULL,
|
||||
"ADC sequence callbacks forbidden from user mode"));
|
||||
}
|
||||
|
||||
return z_impl_adc_read((struct device *)dev, &sequence);
|
||||
}
|
|
@ -306,8 +306,11 @@ struct adc_driver_api {
|
|||
* @retval 0 On success.
|
||||
* @retval -EINVAL If a parameter with an invalid value has been provided.
|
||||
*/
|
||||
static inline int adc_channel_setup(struct device *dev,
|
||||
const struct adc_channel_cfg *channel_cfg)
|
||||
__syscall int adc_channel_setup(struct device *dev,
|
||||
const struct adc_channel_cfg *channel_cfg);
|
||||
|
||||
static inline int z_impl_adc_channel_setup(struct device *dev,
|
||||
const struct adc_channel_cfg *channel_cfg)
|
||||
{
|
||||
const struct adc_driver_api *api = dev->driver_api;
|
||||
|
||||
|
@ -332,7 +335,10 @@ static inline int adc_channel_setup(struct device *dev,
|
|||
* in the buffer, but at least some of them were taken with
|
||||
* an extra delay compared to what was scheduled.
|
||||
*/
|
||||
static inline int adc_read(struct device *dev,
|
||||
__syscall int adc_read(struct device *dev,
|
||||
const struct adc_sequence *sequence);
|
||||
|
||||
static inline int z_impl_adc_read(struct device *dev,
|
||||
const struct adc_sequence *sequence)
|
||||
{
|
||||
const struct adc_driver_api *api = dev->driver_api;
|
||||
|
@ -366,6 +372,8 @@ static inline int adc_read_async(struct device *dev,
|
|||
}
|
||||
#endif /* CONFIG_ADC_ASYNC */
|
||||
|
||||
#include <syscalls/adc.h>
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -12,24 +12,28 @@
|
|||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <ztest.h>
|
||||
|
||||
extern void test_adc_sample_one_channel(void);
|
||||
extern void test_adc_sample_two_channels(void);
|
||||
extern void test_adc_asynchronous_call(void);
|
||||
extern void test_adc_sample_with_interval(void);
|
||||
extern void test_adc_repeated_samplings(void);
|
||||
extern void test_adc_invalid_request(void);
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <ztest.h>
|
||||
extern struct device *get_adc_device(void);
|
||||
|
||||
void test_main(void)
|
||||
{
|
||||
k_object_access_grant(get_adc_device(), k_current_get());
|
||||
|
||||
ztest_test_suite(adc_basic_test,
|
||||
ztest_unit_test(test_adc_sample_one_channel),
|
||||
ztest_unit_test(test_adc_sample_two_channels),
|
||||
ztest_user_unit_test(test_adc_sample_one_channel),
|
||||
ztest_user_unit_test(test_adc_sample_two_channels),
|
||||
ztest_unit_test(test_adc_asynchronous_call),
|
||||
ztest_unit_test(test_adc_sample_with_interval),
|
||||
ztest_unit_test(test_adc_repeated_samplings),
|
||||
ztest_unit_test(test_adc_invalid_request));
|
||||
ztest_user_unit_test(test_adc_invalid_request));
|
||||
ztest_run_test_suite(adc_basic_test);
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@
|
|||
#endif
|
||||
|
||||
#define BUFFER_SIZE 6
|
||||
static s16_t m_sample_buffer[BUFFER_SIZE];
|
||||
static ZTEST_BMEM s16_t m_sample_buffer[BUFFER_SIZE];
|
||||
|
||||
static const struct adc_channel_cfg m_1st_channel_cfg = {
|
||||
.gain = ADC_GAIN,
|
||||
|
@ -149,6 +149,11 @@ static const struct adc_channel_cfg m_2nd_channel_cfg = {
|
|||
};
|
||||
#endif /* defined(ADC_2ND_CHANNEL_ID) */
|
||||
|
||||
struct device *get_adc_device(void)
|
||||
{
|
||||
return device_get_binding(ADC_DEVICE_NAME);
|
||||
}
|
||||
|
||||
static struct device *init_adc(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -288,7 +293,6 @@ static int test_task_asynchronous_call(void)
|
|||
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
|
||||
K_POLL_MODE_NOTIFY_ONLY,
|
||||
&async_sig);
|
||||
|
||||
struct device *adc_dev = init_adc();
|
||||
|
||||
if (!adc_dev) {
|
||||
|
@ -472,7 +476,7 @@ static int test_task_invalid_request(void)
|
|||
ret = adc_read(adc_dev, &sequence);
|
||||
zassert_not_equal(ret, 0, "adc_read() unexpectedly succeeded");
|
||||
|
||||
#if defined(CONFIG_ADC_ASYNC)
|
||||
#if defined(CONFIG_ADC_ASYNC) && !defined(CONFIG_USERSPACE)
|
||||
ret = adc_read_async(adc_dev, &sequence, &async_sig);
|
||||
zassert_not_equal(ret, 0, "adc_read_async() unexpectedly succeeded");
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue