77 lines
1.9 KiB
C
77 lines
1.9 KiB
C
/*
|
|
* Copyright (c) 2017 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <spi.h>
|
|
#include <syscall_handler.h>
|
|
|
|
static void verify_spi_buf_array(const struct spi_buf *bufs, size_t len,
|
|
int writable, void *ssf)
|
|
{
|
|
/* Empty array, nothing to do */
|
|
if (!len) {
|
|
return;
|
|
}
|
|
|
|
/* Validate the array of struct spi_buf instances */
|
|
_SYSCALL_MEMORY_ARRAY_READ(bufs, len, sizeof(struct spi_buf));
|
|
|
|
for ( ; len; --len, ++bufs) {
|
|
/* Now for each array element, validate the memory buffers
|
|
* that they point to
|
|
*/
|
|
_SYSCALL_MEMORY(bufs->buf, bufs->len, writable);
|
|
}
|
|
}
|
|
|
|
_SYSCALL_HANDLER(spi_transceive, dev, config_p, tx_bufs, rx_bufs)
|
|
{
|
|
const struct spi_config *config = (const struct spi_config *)config_p;
|
|
|
|
_SYSCALL_MEMORY_READ(config, sizeof(*config));
|
|
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SPI);
|
|
|
|
/* ssf is implicit system call stack frame parameter, used by
|
|
* _SYSCALL_* APIs when something goes wrong.
|
|
*/
|
|
if (tx_bufs) {
|
|
const struct spi_buf_set *tx =
|
|
(const struct spi_buf_set *)tx_bufs;
|
|
|
|
_SYSCALL_MEMORY_READ(tx_bufs, sizeof(struct spi_buf_set));
|
|
verify_spi_buf_array(tx->buffers, tx->count, 0, ssf);
|
|
}
|
|
|
|
if (rx_bufs) {
|
|
const struct spi_buf_set *rx =
|
|
(const struct spi_buf_set *)rx_bufs;
|
|
|
|
_SYSCALL_MEMORY_READ(rx_bufs, sizeof(struct spi_buf_set));
|
|
verify_spi_buf_array(rx->buffers, rx->count, 1, ssf);
|
|
}
|
|
|
|
if (config->cs) {
|
|
const struct spi_cs_control *cs = config->cs;
|
|
|
|
_SYSCALL_MEMORY_READ(cs, sizeof(*cs));
|
|
if (cs->gpio_dev) {
|
|
_SYSCALL_OBJ(cs->gpio_dev, K_OBJ_DRIVER_GPIO);
|
|
}
|
|
}
|
|
|
|
return _impl_spi_transceive((struct device *)dev, config,
|
|
(const struct spi_buf_set *)tx_bufs,
|
|
(const struct spi_buf_set *)rx_bufs);
|
|
}
|
|
|
|
_SYSCALL_HANDLER(spi_release, dev, config_p)
|
|
{
|
|
const struct spi_config *config = (const struct spi_config *)config_p;
|
|
|
|
_SYSCALL_MEMORY_READ(config, sizeof(*config));
|
|
_SYSCALL_OBJ(dev, K_OBJ_DRIVER_SPI);
|
|
return _impl_spi_release((struct device *)dev, config);
|
|
}
|