diff --git a/Makefile.am b/Makefile.am index fee51de86f293116a10d17afe00fd54abd3429ba..7e80a535c07d1dd20c69a4a59c4b6f17f9f7c045 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,3 +18,7 @@ endif if BLUETOOTH gbridge_SOURCES += bluetooth.c endif + +if UART +gbridge_SOURCES += uart.c +endif \ No newline at end of file diff --git a/configure.ac b/configure.ac index 190443f56faaccd9ac9eb313bdfc0c636b257231..72f61babcbf450c5452c6a0d44bbcea06f15245d 100644 --- a/configure.ac +++ b/configure.ac @@ -42,6 +42,16 @@ AC_ARG_ENABLE([tcpip], esac]) AM_CONDITIONAL([TPCIP], [test x$tcpip = xtrue]) +AC_ARG_ENABLE([uart], +[ --enable-uart Enable uart], +[case "${enableval}" in + yes) uart=true ; + AC_DEFINE([HAVE_UART], [1], ["UART support"]) ;; + no) uart=false ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-uart]) ;; +esac]) +AM_CONDITIONAL([UART], [test x$uart = xtrue]) + AC_ARG_VAR([GBDIR], ["greybus sources directory"]) AS_IF([test "$GBDIR" = ""], [ AC_MSG_ERROR([Environment variable GBDIR needs to be set]) diff --git a/main.c b/main.c index d3c73408cd84672cbe26d0fb4ae7d55fba6de81e..80d5f3db4fdaef530a78b03819a0c1e2d0330446 100644 --- a/main.c +++ b/main.c @@ -16,13 +16,28 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> #include <signal.h> +#include <unistd.h> #include <debug.h> #include <controller.h> #include "gbridge.h" #include "netlink.h" +#include "uart.h" + +static void help(void) +{ + printf("gbridge: Greybus bridge application\n" + "\t-h: Print the help\n" +#ifdef HAVE_UART + "uart options:\n" + "\t-p uart_device: set the uart device\n" + "\t-b baudrate: set the uart baudrate\n" +#endif + ); +} static void signal_handler(int sig) { @@ -31,12 +46,33 @@ static void signal_handler(int sig) int main(int argc, char *argv[]) { + int c; int ret; + int baudrate = 115200; + const char *uart = NULL; + signal(SIGINT, signal_handler); signal(SIGHUP, signal_handler); signal(SIGTERM, signal_handler); + while ((c = getopt(argc, argv, "p:b:")) != -1) { + switch(c) { + case 'p': + uart = optarg; + break; + case 'b': + if (sscanf(optarg, "%u", &baudrate) != 1) { + help(); + return -EINVAL; + } + break; + default: + help(); + return -EINVAL; + } + } + ret = greybus_init(); if (ret) { pr_err("Failed to init Greybus\n"); @@ -55,6 +91,14 @@ int main(int argc, char *argv[]) goto err_netlink_exit; } + if (uart) { + ret = register_uart_controller(uart, baudrate); + if (ret) { + pr_err("Failed to init uart controller\n"); + goto err_netlink_exit; + } + } + controllers_init(); netlink_loop(); diff --git a/uart.c b/uart.c new file mode 100644 index 0000000000000000000000000000000000000000..bb74f4d20cdd3798d3d0638780d3ddecadc17446 --- /dev/null +++ b/uart.c @@ -0,0 +1,183 @@ +/* + * This program 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, either version 3 of the License, or + * (at your option) any later version. + + * This program 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/>. + + * Author: Alexandre Bailon <abailon@baylibre.com> + * Copyright (c) 2016 Alexandre Bailon + */ + +#include <debug.h> +#include <gbridge.h> +#include <controller.h> +#include <uart.h> + +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <termios.h> +#include <unistd.h> + +struct controller uart_controller; + +struct uart_controller { + int fd; +}; + +int register_uart_controller(const char *file_name, int baudrate) +{ + int ret; + struct termios tio; + struct controller *ctrl; + struct uart_controller *uart_ctrl; + + uart_ctrl = malloc(sizeof(*uart_ctrl)); + if (!uart_ctrl) + return -ENOMEM; + + tcgetattr(uart_ctrl->fd, &tio); + cfsetospeed(&tio, baudrate); + cfsetispeed(&tio, baudrate); + tio.c_cflag = CS8 | CREAD; + tio.c_iflag = IGNBRK; + tio.c_lflag = 0; + tio.c_oflag = 0; + + uart_ctrl->fd = open(file_name, O_RDWR | O_NOCTTY | O_NDELAY); + if (uart_ctrl->fd < 0) { + free(uart_ctrl); + return uart_ctrl->fd; + } + + ret = tcsetattr(uart_ctrl->fd, TCSANOW, &tio); + if (ret < 0) { + close(uart_ctrl->fd); + free(uart_ctrl); + } + + ctrl = malloc(sizeof(*ctrl)); + if (!ctrl) { + close(uart_ctrl->fd); + free(uart_ctrl); + return -ENOMEM; + } + + memcpy(ctrl, &uart_controller, sizeof(*ctrl)); + ctrl->priv = uart_ctrl; + register_controller(ctrl); + + return 0; +} + +static int uart_init(struct controller * ctrl) +{ + return 0; +} + +static void uart_exit(struct controller * ctrl) +{ + struct uart_controller *uart_ctrl = ctrl->priv; + + close(uart_ctrl->fd); + free(uart_ctrl); +} + +static int uart_hotplug(struct controller *ctrl) +{ + int ret; + struct interface *intf; + + /* FIXME: use real IDs */ + intf = interface_create(ctrl, 1, 1, 0x1234, NULL); + if (!intf) + return -ENOMEM; + + ret = interface_hotplug(intf); + if (ret < 0) { + interface_destroy(intf); + return ret; + } + + return 0; +} + +static int uart_write(struct connection * conn, void *data, size_t len) +{ + struct uart_controller *ctrl = conn->intf->ctrl->priv; + + cport_pack(data, conn->cport2_id); + return write(ctrl->fd, data, len); +} + +static int _uart_read(struct uart_controller *ctrl, + void *data, size_t len) +{ + int ret; + uint8_t *p_data = data; + + while (len) { + ret = read(ctrl->fd, p_data, len); + if (ret == 0 || ret == -EAGAIN || + (ret == -1 && errno == -EAGAIN )) + usleep(10); + else if (ret < -1) + return ret; + else { + len -= ret; + p_data += ret; + } + } + + return 0; +} + +static int uart_read(struct interface * intf, + uint16_t * cport_id, void *data, size_t len) +{ + int ret; + uint8_t *p_data = data; + struct uart_controller *ctrl = intf->ctrl->priv; + + ret = _uart_read(ctrl, p_data, sizeof(struct gb_operation_msg_hdr)); + if (ret) { + pr_err("Failed to get header\n"); + return ret; + } + + ret = gb_operation_msg_size(data); + if (ret > len) { + pr_err("Message to big\n"); + return -EMSGSIZE; /* FIXME: drop remaining data */ + } + + p_data += sizeof(struct gb_operation_msg_hdr); + len = ret - sizeof(struct gb_operation_msg_hdr); + ret = _uart_read(ctrl, p_data, len); + if (ret) { + pr_err("Failed to get the payload\n"); + return ret; + } + + *cport_id = cport_unpack(data); + + return len + sizeof(struct gb_operation_msg_hdr); +} + +struct controller uart_controller = { + .name = "uart", + .init = uart_init, + .exit = uart_exit, + .write = uart_write, + .intf_read = uart_read, + .event_loop = uart_hotplug, +}; \ No newline at end of file diff --git a/uart.h b/uart.h new file mode 100644 index 0000000000000000000000000000000000000000..289a9438b3238eafc1e71ce5b296617474d8d45e --- /dev/null +++ b/uart.h @@ -0,0 +1,36 @@ +/* + * This program 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, either version 3 of the License, or + * (at your option) any later version. + + * This program 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/>. + + * Author: Alexandre Bailon <abailon@baylibre.com> + * Copyright (c) 2016 Alexandre Bailon + */ + +#ifndef _UART_H_ +#define _UART_H_ + +#include <config.h> +#include <debug.h> + +#ifdef HAVE_UART +int register_uart_controller(const char *file_name, int baudrate); +#else +int register_uart_controller(const char *file_name, int baudrate) +{ + pr_err("UART support has not been compiled.\n"); + + return -1; +} +#endif + +#endif /* _UART_H_ */ \ No newline at end of file