From 02be448cc47046c453cdee61e7da6381732daefa Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Thu, 28 Mar 2019 16:50:39 -0700 Subject: [PATCH] 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 --- drivers/adc/CMakeLists.txt | 1 + drivers/adc/adc_handlers.c | 64 ++++++++++++++++++++++++ include/adc.h | 14 ++++-- tests/drivers/adc/adc_api/src/main.c | 16 +++--- tests/drivers/adc/adc_api/src/test_adc.c | 10 ++-- 5 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 drivers/adc/adc_handlers.c diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index b33f726e2f1a9c..fb389ada301717 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -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) diff --git a/drivers/adc/adc_handlers.c b/drivers/adc/adc_handlers.c new file mode 100644 index 00000000000000..e85f3fbc45cf4c --- /dev/null +++ b/drivers/adc/adc_handlers.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +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); +} diff --git a/include/adc.h b/include/adc.h index fb42a4d75177f7..0517b8193303b3 100644 --- a/include/adc.h +++ b/include/adc.h @@ -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 + /** * @} */ diff --git a/tests/drivers/adc/adc_api/src/main.c b/tests/drivers/adc/adc_api/src/main.c index b33247e9524f54..cdd95d8fe70917 100644 --- a/tests/drivers/adc/adc_api/src/main.c +++ b/tests/drivers/adc/adc_api/src/main.c @@ -12,24 +12,28 @@ * @} */ + +#include +#include + 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 -#include +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); } diff --git a/tests/drivers/adc/adc_api/src/test_adc.c b/tests/drivers/adc/adc_api/src/test_adc.c index 8a81c269682387..75cda17457594b 100644 --- a/tests/drivers/adc/adc_api/src/test_adc.c +++ b/tests/drivers/adc/adc_api/src/test_adc.c @@ -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