Skip to content

Commit

Permalink
drivers: adc: add some missing system calls
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Andrew Boie authored and nashif committed Mar 30, 2019
1 parent 606e607 commit 02be448
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 12 deletions.
1 change: 1 addition & 0 deletions drivers/adc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 64 additions & 0 deletions drivers/adc/adc_handlers.c
Original file line number Diff line number Diff line change
@@ -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);
}
14 changes: 11 additions & 3 deletions include/adc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -366,6 +372,8 @@ static inline int adc_read_async(struct device *dev,
}
#endif /* CONFIG_ADC_ASYNC */

#include <syscalls/adc.h>

/**
* @}
*/
Expand Down
16 changes: 10 additions & 6 deletions tests/drivers/adc/adc_api/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
10 changes: 7 additions & 3 deletions tests/drivers/adc/adc_api/src/test_adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 02be448

Please sign in to comment.