kendryte-freertos-sdk/lib/freertos/kernel/devices.cpp

977 lines
28 KiB
C++

/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "devices.h"
#include "FreeRTOS.h"
#include "device_priv.h"
#include "filesystem.h"
#include "hal.h"
#include "kernel/driver.hpp"
#include <atomic.h>
#include <plic.h>
#include <semphr.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysctl.h>
#include <uarths.h>
using namespace sys;
#define MAX_HANDLES 256
#define HANDLE_OFFSET 256
#define MAX_CUSTOM_DRIVERS 32
#define DEFINE_INSTALL_DRIVER(type) \
static void install_##type##_drivers() \
{ \
auto head = g_##type##_drivers; \
while (head->name) \
{ \
auto &driver = head->driver_ptr; \
driver->install(); \
head++; \
} \
}
#define CATCH_ALL \
catch (errno_exception & e) \
{ \
errno = e.code(); \
return -1; \
}
typedef struct
{
object_accessor<object_access> object;
} _file;
static _file *handles_[MAX_HANDLES];
static driver_registry_t g_custom_drivers[MAX_CUSTOM_DRIVERS];
static const char dummy_driver_name[] = "";
uintptr_t fft_file_;
uintptr_t aes_file_;
uintptr_t sha256_file_;
extern UBaseType_t uxCPUClockRate;
DEFINE_INSTALL_DRIVER(hal);
DEFINE_INSTALL_DRIVER(dma);
DEFINE_INSTALL_DRIVER(system);
object_accessor<driver> find_free_driver(driver_registry_t *registry, const char *name)
{
auto head = registry;
while (head->name)
{
if (strcmp(name, head->name) == 0)
{
auto &driver = head->driver_ptr;
try
{
return make_accessor(driver);
}
catch (...)
{
return {};
}
}
head++;
}
return {};
}
object_accessor<driver> find_free_dynamic_driver(const char *name)
{
size_t i = 0;
driver_registry_t *head = g_custom_drivers;
for (i = 0; i < MAX_CUSTOM_DRIVERS; i++, head++)
{
if (head->name && strcmp(name, head->name) == 0)
{
auto &driver = head->driver_ptr;
try
{
return make_accessor(driver);
}
catch (...)
{
return {};
}
}
}
return {};
}
void install_drivers()
{
install_system_drivers();
fft_file_ = io_open("/dev/fft0");
aes_file_ = io_open("/dev/aes0");
sha256_file_ = io_open("/dev/sha256");
}
static _file *io_alloc_file(object_accessor<object_access> object)
{
if (object)
{
_file *file = new (std::nothrow) _file;
if (!file)
return nullptr;
file->object = std::move(object);
return file;
}
return nullptr;
}
static _file *io_alloc_file(object_ptr<object_access> object)
{
if (object)
return io_alloc_file(make_accessor(object));
return nullptr;
}
static _file *io_open_reg(driver_registry_t *registry, const char *name, _file **file)
{
auto driver = find_free_driver(registry, name);
if (driver)
{
_file *ret = io_alloc_file(std::move(driver));
*file = ret;
return ret;
}
return nullptr;
}
static _file *io_open_dynamic(const char *name, _file **file)
{
auto driver = find_free_dynamic_driver(name);
if (driver)
{
_file *ret = io_alloc_file(std::move(driver));
*file = ret;
return ret;
}
return nullptr;
}
/* Generic IO Implementation Helper Macros */
#define DEFINE_READ_PROXY(t) \
if (auto f = rfile->object.as<t>()) \
{ \
return (int)f->read({ buffer, std::ptrdiff_t(len) }); \
}
#define DEFINE_WRITE_PROXY(t) \
if (auto f = rfile->object.as<t>()) \
{ \
return (int)f->write({ buffer, std::ptrdiff_t(len) }); \
}
#define DEFINE_CONTROL_PROXY(t) \
if (auto t = rfile->object.as<t##_driver>()) \
{ \
return (int)t->control(control_code, { write_buffer, std::ptrdiff_t(write_len) }, { read_buffer, std::ptrdiff_t(read_len) }); \
}
static void dma_add_free();
int io_read(handle_t file, uint8_t *buffer, size_t len)
{
try
{
configASSERT(file >= HANDLE_OFFSET);
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET];
/* clang-format off */
DEFINE_READ_PROXY(uart_driver)
else DEFINE_READ_PROXY(i2c_device_driver)
else DEFINE_READ_PROXY(spi_device_driver)
else DEFINE_READ_PROXY(filesystem_file)
else DEFINE_READ_PROXY(network_socket)
else
{
return -1;
}
/* clang-format on */
}
CATCH_ALL;
}
static void io_free(_file *file)
{
if (file)
{
if (file->object.is<dma_driver>())
dma_add_free();
delete file;
}
}
static handle_t io_alloc_handle(_file *file)
{
if (file)
{
size_t i, j;
for (i = 0; i < 2; i++)
{
for (j = 0; j < MAX_HANDLES; j++)
{
if (atomic_cas(handles_ + j, 0, file) == 0)
return j + HANDLE_OFFSET;
}
}
io_free(file);
return 0;
}
return 0;
}
handle_t io_open(const char *name)
{
_file *file = 0;
if (io_open_reg(g_system_drivers, name, &file))
{
}
else if (io_open_reg(g_hal_drivers, name, &file))
{
}
else if (io_open_dynamic(name, &file))
{
}
if (file)
return io_alloc_handle(file);
configASSERT(file);
return 0;
}
int io_close(handle_t file)
{
if (file)
{
configASSERT(file >= HANDLE_OFFSET);
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET];
io_free(rfile);
atomic_set(handles_ + file - HANDLE_OFFSET, 0);
}
return 0;
}
int io_write(handle_t file, const uint8_t *buffer, size_t len)
{
try
{
configASSERT(file >= HANDLE_OFFSET);
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET];
/* clang-format off */
DEFINE_WRITE_PROXY(uart_driver)
else DEFINE_WRITE_PROXY(i2c_device_driver)
else DEFINE_WRITE_PROXY(spi_device_driver)
else DEFINE_WRITE_PROXY(filesystem_file)
else DEFINE_WRITE_PROXY(network_socket)
else
{
return -1;
}
/* clang-format on */
}
CATCH_ALL;
}
int io_control(handle_t file, uint32_t control_code, const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len)
{
try
{
configASSERT(file >= HANDLE_OFFSET);
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET];
DEFINE_CONTROL_PROXY(custom)
else
{
return -1;
}
}
CATCH_ALL;
}
/* Device IO Implementation Helper Macros */
#define COMMON_ENTRY(t) \
configASSERT(file >= HANDLE_OFFSET); \
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET]; \
configASSERT(rfile && rfile->object.is<t##_driver>()); \
auto t = rfile->object.as<t##_driver>();
#define COMMON_ENTRY_FILE(file, t) \
configASSERT(file >= HANDLE_OFFSET); \
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET]; \
configASSERT(rfile && rfile->object.is<t##_driver>()); \
auto t = rfile->object.as<t##_driver>();
/* UART */
void uart_config(handle_t file, uint32_t baud_rate, uint32_t databits, uart_stopbits_t stopbits, uart_parity_t parity)
{
COMMON_ENTRY(uart);
uart->config(baud_rate, databits, stopbits, parity);
}
/* GPIO */
uint32_t gpio_get_pin_count(handle_t file)
{
COMMON_ENTRY(gpio);
return gpio->get_pin_count();
}
void gpio_set_drive_mode(handle_t file, uint32_t pin, gpio_drive_mode_t mode)
{
COMMON_ENTRY(gpio);
gpio->set_drive_mode(pin, mode);
}
void gpio_set_pin_edge(handle_t file, uint32_t pin, gpio_pin_edge_t edge)
{
COMMON_ENTRY(gpio);
gpio->set_pin_edge(pin, edge);
}
void gpio_set_on_changed(handle_t file, uint32_t pin, gpio_on_changed_t callback, void *userdata)
{
COMMON_ENTRY(gpio);
gpio->set_on_changed(pin, callback, userdata);
}
gpio_pin_value_t gpio_get_pin_value(handle_t file, uint32_t pin)
{
COMMON_ENTRY(gpio);
return gpio->get_pin_value(pin);
}
void gpio_set_pin_value(handle_t file, uint32_t pin, gpio_pin_value_t value)
{
COMMON_ENTRY(gpio);
gpio->set_pin_value(pin, value);
}
/* I2C */
handle_t i2c_get_device(handle_t file, uint32_t slave_address, uint32_t address_width)
{
COMMON_ENTRY(i2c);
auto driver = i2c->get_device(slave_address, address_width);
return io_alloc_handle(io_alloc_file(driver));
}
double i2c_dev_set_clock_rate(handle_t file, double clock_rate)
{
COMMON_ENTRY(i2c_device);
return i2c_device->set_clock_rate(clock_rate);
}
int i2c_dev_transfer_sequential(handle_t file, const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len)
{
COMMON_ENTRY(i2c_device);
return i2c_device->transfer_sequential({ write_buffer, std::ptrdiff_t(write_len) }, { read_buffer, std::ptrdiff_t(read_len) });
}
void i2c_config_as_slave(handle_t file, uint32_t slave_address, uint32_t address_width, i2c_slave_handler_t *handler)
{
COMMON_ENTRY(i2c);
i2c->config_as_slave(slave_address, address_width, *handler);
}
double i2c_slave_set_clock_rate(handle_t file, double clock_rate)
{
COMMON_ENTRY(i2c);
return i2c->slave_set_clock_rate(clock_rate);
}
/* I2S */
void i2s_config_as_render(handle_t file, const audio_format_t *format, size_t delay_ms, i2s_align_mode_t align_mode, size_t channels_mask)
{
COMMON_ENTRY(i2s);
i2s->config_as_render(*format, delay_ms, align_mode, channels_mask);
}
void i2s_config_as_capture(handle_t file, const audio_format_t *format, size_t delay_ms, i2s_align_mode_t align_mode, size_t channels_mask)
{
COMMON_ENTRY(i2s);
i2s->config_as_capture(*format, delay_ms, align_mode, channels_mask);
}
void i2s_get_buffer(handle_t file, uint8_t **buffer, size_t *frames)
{
COMMON_ENTRY(i2s);
gsl::span<uint8_t> span;
i2s->get_buffer(span, *frames);
*buffer = span.data();
}
void i2s_release_buffer(handle_t file, size_t frames)
{
COMMON_ENTRY(i2s);
i2s->release_buffer(frames);
}
void i2s_start(handle_t file)
{
COMMON_ENTRY(i2s);
i2s->start();
}
void i2s_stop(handle_t file)
{
COMMON_ENTRY(i2s);
i2s->stop();
}
/* SPI */
void spi_slave_config(handle_t file, uint32_t data_bit_length, spi_slave_handler_t *handler)
{
COMMON_ENTRY(spi);
spi->slave_config(data_bit_length, *handler);
}
handle_t spi_get_device(handle_t file, spi_mode_t mode, spi_frame_format_t frame_format, uint32_t chip_select_mask, uint32_t data_bit_length)
{
COMMON_ENTRY(spi);
auto driver = spi->get_device(mode, frame_format, chip_select_mask, data_bit_length);
return io_alloc_handle(io_alloc_file(driver));
}
void spi_dev_config_non_standard(handle_t file, uint32_t instruction_length, uint32_t address_length, uint32_t wait_cycles, spi_inst_addr_trans_mode_t trans_mode)
{
COMMON_ENTRY(spi_device);
spi_device->config_non_standard(instruction_length, address_length, wait_cycles, trans_mode);
}
double spi_dev_set_clock_rate(handle_t file, double clock_rate)
{
COMMON_ENTRY(spi_device);
return spi_device->set_clock_rate(clock_rate);
}
int spi_dev_transfer_full_duplex(handle_t file, const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len)
{
COMMON_ENTRY(spi_device);
return spi_device->transfer_full_duplex({ write_buffer, std::ptrdiff_t(write_len) }, { read_buffer, std::ptrdiff_t(read_len) });
}
int spi_dev_transfer_sequential(handle_t file, const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len)
{
COMMON_ENTRY(spi_device);
return spi_device->transfer_sequential({ write_buffer, std::ptrdiff_t(write_len) }, { read_buffer, std::ptrdiff_t(read_len) });
}
void spi_dev_fill(handle_t file, uint32_t instruction, uint32_t address, uint32_t value, size_t count)
{
COMMON_ENTRY(spi_device);
return spi_device->fill(instruction, address, value, count);
}
/* DVP */
void dvp_config(handle_t file, uint32_t width, uint32_t height, bool auto_enable)
{
COMMON_ENTRY(dvp);
dvp->config(width, height, auto_enable);
}
void dvp_enable_frame(handle_t file)
{
COMMON_ENTRY(dvp);
dvp->enable_frame();
}
uint32_t dvp_get_output_num(handle_t file)
{
COMMON_ENTRY(dvp);
return dvp->get_output_num();
}
void dvp_set_signal(handle_t file, dvp_signal_type_t type, bool value)
{
COMMON_ENTRY(dvp);
dvp->set_signal(type, value);
}
void dvp_set_output_enable(handle_t file, uint32_t index, bool enable)
{
COMMON_ENTRY(dvp);
dvp->set_output_enable(index, enable);
}
void dvp_set_output_attributes(handle_t file, uint32_t index, video_format_t format, void *output_buffer)
{
COMMON_ENTRY(dvp);
dvp->set_output_attributes(index, format, output_buffer);
}
void dvp_set_frame_event_enable(handle_t file, dvp_frame_event_t event, bool enable)
{
COMMON_ENTRY(dvp);
dvp->set_frame_event_enable(event, enable);
}
void dvp_set_on_frame_event(handle_t file, dvp_on_frame_event_t handler, void *userdata)
{
COMMON_ENTRY(dvp);
dvp->set_on_frame_event(handler, userdata);
}
double dvp_xclk_set_clock_rate(handle_t file, double clock_rate)
{
COMMON_ENTRY(dvp);
return dvp->xclk_set_clock_rate(clock_rate);
}
/* SSCB */
handle_t sccb_get_device(handle_t file, uint32_t slave_address, uint32_t reg_address_width)
{
COMMON_ENTRY(sccb);
auto driver = sccb->get_device(slave_address, reg_address_width);
return io_alloc_handle(io_alloc_file(driver));
}
uint8_t sccb_dev_read_byte(handle_t file, uint16_t reg_address)
{
COMMON_ENTRY(sccb_device);
return sccb_device->read_byte(reg_address);
}
void sccb_dev_write_byte(handle_t file, uint16_t reg_address, uint8_t value)
{
COMMON_ENTRY(sccb_device);
sccb_device->write_byte(reg_address, value);
}
/* FFT */
void fft_complex_uint16(uint16_t shift, fft_direction_t direction, const uint64_t *input, size_t point_num, uint64_t *output)
{
COMMON_ENTRY_FILE(fft_file_, fft);
fft->complex_uint16(shift, direction, input, point_num, output);
}
/* AES */
void aes_ecb128_hard_decrypt(const uint8_t *input_key, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_ecb128_hard_decrypt({ input_key, 16 }, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_ecb128_hard_encrypt(const uint8_t *input_key, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_ecb128_hard_encrypt({ input_key, 16 }, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_ecb192_hard_decrypt(const uint8_t *input_key, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_ecb192_hard_decrypt({ input_key, 24 }, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_ecb192_hard_encrypt(const uint8_t *input_key, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_ecb192_hard_encrypt({ input_key, 24 }, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_ecb256_hard_decrypt(const uint8_t *input_key, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_ecb256_hard_decrypt({ input_key, 32 }, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_ecb256_hard_encrypt(const uint8_t *input_key, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_ecb256_hard_encrypt({ input_key, 32 }, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_cbc128_hard_decrypt(cbc_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_cbc128_hard_decrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_cbc128_hard_encrypt(cbc_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_cbc128_hard_encrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_cbc192_hard_decrypt(cbc_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_cbc192_hard_decrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_cbc192_hard_encrypt(cbc_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_cbc192_hard_encrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_cbc256_hard_decrypt(cbc_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_cbc256_hard_decrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_cbc256_hard_encrypt(cbc_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_cbc256_hard_encrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) });
}
void aes_gcm128_hard_decrypt(gcm_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_gcm128_hard_decrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) }, { gcm_tag, 16 });
}
void aes_gcm128_hard_encrypt(gcm_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_gcm128_hard_encrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) }, { gcm_tag, 16 });
}
void aes_gcm192_hard_decrypt(gcm_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_gcm192_hard_decrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) }, { gcm_tag, 16 });
}
void aes_gcm192_hard_encrypt(gcm_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_gcm192_hard_encrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) }, { gcm_tag, 16 });
}
void aes_gcm256_hard_decrypt(gcm_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_gcm256_hard_decrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) }, { gcm_tag, 16 });
}
void aes_gcm256_hard_encrypt(gcm_context_t *context, const uint8_t *input_data, size_t input_len, uint8_t *output_data, uint8_t *gcm_tag)
{
COMMON_ENTRY_FILE(aes_file_, aes);
aes->aes_gcm256_hard_encrypt(*context, { input_data, std::ptrdiff_t(input_len) }, { output_data, std::ptrdiff_t(input_len) }, { gcm_tag, 16 });
}
/* SHA */
void sha256_hard_calculate(const uint8_t *input, size_t input_len, uint8_t *output)
{
COMMON_ENTRY_FILE(sha256_file_, sha256);
sha256->sha256_hard_calculate({ input, std::ptrdiff_t(input_len) }, { output, 32 });
}
/* TIMER */
size_t timer_set_interval(handle_t file, size_t nanoseconds)
{
COMMON_ENTRY(timer);
return timer->set_interval(nanoseconds);
}
void timer_set_on_tick(handle_t file, timer_on_tick_t on_tick, void *ontick_data)
{
COMMON_ENTRY(timer);
timer->set_on_tick(on_tick, ontick_data);
}
void timer_set_enable(handle_t file, bool enable)
{
COMMON_ENTRY(timer);
timer->set_enable(enable);
}
/* PWM */
uint32_t pwm_get_pin_count(handle_t file)
{
COMMON_ENTRY(pwm);
return pwm->get_pin_count();
}
double pwm_set_frequency(handle_t file, double frequency)
{
COMMON_ENTRY(pwm);
return pwm->set_frequency(frequency);
}
double pwm_set_active_duty_cycle_percentage(handle_t file, uint32_t pin, double duty_cycle_percentage)
{
COMMON_ENTRY(pwm);
return pwm->set_active_duty_cycle_percentage(pin, duty_cycle_percentage);
}
void pwm_set_enable(handle_t file, uint32_t pin, bool enable)
{
COMMON_ENTRY(pwm);
pwm->set_enable(pin, enable);
}
/* WDT */
void wdt_set_response_mode(handle_t file, wdt_response_mode_t mode)
{
COMMON_ENTRY(wdt);
wdt->set_response_mode(mode);
}
size_t wdt_set_timeout(handle_t file, size_t nanoseconds)
{
COMMON_ENTRY(wdt);
return wdt->set_timeout(nanoseconds);
}
void wdt_set_on_timeout(handle_t file, wdt_on_timeout_t handler, void *userdata)
{
COMMON_ENTRY(wdt);
wdt->set_on_timeout(handler, userdata);
}
void wdt_restart_counter(handle_t file)
{
COMMON_ENTRY(wdt);
wdt->restart_counter();
}
void wdt_set_enable(handle_t file, bool enable)
{
COMMON_ENTRY(wdt);
wdt->set_enable(enable);
}
/* RTC */
void rtc_get_datetime(handle_t file, struct tm *datetime)
{
COMMON_ENTRY(rtc);
rtc->get_datetime(*datetime);
}
void rtc_set_datetime(handle_t file, const struct tm *datetime)
{
COMMON_ENTRY(rtc);
rtc->set_datetime(*datetime);
}
/* HAL */
static uintptr_t pic_file_;
typedef struct
{
pic_irq_handler_t pic_callbacks[IRQN_MAX];
void *callback_userdata[IRQN_MAX];
} pic_context_t;
static pic_context_t pic_context_;
static SemaphoreHandle_t dma_free_;
static void init_dma_system()
{
size_t count = 0;
driver_registry_t *head = g_dma_drivers;
while (head->name)
{
count++;
head++;
}
dma_free_ = xSemaphoreCreateCounting(count, count);
}
void install_hal()
{
uxCPUClockRate = sysctl_clock_get_freq(SYSCTL_CLOCK_CPU);
install_hal_drivers();
pic_file_ = io_open("/dev/pic0");
configASSERT(pic_file_);
install_dma_drivers();
init_dma_system();
}
/* PIC */
void pic_set_irq_enable(uint32_t irq, bool enable)
{
COMMON_ENTRY_FILE(pic_file_, pic);
pic->set_irq_enable(irq, enable);
}
void pic_set_irq_priority(uint32_t irq, uint32_t priority)
{
COMMON_ENTRY_FILE(pic_file_, pic);
pic->set_irq_priority(irq, priority);
}
void pic_set_irq_handler(uint32_t irq, pic_irq_handler_t handler, void *userdata)
{
atomic_set(pic_context_.callback_userdata + irq, userdata);
pic_context_.pic_callbacks[irq] = handler;
}
void sys::kernel_iface_pic_on_irq(uint32_t irq)
{
pic_irq_handler_t handler = pic_context_.pic_callbacks[irq];
if (handler)
handler(pic_context_.callback_userdata[irq]);
}
/* DMA */
handle_t dma_open_free()
{
configASSERT(xSemaphoreTake(dma_free_, portMAX_DELAY) == pdTRUE);
driver_registry_t *head = g_dma_drivers;
object_accessor<driver> dma;
while (head->name)
{
auto &driver = head->driver_ptr;
try
{
dma = make_accessor(driver);
break;
}
catch (...)
{
head++;
}
}
configASSERT(dma);
uintptr_t handle = io_alloc_handle(io_alloc_file(std::move(dma)));
return handle;
}
void dma_close(handle_t file)
{
io_close(file);
}
static void dma_add_free()
{
xSemaphoreGive(dma_free_);
}
void dma_set_request_source(handle_t file, uint32_t request)
{
COMMON_ENTRY(dma);
dma->set_select_request(request);
}
void dma_transmit_async(handle_t file, const volatile void *src, volatile void *dest, bool src_inc, bool dest_inc, size_t element_size, size_t count, size_t burst_size, SemaphoreHandle_t completion_event)
{
COMMON_ENTRY(dma);
dma->transmit_async(src, dest, src_inc, dest_inc, element_size, count, burst_size, completion_event);
}
void dma_transmit(handle_t file, const volatile void *src, volatile void *dest, bool src_inc, bool dest_inc, size_t element_size, size_t count, size_t burst_size)
{
SemaphoreHandle_t event = xSemaphoreCreateBinary();
dma_transmit_async(file, src, dest, src_inc, dest_inc, element_size, count, burst_size, event);
configASSERT(xSemaphoreTake(event, portMAX_DELAY) == pdTRUE);
vSemaphoreDelete(event);
}
void dma_loop_async(handle_t file, const volatile void **srcs, size_t src_num, volatile void **dests, size_t dest_num, bool src_inc, bool dest_inc, size_t element_size, size_t count, size_t burst_size, dma_stage_completion_handler_t stage_completion_handler, void *stage_completion_handler_data, SemaphoreHandle_t completion_event, int *stop_signal)
{
COMMON_ENTRY(dma);
dma->loop_async(srcs, src_num, dests, dest_num, src_inc, dest_inc, element_size, count, burst_size, stage_completion_handler, stage_completion_handler_data, completion_event, stop_signal);
}
/* System */
driver_registry_t *sys::system_install_driver(const char *name, object_ptr<driver> driver)
{
size_t i = 0;
driver_registry_t *head = g_custom_drivers;
for (i = 0; i < MAX_CUSTOM_DRIVERS; i++, head++)
{
if (!head->name)
{
head->name = name ? strdup(name) : dummy_driver_name;
head->driver_ptr = driver;
driver->install();
return head;
}
}
configASSERT(!"Max custom drivers exceeded.");
return nullptr;
}
object_accessor<driver> sys::system_open_driver(const char *name)
{
auto driver = find_free_driver(g_system_drivers, name);
if (!driver)
driver = find_free_driver(g_hal_drivers, name);
if (!driver)
driver = find_free_dynamic_driver(name);
if (!driver)
throw std::runtime_error("driver is not found.");
return driver;
}
handle_t sys::system_alloc_handle(object_accessor<object_access> object)
{
return io_alloc_handle(io_alloc_file(std::move(object)));
}
object_accessor<object_access> &sys::system_handle_to_object(handle_t file)
{
if (file < HANDLE_OFFSET)
throw std::invalid_argument("Invalid handle.");
_file *rfile = (_file *)handles_[file - HANDLE_OFFSET];
configASSERT(rfile);
return rfile->object;
}
uint32_t system_set_cpu_frequency(uint32_t frequency)
{
uint32_t divider = (sysctl->clk_sel0.aclk_divider_sel + 1) * 2;
uint32_t result = sysctl_pll_set_freq(SYSCTL_PLL0, divider * frequency) / divider;
uxCPUClockRate = result;
uarths_init();
return result;
}