1 /* Ringbuffer based serial console layer, imported from OpenPCD */
3 /* (C) 2006-2010 by Harald Welte <laforge@gnumonks.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <calypso/uart.h>
28 #include <asm/system.h>
31 char buf[CONS_RB_SIZE];
36 static struct cons cons;
40 memset(cons.buf, 0, sizeof(cons.buf));
41 cons.next_inbyte = &cons.buf[0];
42 cons.next_outbyte = &cons.buf[0];
46 /* determine how many bytes are left in the ringbuffer without overwriting
47 bytes that haven't been written to the console yet */
48 static int __cons_rb_space(void)
50 if (cons.next_inbyte == cons.next_outbyte)
51 return sizeof(cons.buf)-1;
52 else if (cons.next_outbyte > cons.next_inbyte)
53 return (cons.next_outbyte - cons.next_inbyte) -1;
55 return sizeof(cons.buf) - 1 - (cons.next_inbyte - cons.next_outbyte);
58 /* pull one char out of debug ring buffer */
59 static int cons_rb_pull(char *ret)
63 local_irq_save(flags);
65 if (cons.next_outbyte == cons.next_inbyte) {
66 local_irq_restore(flags);
70 *ret = *cons.next_outbyte;
73 if (cons.next_outbyte >= &cons.buf[0]+sizeof(cons.buf)) {
74 cons.next_outbyte = &cons.buf[0];
77 else if (cons.next_outbyte > &cons.buf[0]+sizeof(cons.buf)) {
78 cons.next_outbyte -= sizeof(cons.buf);
82 local_irq_restore(flags);
87 /* returns if everything was flushed (1) or if there's more to flush (0) */
88 static void __rb_flush_wait(void)
91 while (cons_rb_pull(&ch) >= 0)
92 uart_putchar_wait(CONS_UART_NR, ch);
95 /* returns if everything was flushed (1) or if there's more to flush (0) */
96 static int __rb_flush(void)
98 while (!uart_tx_busy(CONS_UART_NR)) {
100 if (cons_rb_pull(&ch) < 0) {
101 /* no more data to write, disable interest in Tx FIFO interrupts */
104 uart_putchar_nb(CONS_UART_NR, ch);
107 /* if we reach here, UART Tx FIFO is busy again */
111 /* flush pending data from debug ring buffer to serial port */
112 int cons_rb_flush(void)
117 static void cons_memcpy(char *pos, const char *data, int len)
120 /* Somehow our memcpy is broken !?! */
121 memcpy(pos, data, len);
124 for (i = 0; i < len; i++)
129 /* Append bytes to ring buffer, not more than we have left! */
130 static void __cons_rb_append(const char *data, int len)
132 if (cons.next_inbyte + len >= &cons.buf[0]+sizeof(cons.buf)) {
133 int before_tail = (&cons.buf[0]+sizeof(cons.buf)) - cons.next_inbyte;
134 /* copy the first part before we wrap */
135 cons_memcpy(cons.next_inbyte, data, before_tail);
138 /* reset the buffer */
139 cons.next_inbyte = &cons.buf[0];
141 cons_memcpy(cons.next_inbyte, data, len);
142 cons.next_inbyte += len;
145 /* append bytes to the ringbuffer, do one wrap */
146 int cons_rb_append(const char *data, int len)
150 const char *data_cur;
152 /* we will never be able to write more than the console buffer */
153 if (len > (int) sizeof(cons.buf))
154 len = sizeof(cons.buf);
156 local_irq_save(flags);
158 bytes_left = __cons_rb_space();
161 if (len > bytes_left) {
162 /* append what we can */
163 __cons_rb_append(data_cur, bytes_left);
164 /* busy-wait for all characters to be transmitted */
166 /* fill it with the remaining bytes */
168 data_cur += bytes_left;
170 __cons_rb_append(data_cur, len);
172 /* we want to get Tx FIFO interrupts */
173 uart_irq_enable(CONS_UART_NR, UART_IRQ_TX_EMPTY, 1);
175 local_irq_restore(flags);
180 int cons_puts(const char *s)
182 if (cons.initialized) {
183 return cons_rb_append(s, strlen(s));
185 /* if the console is not active yet, we need to fall back */
188 uart_putchar_wait(CONS_UART_NR, *s++);
193 int cons_putchar(char c)
195 if (cons.initialized)
196 return cons_rb_append(&c, 1);
198 /* if the console is not active yet, we need to fall back */
199 uart_putchar_wait(CONS_UART_NR, c);