blob: 8297522899165684901ec4ea72dc72779e35f883 [file] [log] [blame]
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +02001/*
2 * Copyright (c) 2017 Nordic Semiconductor ASA
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
Peter Bigot54c1e3f2020-01-25 05:50:12 -060018#include <drivers/uart.h>
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020019#include <assert.h>
20#include <string.h>
21#include <zephyr.h>
Emanuele Di Santod1fd3f92018-07-20 11:34:14 +020022#include "bootutil/bootutil_log.h"
Andrzej Puzdrowskiac1f1ff2020-02-05 08:40:12 +010023#include <usb/usb_device.h>
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020024
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +010025#if defined(CONFIG_BOOT_SERIAL_UART) && defined(CONFIG_UART_CONSOLE)
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020026#error Zephyr UART console must been disabled if serial_adapter module is used.
27#endif
28
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010029MCUBOOT_LOG_MODULE_REGISTER(serial_adapter);
30
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020031/** @brief Console input representation
32 *
33 * This struct is used to represent an input line from a serial interface.
34 */
35struct line_input {
Carles Cufi5ceeddb2018-06-15 12:43:22 +020036 /** Required to use sys_slist */
37 sys_snode_t node;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020038
Carles Cufi5ceeddb2018-06-15 12:43:22 +020039 int len;
40 /** Buffer where the input line is recorded */
41 char line[CONFIG_BOOT_MAX_LINE_INPUT_LEN];
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020042};
43
Dominik Ermel1422b4b2020-09-11 11:31:38 +000044static struct device const *uart_dev;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020045static struct line_input line_bufs[2];
46
Carles Cufi6400f0b2018-07-17 17:32:12 +020047static sys_slist_t avail_queue;
48static sys_slist_t lines_queue;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020049
Kumar Gala0813efe2020-05-27 12:25:41 -050050static uint16_t cur;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020051
52static int boot_uart_fifo_getline(char **line);
53static int boot_uart_fifo_init(void);
54
55int
56console_out(int c)
57{
Carles Cufi5ceeddb2018-06-15 12:43:22 +020058 uart_poll_out(uart_dev, c);
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020059
Carles Cufi5ceeddb2018-06-15 12:43:22 +020060 return c;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020061}
62
63void
64console_write(const char *str, int cnt)
65{
Carles Cufi5ceeddb2018-06-15 12:43:22 +020066 int i;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020067
Carles Cufi5ceeddb2018-06-15 12:43:22 +020068 for (i = 0; i < cnt; i++) {
69 if (console_out((int)str[i]) == EOF) {
70 break;
71 }
72 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020073}
74
75int
76console_read(char *str, int str_size, int *newline)
77{
Carles Cufi5ceeddb2018-06-15 12:43:22 +020078 char *line;
79 int len;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020080
Carles Cufi5ceeddb2018-06-15 12:43:22 +020081 len = boot_uart_fifo_getline(&line);
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020082
Carles Cufi5ceeddb2018-06-15 12:43:22 +020083 if (line == NULL) {
84 *newline = 0;
85 return 0;
86 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020087
Carles Cufi5ceeddb2018-06-15 12:43:22 +020088 if (len > str_size - 1) {
89 len = str_size - 1;
90 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020091
Carles Cufi5ceeddb2018-06-15 12:43:22 +020092 memcpy(str, line, len);
93 str[len] = '\0';
94 *newline = 1;
95 return len + 1;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +020096}
97
98int
99boot_console_init(void)
100{
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200101 int i;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200102
Carles Cufi6400f0b2018-07-17 17:32:12 +0200103 /* Zephyr UART handler takes an empty buffer from avail_queue,
104 * stores UART input in it until EOL, and then puts it into
105 * lines_queue.
106 */
107 sys_slist_init(&avail_queue);
108 sys_slist_init(&lines_queue);
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200109
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200110 for (i = 0; i < ARRAY_SIZE(line_bufs); i++) {
Carles Cufi6400f0b2018-07-17 17:32:12 +0200111 sys_slist_append(&avail_queue, &line_bufs[i].node);
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200112 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200113
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200114 return boot_uart_fifo_init();
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200115}
116
117static void
Dominik Ermel1422b4b2020-09-11 11:31:38 +0000118boot_uart_fifo_callback(const struct device *dev, void *user_data)
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200119{
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200120 static struct line_input *cmd;
Kumar Gala0813efe2020-05-27 12:25:41 -0500121 uint8_t byte;
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200122 int rx;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200123
Emanuele Di Santod1fd3f92018-07-20 11:34:14 +0200124 uart_irq_update(uart_dev);
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200125
Emanuele Di Santod1fd3f92018-07-20 11:34:14 +0200126 if (!uart_irq_rx_ready(uart_dev)) {
127 return;
128 }
129
130 while (true) {
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200131 rx = uart_fifo_read(uart_dev, &byte, 1);
132 if (rx != 1) {
Emanuele Di Santod1fd3f92018-07-20 11:34:14 +0200133 break;
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200134 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200135
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200136 if (!cmd) {
137 sys_snode_t *node;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200138
Carles Cufi6400f0b2018-07-17 17:32:12 +0200139 node = sys_slist_get(&avail_queue);
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200140 if (!node) {
Emanuele Di Santod1fd3f92018-07-20 11:34:14 +0200141 BOOT_LOG_ERR("Not enough memory to store"
142 " incoming data!");
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200143 return;
144 }
145 cmd = CONTAINER_OF(node, struct line_input, node);
146 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200147
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200148 if (cur < CONFIG_BOOT_MAX_LINE_INPUT_LEN) {
149 cmd->line[cur++] = byte;
150 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200151
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200152 if (byte == '\n') {
153 cmd->len = cur;
Carles Cufi6400f0b2018-07-17 17:32:12 +0200154 sys_slist_append(&lines_queue, &cmd->node);
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200155 cur = 0;
Carles Cufib124e392018-07-17 17:27:50 +0200156 cmd = NULL;
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200157 }
158 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200159}
160
161static int
162boot_uart_fifo_getline(char **line)
163{
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200164 static struct line_input *cmd;
165 sys_snode_t *node;
Andrzej Puzdrowski30117142018-06-18 14:43:14 +0200166 int key;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200167
Andrzej Puzdrowski30117142018-06-18 14:43:14 +0200168 key = irq_lock();
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200169 /* Recycle cmd buffer returned previous time */
170 if (cmd != NULL) {
Carles Cufi6400f0b2018-07-17 17:32:12 +0200171 if (sys_slist_peek_tail(&avail_queue) != &cmd->node) {
172 sys_slist_append(&avail_queue, &cmd->node);
Andrzej Puzdrowski30117142018-06-18 14:43:14 +0200173 }
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200174 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200175
Carles Cufi6400f0b2018-07-17 17:32:12 +0200176 node = sys_slist_get(&lines_queue);
Andrzej Puzdrowski30117142018-06-18 14:43:14 +0200177 irq_unlock(key);
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200178
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200179 if (node == NULL) {
180 cmd = NULL;
181 *line = NULL;
Andrzej Puzdrowski30117142018-06-18 14:43:14 +0200182
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200183 return 0;
184 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200185
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200186 cmd = CONTAINER_OF(node, struct line_input, node);
187 *line = cmd->line;
188 return cmd->len;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200189}
190
191static int
192boot_uart_fifo_init(void)
193{
Emanuele Di Santoc4bf7802018-07-20 11:39:57 +0200194#ifdef CONFIG_BOOT_SERIAL_UART
Andrzej Puzdrowskif0004802019-10-01 14:13:35 +0200195 uart_dev = device_get_binding(CONFIG_RECOVERY_UART_DEV_NAME);
Emanuele Di Santoc4bf7802018-07-20 11:39:57 +0200196#elif CONFIG_BOOT_SERIAL_CDC_ACM
Filip Kubiczdb6be2d2019-05-16 15:48:24 +0200197 uart_dev = device_get_binding(CONFIG_USB_CDC_ACM_DEVICE_NAME "_0");
Andrzej Puzdrowskiac1f1ff2020-02-05 08:40:12 +0100198 if (uart_dev) {
199 int rc;
200 rc = usb_enable(NULL);
201 if (rc) {
202 return (-1);
203 }
204 }
Emanuele Di Santoc4bf7802018-07-20 11:39:57 +0200205#endif
Kumar Gala0813efe2020-05-27 12:25:41 -0500206 uint8_t c;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200207
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200208 if (!uart_dev) {
209 return (-1);
210 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200211
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200212 uart_irq_callback_set(uart_dev, boot_uart_fifo_callback);
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200213
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200214 /* Drain the fifo */
Emanuele Di Santod1fd3f92018-07-20 11:34:14 +0200215 if (uart_irq_rx_ready(uart_dev)) {
216 while (uart_fifo_read(uart_dev, &c, 1)) {
217 ;
218 }
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200219 }
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200220
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200221 cur = 0;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200222
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200223 uart_irq_rx_enable(uart_dev);
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200224
Carles Cufi5e48c552018-06-15 12:58:08 +0200225 /* Enable all interrupts unconditionally. Note that this is due
226 * to Zephyr issue #8393. This should be removed once the
Emanuele Di Santod1fd3f92018-07-20 11:34:14 +0200227 * issue is fixed in upstream Zephyr.
228 */
Carles Cufi5e48c552018-06-15 12:58:08 +0200229 irq_unlock(0);
230
Carles Cufi5ceeddb2018-06-15 12:43:22 +0200231 return 0;
Andrzej Puzdrowskif6f652e2017-10-19 11:21:52 +0200232}