ChibiOS/os/sb/vio/sbvio_uart.c

245 lines
6.9 KiB
C

/*
ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio.
This file is part of ChibiOS.
ChibiOS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 3 of the License.
ChibiOS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file sb/vhal/sbvio_uart.c
* @brief ARM SandBox host Virtual UART code.
*
* @addtogroup ARM_SANDBOX_HOST_VIO_UART
* @{
*/
#include "sb.h"
#if (VIO_CFG_ENABLE_UART == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Module local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Module exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local types. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Module local functions. */
/*===========================================================================*/
static void vuart_cb(void *ip) {
hal_sio_driver_c *siop = (hal_sio_driver_c *)ip;
const vio_uart_unit_t *unitp = (const vio_uart_unit_t *)drvGetArgumentX(siop);
sbVRQTriggerFromISR(unitp->vrqsb, unitp->vrqn);
}
/*===========================================================================*/
/* Module exported functions. */
/*===========================================================================*/
void sb_sysc_vio_uart(struct port_extctx *ectxp) {
sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p;
uint32_t sub = VIO_CALL_SUBCODE(ectxp->r0);
uint32_t unit = VIO_CALL_UNIT(ectxp->r0);
ectxp->r0 = (uint32_t)CH_RET_INNER_ERROR;
const vio_uart_unit_t *unitp;
if (unit >= sbp->config->vioconf->uarts->n) {
ectxp->r0 = (uint32_t)HAL_RET_NO_RESOURCE;
return;
}
unitp = &sbp->config->vioconf->uarts->units[unit];
switch (sub) {
case SB_VUART_INIT:
{
msg_t msg;
/* Associating this virtual UART to the SIO driver.*/
drvSetArgumentX(unitp->siop, (void *)unitp);
msg = drvStart(unitp->siop);
if (msg == HAL_RET_SUCCESS) {
/* Starting with disabled events, enabling the callback.*/
sioWriteEnableFlags(unitp->siop, SIO_EV_NONE);
drvSetCallbackX(unitp->siop, vuart_cb);
}
ectxp->r0 = (uint32_t)msg;
break;
}
case SB_VUART_DEINIT:
{
drvStop(unitp->siop);
ectxp->r0 = (uint32_t)HAL_RET_SUCCESS;
break;
}
default:
ectxp->r0 = (uint32_t)CH_RET_ENOSYS;
break;
}
}
void sb_fastc_vio_uart(struct port_extctx *ectxp) {
sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p;
uint32_t sub = VIO_CALL_SUBCODE(ectxp->r0);
uint32_t unit = VIO_CALL_UNIT(ectxp->r0);
const vio_uart_unit_t *unitp;
/* Returned value in case of error or illegal sub-code.*/
ectxp->r0 = (uint32_t)-1;
if (unit >= sbp->config->vioconf->uarts->n) {
return;
}
unitp = &sbp->config->vioconf->uarts->units[unit];
/* We don't want assertion or errors to be caused in host, making sure
all functions are called in the proper state.*/
if (unitp->siop->state != HAL_DRV_STATE_READY) {
return;
}
switch (sub) {
case SB_VUART_SETCFG:
{
uint32_t conf = ectxp->r1;
const vio_uart_config_t *confp;
/* Check on configuration index.*/
if (conf >= sbp->config->vioconf->uarts->n) {
ectxp->r0 = (uint32_t)HAL_RET_CONFIG_ERROR;
return;
}
/* Specified VUART configuration.*/
confp = &sbp->config->vioconf->uartconfs->cfgs[conf];
ectxp->r0 = (uint32_t)drvConfigureX(unitp->siop, confp->siocfgp);
break;
}
case SB_VUART_ISRXE:
{
ectxp->r0 = (uint32_t)sioIsRXEmptyX(unitp->siop);
break;
}
case SB_VUART_ISRXI:
{
ectxp->r0 = (uint32_t)sioIsRXIdleX(unitp->siop);
break;
}
case SB_VUART_ISTXF:
{
ectxp->r0 = (uint32_t)sioIsTXFullX(unitp->siop);
break;
}
case SB_VUART_ISTXO:
{
ectxp->r0 = (uint32_t)sioIsTXOngoingX(unitp->siop);
break;
}
case SB_VUART_HASERR:
{
ectxp->r0 = (uint32_t)sioHasRXErrorsX(unitp->siop);
break;
}
case SB_VUART_READ:
{
uint8_t *buffer = (uint8_t *)ectxp->r1;
size_t n = (size_t)ectxp->r2;
if (!sb_is_valid_write_range(sbp, buffer, n)) {
ectxp->r0 = (uint32_t)0;
/* TODO enforce fault instead.*/
break;
}
ectxp->r0 = sioAsyncReadX(unitp->siop, buffer, n);
break;
}
case SB_VUART_WRITE:
{
const uint8_t *buffer = (const uint8_t *)ectxp->r1;
size_t n = (size_t)ectxp->r2;
if (!sb_is_valid_read_range(sbp, buffer, n)) {
ectxp->r0 = (uint32_t)0;
/* TODO enforce fault instead.*/
break;
}
ectxp->r0 = sioAsyncWriteX(unitp->siop, buffer, n);
break;
}
case SB_VUART_GET:
{
ectxp->r0 = sioGetX(unitp->siop);
break;
}
case SB_VUART_PUT:
{
sioPutX(unitp->siop, (uint_fast16_t)ectxp->r1);
ectxp->r0 = (uint32_t)0;
break;
}
case SB_VUART_WREN:
{
sioWriteEnableFlagsX(unitp->siop, (sioevents_t)ectxp->r1);
ectxp->r0 = (uint32_t)0;
break;
}
case SB_VUART_GCERR:
{
ectxp->r0 = (uint32_t)sioGetAndClearErrorsX(unitp->siop);
break;
}
case SB_VUART_GCEVT:
{
ectxp->r0 = (uint32_t)sioGetAndClearEventsX(unitp->siop,
(sioevents_t)ectxp->r1);
break;
}
case SB_VUART_GEVT:
{
ectxp->r0 = (uint32_t)sioGetEventsX(unitp->siop);
break;
}
case SB_VUART_CTL:
/* falls through */
default:
/* Silently ignored.*/
break;
}
}
#endif /* VIO_CFG_ENABLE_UART == TRUE */
/** @} */