blob: bef608be2b26115830cb63912fb7a288194ada67 [file] [log] [blame]
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -07001/*
2 * Copyright (c) 2011-2012, 2014-2015 Wind River Systems, Inc.
3 *
Javier B Perez Hernandezf7fffae2015-10-06 11:00:37 -05004 * 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
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -07007 *
Javier B Perez Hernandezf7fffae2015-10-06 11:00:37 -05008 * http://www.apache.org/licenses/LICENSE-2.0
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -07009 *
Javier B Perez Hernandezf7fffae2015-10-06 11:00:37 -050010 * 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.
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070015 */
16
Anas Nashif275ca602015-12-04 10:09:39 -050017/**
18 * @file
19 * @brief UART-driven console
20 *
Dan Kalowskyda67b292015-10-20 09:42:33 -070021 *
22 * Serial console driver.
23 * Hooks into the printk and fputc (for printf) modules. Poll driven.
Anas Nashifea0d0b22015-07-01 17:22:39 -040024 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070025
Andrei Emeltchenko139c8562015-04-20 11:04:22 +030026#include <nanokernel.h>
Dan Kalowskyc02dd342015-05-28 10:56:47 -070027#include <arch/cpu.h>
Andrei Emeltchenko139c8562015-04-20 11:04:22 +030028
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070029#include <stdio.h>
30#include <stdint.h>
Andrei Emeltchenko139c8562015-04-20 11:04:22 +030031#include <errno.h>
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070032
Daniel Leungad2d2962015-08-12 10:17:35 -070033#include <device.h>
34#include <init.h>
35
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070036#include <board.h>
Tomasz Bursztyka17e06fb2015-10-15 09:48:03 +030037#include <uart.h>
Tomasz Bursztykaae09a482015-04-23 13:12:51 +030038#include <console/uart_console.h>
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070039#include <toolchain.h>
40#include <sections.h>
41
Daniel Leung08b4fd42015-12-01 08:42:20 -080042static struct device *uart_console_dev;
43
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070044#if 0 /* NOTUSED */
Anas Nashifea0d0b22015-07-01 17:22:39 -040045/**
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070046 *
Anas Nashiff367f072015-07-01 17:51:40 -040047 * @brief Get a character from UART
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070048 *
Anas Nashif1362e3c2015-07-01 17:29:04 -040049 * @return the character or EOF if nothing present
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070050 */
51
Daniel Leung08b4fd42015-12-01 08:42:20 -080052static int console_in(void)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070053{
54 unsigned char c;
Dan Kalowskyda67b292015-10-20 09:42:33 -070055
Daniel Leung08b4fd42015-12-01 08:42:20 -080056 if (uart_poll_in(uart_console_dev, &c) < 0)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070057 return EOF;
58 else
59 return (int)c;
60}
61#endif
62
63#if defined(CONFIG_PRINTK) || defined(CONFIG_STDOUT_CONSOLE)
Anas Nashifea0d0b22015-07-01 17:22:39 -040064/**
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070065 *
Anas Nashiff367f072015-07-01 17:51:40 -040066 * @brief Output one character to UART
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070067 *
68 * Outputs both line feed and carriage return in the case of a '\n'.
69 *
Daniel Leung08b4fd42015-12-01 08:42:20 -080070 * @param c Character to output
71 *
Anas Nashif1362e3c2015-07-01 17:29:04 -040072 * @return The character passed as input.
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070073 */
74
Daniel Leung08b4fd42015-12-01 08:42:20 -080075static int console_out(int c)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070076{
Daniel Leung08b4fd42015-12-01 08:42:20 -080077 uart_poll_out(uart_console_dev, (unsigned char)c);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070078 if ('\n' == c) {
Daniel Leung08b4fd42015-12-01 08:42:20 -080079 uart_poll_out(uart_console_dev, (unsigned char)'\r');
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070080 }
81 return c;
82}
Daniel Leung08b4fd42015-12-01 08:42:20 -080083
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070084#endif
85
86#if defined(CONFIG_STDOUT_CONSOLE)
87extern void __stdout_hook_install(int (*hook)(int));
88#else
89#define __stdout_hook_install(x) \
90 do {/* nothing */ \
91 } while ((0))
92#endif
93
94#if defined(CONFIG_PRINTK)
95extern void __printk_hook_install(int (*fn)(int));
96#else
97#define __printk_hook_install(x) \
98 do {/* nothing */ \
99 } while ((0))
100#endif
101
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300102#if defined(CONFIG_CONSOLE_HANDLER)
Dan Kalowsky2e938482015-10-14 16:12:09 -0700103static size_t pos;
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300104
105static struct nano_fifo *avail_queue;
106static struct nano_fifo *lines_queue;
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300107
Daniel Leung1ad2a562015-08-05 12:13:36 -0700108static int read_uart(struct device *uart, uint8_t *buf, unsigned int size)
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300109{
110 int rx;
111
112 rx = uart_fifo_read(uart, buf, size);
113 if (rx < 0) {
114 /* Overrun issue. Stop the UART */
115 uart_irq_rx_disable(uart);
116
117 return -EIO;
118 }
119
120 return rx;
121}
122
Andrei Emeltchenkodfa5f232015-04-23 10:20:32 +0300123void uart_console_isr(void *unused)
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300124{
125 ARG_UNUSED(unused);
126
Daniel Leung08b4fd42015-12-01 08:42:20 -0800127 while (uart_irq_update(uart_console_dev)
128 && uart_irq_is_pending(uart_console_dev)) {
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300129 /* Character(s) have been received */
Daniel Leung08b4fd42015-12-01 08:42:20 -0800130 if (uart_irq_rx_ready(uart_console_dev)) {
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300131 static struct uart_console_input *cmd;
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300132 uint8_t byte;
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300133 int rx;
134
Daniel Leung08b4fd42015-12-01 08:42:20 -0800135 rx = read_uart(uart_console_dev, &byte, 1);
Peter Mitsisb1c10202015-09-17 13:22:00 -0400136 if (rx < 0) {
137 return;
138 }
139
Daniel Leung08b4fd42015-12-01 08:42:20 -0800140 if (uart_irq_input_hook(uart_console_dev, byte) != 0) {
Peter Mitsisb1c10202015-09-17 13:22:00 -0400141 /*
142 * The input hook indicates that no further processing
143 * should be done by this handler.
144 */
145 return;
146 }
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300147
148 if (!cmd) {
149 cmd = nano_isr_fifo_get(avail_queue);
150 if (!cmd)
151 return;
152 }
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300153
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300154 /* Echo back to console */
Daniel Leung08b4fd42015-12-01 08:42:20 -0800155 uart_poll_out(uart_console_dev, byte);
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300156
157 if (byte == '\r' || byte == '\n' ||
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300158 pos == sizeof(cmd->line) - 1) {
159 cmd->line[pos] = '\0';
Daniel Leung08b4fd42015-12-01 08:42:20 -0800160 uart_poll_out(uart_console_dev, '\n');
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300161 pos = 0;
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300162
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300163 nano_isr_fifo_put(lines_queue, cmd);
164 cmd = NULL;
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300165 } else {
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300166 cmd->line[pos++] = byte;
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300167 }
168
169 }
170 }
171}
172
Dmitriy Korovkin8d065342015-06-04 11:42:35 -0400173IRQ_CONNECT_STATIC(console, CONFIG_UART_CONSOLE_IRQ,
Daniel Leung08b4fd42015-12-01 08:42:20 -0800174 CONFIG_UART_CONSOLE_IRQ_PRI, uart_console_isr, 0,
Dmitriy Korovkinf1420512015-11-02 18:06:08 -0500175 UART_IRQ_FLAGS);
Dmitriy Korovkin8d065342015-06-04 11:42:35 -0400176
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300177static void console_input_init(void)
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300178{
179 uint8_t c;
180
Daniel Leung08b4fd42015-12-01 08:42:20 -0800181 uart_irq_rx_disable(uart_console_dev);
182 uart_irq_tx_disable(uart_console_dev);
Juan Manuel Cruzbc1a79c2015-11-30 11:21:13 -0600183 IRQ_CONFIG(console, uart_irq_get(uart_console_dev));
Daniel Leung08b4fd42015-12-01 08:42:20 -0800184 irq_enable(uart_irq_get(uart_console_dev));
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300185
186 /* Drain the fifo */
Daniel Leung08b4fd42015-12-01 08:42:20 -0800187 while (uart_irq_rx_ready(uart_console_dev)) {
188 uart_fifo_read(uart_console_dev, &c, 1);
Daniel Leung1ad2a562015-08-05 12:13:36 -0700189 }
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300190
Daniel Leung08b4fd42015-12-01 08:42:20 -0800191 uart_irq_rx_enable(uart_console_dev);
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300192}
193
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300194void uart_register_input(struct nano_fifo *avail, struct nano_fifo *lines)
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300195{
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300196 avail_queue = avail;
197 lines_queue = lines;
198
199 console_input_init();
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300200}
201#else
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300202#define console_input_init(x) \
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300203 do {/* nothing */ \
204 } while ((0))
Andrei Emeltchenko879541a2015-05-04 14:43:36 +0300205#define uart_register_input(x) \
Andrei Emeltchenko139c8562015-04-20 11:04:22 +0300206 do {/* nothing */ \
207 } while ((0))
208#endif
209
Anas Nashifea0d0b22015-07-01 17:22:39 -0400210/**
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700211 *
Daniel Leungad2d2962015-08-12 10:17:35 -0700212 * @brief Install printk/stdout hook for UART console output
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700213 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400214 * @return N/A
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700215 */
216
Daniel Leungad2d2962015-08-12 10:17:35 -0700217void uart_console_hook_install(void)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700218{
Daniel Leung08b4fd42015-12-01 08:42:20 -0800219 __stdout_hook_install(console_out);
220 __printk_hook_install(console_out);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700221}
Daniel Leungad2d2962015-08-12 10:17:35 -0700222
223/**
224 *
225 * @brief Initialize one UART as the console/debug port
226 *
227 * @return DEV_OK if successful, otherwise failed.
228 */
229static int uart_console_init(struct device *arg)
230{
231 ARG_UNUSED(arg);
232
Daniel Leung08b4fd42015-12-01 08:42:20 -0800233 uart_console_dev = device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME);
234
Daniel Leungad2d2962015-08-12 10:17:35 -0700235 uart_console_hook_install();
236
237 return DEV_OK;
238}
239DECLARE_DEVICE_INIT_CONFIG(uart_console, "", uart_console_init, NULL);
Dmitriy Korovkin57f27412015-10-26 15:56:02 -0400240
241/* UART consloe initializes after the UART device itself */
242#if defined(CONFIG_EARLY_CONSOLE)
243SYS_DEFINE_DEVICE(uart_console, NULL, PRIMARY, CONFIG_UART_CONSOLE_PRIORITY);
244#else
245SYS_DEFINE_DEVICE(uart_console, NULL, SECONDARY, CONFIG_UART_CONSOLE_PRIORITY);
246#endif