summaryrefslogtreecommitdiff
path: root/common/uart_buffering.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-06-06 12:16:11 -0700
committerGerrit <chrome-bot@google.com>2012-06-07 00:54:02 -0700
commitc7f2e0246e8129aa179b09c5042d0265266e3a17 (patch)
tree62a7e81c5119b9a8f09078dc85078a3396a005b8 /common/uart_buffering.c
parent3073c600786c6170cb3ff4d05ebc917f154c4ec1 (diff)
downloadchrome-ec-c7f2e0246e8129aa179b09c5042d0265266e3a17.tar.gz
Move printf() formatting to its own file to enable re-use
Also add snprintf(), and %X format code. BUG=chrome-os-partner:10206 TEST=timerinfo; should print correctly. 'ectool battery' on host side should print same serial as 'battery' on EC console. Change-Id: I5c9f69d1a20ee5d0a59440c122655adbf62c9aea Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/24635 Reviewed-by: Simon Glass <sjg@chromium.org> Reviewed-by: Rong Chang <rongchang@chromium.org>
Diffstat (limited to 'common/uart_buffering.c')
-rw-r--r--common/uart_buffering.c221
1 files changed, 48 insertions, 173 deletions
diff --git a/common/uart_buffering.c b/common/uart_buffering.c
index 0aa3c760b7..9a0fd715ed 100644
--- a/common/uart_buffering.c
+++ b/common/uart_buffering.c
@@ -9,9 +9,9 @@
#include "console.h"
#include "task.h"
-#include "timer.h"
#include "uart.h"
#include "util.h"
+#include "printf.h"
/* Buffer sizes; should be power of 2 */
#define TX_BUF_SIZE 512
@@ -58,19 +58,17 @@ static volatile int cmd_history_ptr;
static int console_mode = 1;
-/* TODO: should have an API to set raw mode for the UART. In raw
- * mode, we don't do CRLF translation or echo input. */
-
/* Put a single character into the transmit buffer. Does not enable
* the transmit interrupt; assumes that happens elsewhere. Returns
- * zero if the character was transmitted, 1 if it was dropped. */
-static int __tx_char(int c)
+ * zero if the character was transmitted, 1 if it was dropped. We only
+ * have a single transmit buffer, so context is ignored. */
+static int __tx_char(void *context, int c)
{
int tx_buf_next;
/* Do newline to CRLF translation */
- if (console_mode && c == '\n' && __tx_char('\r'))
+ if (console_mode && c == '\n' && __tx_char(NULL, '\r'))
return 1;
tx_buf_next = TX_BUF_NEXT(tx_buf_head);
@@ -82,6 +80,7 @@ static int __tx_char(int c)
return 0;
}
+
static void move_rx_ptr_fwd(void)
{
if (rx_cur_buf_ptr != rx_cur_buf_head) {
@@ -93,6 +92,7 @@ static void move_rx_ptr_fwd(void)
}
}
+
static void move_rx_ptr_bwd(void)
{
if (rx_cur_buf_ptr != 0) {
@@ -104,12 +104,14 @@ static void move_rx_ptr_bwd(void)
}
}
+
static void repeat_char(char c, int cnt)
{
while (cnt--)
uart_write_char(c);
}
+
static void handle_backspace(void)
{
if (rx_cur_buf_ptr != 0) {
@@ -134,6 +136,7 @@ static void handle_backspace(void)
uart_write_char(' ');
}
+
static void insert_char(char c)
{
int ptr;
@@ -169,6 +172,7 @@ static void insert_char(char c)
}
}
+
static int rx_buf_space_available(void)
{
if (cmd_history_head == cmd_history_tail)
@@ -177,6 +181,7 @@ static int rx_buf_space_available(void)
cmd_history[CMD_HIST_PREV(cmd_history_head)].head);
}
+
static void history_save(void)
{
int ptr;
@@ -211,6 +216,7 @@ static void history_save(void)
cmd_history[hist_id].tail = tail;
}
+
static void history_load(int id)
{
int head = cmd_history[id].head;
@@ -238,6 +244,7 @@ static void history_load(int id)
rx_cur_buf_head = rx_cur_buf_ptr;
}
+
static void history_prev(void)
{
if (cmd_history_ptr == cmd_history_tail)
@@ -260,6 +267,7 @@ static void history_prev(void)
history_load(cmd_history_ptr);
}
+
static void history_next(void)
{
if (cmd_history_ptr == cmd_history_head)
@@ -273,6 +281,7 @@ static void history_next(void)
cmd_history_head = cmd_history_ptr;
}
+
/* Helper for UART processing */
void uart_process(void)
{
@@ -371,7 +380,7 @@ int uart_puts(const char *outstr)
{
/* Put all characters in the output buffer */
while (*outstr) {
- if (__tx_char(*outstr++) != 0)
+ if (__tx_char(NULL, *outstr++) != 0)
break;
}
@@ -385,190 +394,56 @@ int uart_puts(const char *outstr)
int uart_vprintf(const char *format, va_list args)
{
- static const char int_chars[] = "0123456789abcdef";
- static const char error_str[] = "ERROR";
- char intbuf[34];
- /* Longest uint64 in decimal = 20
- * longest uint32 in binary = 32
- */
- int dropped_chars = 0;
- int is_left;
- int pad_zero;
- int pad_width;
- char *vstr;
- int vlen;
-
- while (*format && !dropped_chars) {
- int c = *format++;
-
- /* Copy normal characters */
- if (c != '%') {
- dropped_chars |= __tx_char(c);
- continue;
- }
-
- /* Get first format character */
- c = *format++;
-
- /* Send "%" for "%%" input */
- if (c == '%' || c == '\0') {
- dropped_chars |= __tx_char('%');
- continue;
- }
-
- /* Handle %c */
- if (c == 'c') {
- c = va_arg(args, int);
- dropped_chars |= __tx_char(c);
- continue;
- }
-
- /* Handle left-justification ("%-5s") */
- is_left = (c == '-');
- if (is_left)
- c = *format++;
-
- /* Handle padding with 0's */
- pad_zero = (c == '0');
- if (pad_zero)
- c = *format++;
-
- /* Count padding length */
- pad_width = 0;
- while (c >= '0' && c <= '9') {
- pad_width = (10 * pad_width) + c - '0';
- c = *format++;
- }
- if (pad_width > 80) {
- /* Sanity check for width failed */
- format = error_str;
- continue;
- }
-
- if (c == 's') {
- vstr = va_arg(args, char *);
- if (vstr == NULL)
- vstr = "(NULL)";
- } else {
- uint64_t v;
- int is_negative = 0;
- int is_64bit = 0;
- int base = 10;
- int fixed_point = 0;
-
- /* Handle fixed point numbers */
- if (c == '.') {
- c = *format++;
- if (c < '0' || c > '9') {
- format = error_str;
- continue;
- }
- fixed_point = c - '0';
- c = *format++;
- }
-
- if (c == 'l') {
- is_64bit = 1;
- c = *format++;
- }
-
- /* Special-case: %T = current time */
- if (c == 'T') {
- v = get_time().val;
- is_64bit = 1;
- fixed_point = 6;
- } else if (is_64bit) {
- v = va_arg(args, uint64_t);
- } else {
- v = va_arg(args, uint32_t);
- }
+ int rv = vfnprintf(__tx_char, NULL, format, args);
- switch (c) {
- case 'd':
- if (is_64bit) {
- if ((int64_t)v < 0) {
- is_negative = 1;
- if (v != (1ULL << 63))
- v = -v;
- }
- } else {
- if ((int)v < 0) {
- is_negative = 1;
- if (v != (1ULL << 31))
- v = -(int)v;
- }
- }
- break;
- case 'u':
- case 'T':
- break;
- case 'x':
- case 'p':
- base = 16;
- break;
- case 'b':
- base = 2;
- break;
- default:
- format = error_str;
- }
- if (format == error_str)
- continue; /* Bad format specifier */
+ if (uart_tx_stopped())
+ uart_tx_start();
- /* Convert integer to string, starting at end of
- * buffer and working backwards. */
- vstr = intbuf + sizeof(intbuf) - 1;
- *(vstr) = '\0';
+ return rv;
+}
- /* Handle digits to right of decimal for fixed point
- * numbers. */
- for (vlen = 0; vlen < fixed_point; vlen++)
- *(--vstr) = int_chars[uint64divmod(&v, 10)];
- if (fixed_point)
- *(--vstr) = '.';
- if (!v)
- *(--vstr) = '0';
+int uart_printf(const char *format, ...)
+{
+ int rv;
+ va_list args;
- while (v)
- *(--vstr) = int_chars[uint64divmod(&v, base)];
+ va_start(args, format);
+ rv = uart_vprintf(format, args);
+ va_end(args);
+ return rv;
+}
- if (is_negative)
- *(--vstr) = '-';
- }
- /* Copy string (or stringified integer) */
- vlen = strlen(vstr);
- while (vlen < pad_width && !is_left) {
- dropped_chars |= __tx_char(pad_zero ? '0' : ' ');
- vlen++;
- }
- while (*vstr)
- dropped_chars |= __tx_char(*vstr++);
- while (vlen < pad_width && is_left) {
- dropped_chars |= __tx_char(' ');
- vlen++;
- }
- }
-
- if (uart_tx_stopped())
- uart_tx_start();
+/* Add a character directly to the UART buffer */
+static int emergency_txchar(void *format, int c)
+{
+ /* Wait for space */
+ while (!uart_tx_ready())
+ ;
- /* Successful if we consumed all output */
- return dropped_chars ? EC_ERROR_OVERFLOW : EC_SUCCESS;
+ /* Write the character */
+ uart_write_char(c);
+ return 0;
}
-int uart_printf(const char *format, ...)
+int uart_emergency_printf(const char *format, ...)
{
int rv;
va_list args;
va_start(args, format);
- rv = uart_vprintf(format, args);
+ rv = vfnprintf(emergency_txchar, NULL, format, args);
va_end(args);
+
+ /* Wait for transmit FIFO empty */
+ uart_tx_flush();
+
return rv;
}
+
+
/* For use when debugging verified boot. We could wrap it with a real function,
* but it's rarely needed and this doesn't add any extra code. We have to
* declare it here in order for this trick to work. */