/**************************************************************************** * drivers/serial/uart_hostfs.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you 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. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define UART_WDOG_DELAY USEC2TICK(CONFIG_UART_HOSTFS_DELAY_USEC) /**************************************************************************** * Private Types ****************************************************************************/ struct uart_hostfs_priv_s { int fd; bool rxint; struct wdog_s wdog; }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static int uart_hostfs_setup(FAR struct uart_dev_s *dev); static void uart_hostfs_shutdown(FAR struct uart_dev_s *dev); static int uart_hostfs_attach(FAR struct uart_dev_s *dev); static void uart_hostfs_detach(FAR struct uart_dev_s *dev); static int uart_hostfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static void uart_hostfs_rxint(FAR struct uart_dev_s *dev, bool enable); static bool uart_hostfs_rxavailable(FAR struct uart_dev_s *dev); #ifdef CONFIG_SERIAL_IFLOWCONTROL static bool uart_hostfs_rxflowcontrol(FAR struct uart_dev_s *dev, unsigned int nbuffered, bool upper); #endif static void uart_hostfs_dmatxavail(FAR struct uart_dev_s *dev); static void uart_hostfs_dmasend(FAR struct uart_dev_s *dev); static void uart_hostfs_dmarxfree(FAR struct uart_dev_s *dev); static void uart_hostfs_dmareceive(FAR struct uart_dev_s *dev); static void uart_hostfs_send(FAR struct uart_dev_s *dev, int ch); static void uart_hostfs_txint(FAR struct uart_dev_s *dev, bool enable); static bool uart_hostfs_txready(FAR struct uart_dev_s *dev); static bool uart_hostfs_txempty(FAR struct uart_dev_s *dev); /**************************************************************************** * Private Data ****************************************************************************/ static const struct uart_ops_s g_uart_hostfs_ops = { .setup = uart_hostfs_setup, .shutdown = uart_hostfs_shutdown, .attach = uart_hostfs_attach, .detach = uart_hostfs_detach, .ioctl = uart_hostfs_ioctl, .rxint = uart_hostfs_rxint, .rxavailable = uart_hostfs_rxavailable, #ifdef CONFIG_SERIAL_IFLOWCONTROL .rxflowcontrol = uart_hostfs_rxflowcontrol, #endif .dmatxavail = uart_hostfs_dmatxavail, .dmasend = uart_hostfs_dmasend, .dmarxfree = uart_hostfs_dmarxfree, .dmareceive = uart_hostfs_dmareceive, .send = uart_hostfs_send, .txint = uart_hostfs_txint, .txready = uart_hostfs_txready, .txempty = uart_hostfs_txempty, }; static char g_uart_hostfs_rxbuf[CONFIG_UART_HOSTFS_RXBUFSIZE]; static char g_uart_hostfs_txbuf[CONFIG_UART_HOSTFS_TXBUFSIZE]; static struct uart_hostfs_priv_s g_uart_hostfs_priv; static struct uart_dev_s g_uart_hostfs_dev = { .ops = &g_uart_hostfs_ops, .priv = &g_uart_hostfs_priv, .xmit = { .size = CONFIG_UART_HOSTFS_TXBUFSIZE, .buffer = g_uart_hostfs_txbuf, }, .recv = { .size = CONFIG_UART_HOSTFS_RXBUFSIZE, .buffer = g_uart_hostfs_rxbuf, }, }; /**************************************************************************** * Private Functions ****************************************************************************/ static int uart_hostfs_setup(FAR struct uart_dev_s *dev) { FAR struct uart_hostfs_priv_s *priv = dev->priv; priv->fd = host_open(CONFIG_UART_HOSTFS_DEVPATH, O_RDWR | O_NONBLOCK, 0666); return priv->fd; } static void uart_hostfs_shutdown(FAR struct uart_dev_s *dev) { FAR struct uart_hostfs_priv_s *priv = dev->priv; if (priv->fd > 0) { host_close(priv->fd); priv->fd = -1; } } static int uart_hostfs_attach(FAR struct uart_dev_s *dev) { return OK; } static void uart_hostfs_detach(FAR struct uart_dev_s *dev) { } static int uart_hostfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { return -ENOTTY; } static void uart_hostfs_wdog(wdparm_t arg) { FAR struct uart_dev_s *dev = (FAR struct uart_dev_s *)arg; FAR struct uart_hostfs_priv_s *priv = dev->priv; if (priv->rxint) { uart_dmarxfree(dev); } wd_start(&priv->wdog, UART_WDOG_DELAY, uart_hostfs_wdog, (wdparm_t)dev); } static void uart_hostfs_rxint(FAR struct uart_dev_s *dev, bool enable) { FAR struct uart_hostfs_priv_s *priv = dev->priv; priv->rxint = enable; if (enable) { wd_start(&priv->wdog, 0, uart_hostfs_wdog, (wdparm_t)dev); } else { wd_cancel(&priv->wdog); } } static bool uart_hostfs_rxavailable(FAR struct uart_dev_s *dev) { return true; } #ifdef CONFIG_SERIAL_IFLOWCONTROL static bool uart_hostfs_rxflowcontrol(FAR struct uart_dev_s *dev, unsigned int nbuffered, bool upper) { FAR struct uart_buffer_s *rxbuf = &dev->recv; return nbuffered == rxbuf->size; } #endif static void uart_hostfs_dmatxavail(FAR struct uart_dev_s *dev) { uart_xmitchars_dma(dev); } static void uart_hostfs_dmasend(FAR struct uart_dev_s *dev) { FAR struct uart_hostfs_priv_s *priv = dev->priv; FAR struct uart_dmaxfer_s *xfer = &dev->dmatx; int ret; xfer->nbytes = 0; ret = host_write(priv->fd, xfer->buffer, xfer->length); if (ret > 0) { xfer->nbytes = ret; if (ret == xfer->length && xfer->nlength > 0) { ret = host_write(priv->fd, xfer->nbuffer, xfer->nlength); if (ret > 0) { xfer->nbytes += ret; } } } uart_xmitchars_done(dev); } static void uart_hostfs_dmarxfree(FAR struct uart_dev_s *dev) { uart_recvchars_dma(dev); } static void uart_hostfs_dmareceive(FAR struct uart_dev_s *dev) { FAR struct uart_hostfs_priv_s *priv = dev->priv; FAR struct uart_dmaxfer_s *xfer = &dev->dmarx; ssize_t ret; xfer->nbytes = 0; ret = host_read(priv->fd, xfer->buffer, xfer->length); if (ret > 0) { xfer->nbytes = ret; if (ret == xfer->length && xfer->nlength > 0) { ret = host_read(priv->fd, xfer->nbuffer, xfer->nlength); if (ret > 0) { xfer->nbytes += ret; } } } uart_recvchars_done(dev); } static void uart_hostfs_send(FAR struct uart_dev_s *dev, int ch) { FAR struct uart_hostfs_priv_s *priv = dev->priv; char c = ch; host_write(priv->fd, &c, 1); } static void uart_hostfs_txint(FAR struct uart_dev_s *dev, bool enable) { } static bool uart_hostfs_txready(FAR struct uart_dev_s *dev) { return true; } static bool uart_hostfs_txempty(FAR struct uart_dev_s *dev) { return true; } /**************************************************************************** * Public Functions ****************************************************************************/ void uart_hostfs_init(void) { uart_register("/dev/console", &g_uart_hostfs_dev); } void up_putc(int ch) { FAR struct uart_dev_s *dev = &g_uart_hostfs_dev; uart_hostfs_send(dev, ch); }