treewide: remove FSF address
[osmocom-bb.git] / src / target / firmware / comm / sercomm_cons.c
blob275ca5a4f0bfae9e054cb95e8794bfcf132ba910
1 /* Serial console layer, layered on top of sercomm HDLC */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
5 * All Rights Reserved
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.
19 #include <stdint.h>
20 #include <errno.h>
21 #include <string.h>
23 #include <asm/system.h>
25 #include <uart.h>
27 #include <console.h>
28 #include <osmocom/core/msgb.h>
29 #include <comm/sercomm.h>
30 #include <comm/sercomm_cons.h>
32 static struct {
33 struct msgb *cur_msg;
34 } scons;
36 static void raw_puts(const char *s)
38 int i = strlen(s);
39 int uart_id = sercomm_get_uart();
40 while (i--)
41 uart_putchar_wait(uart_id, *s++);
44 #ifdef DEBUG
45 #define raw_putd(x) raw_puts(x)
46 #else
47 #define raw_putd(x)
48 #endif
50 int sercomm_puts(const char *s)
52 unsigned long flags;
53 const int len = strlen(s);
54 unsigned int bytes_left = len;
56 if (!sercomm_initialized()) {
57 raw_putd("sercomm not initialized: ");
58 raw_puts(s);
59 return len - 1;
62 /* This function is called from any context: Supervisor, IRQ, FIQ, ...
63 * as such, we need to ensure re-entrant calls are either supported or
64 * avoided. */
65 local_irq_save(flags);
66 local_fiq_disable();
68 while (bytes_left > 0) {
69 unsigned int write_num, space_left, flush;
70 uint8_t *data;
72 if (!scons.cur_msg)
73 scons.cur_msg = sercomm_alloc_msgb(SERCOMM_CONS_ALLOC);
75 if (!scons.cur_msg) {
76 raw_putd("cannot allocate sercomm msgb: ");
77 raw_puts(s);
78 return -ENOMEM;
81 /* space left in the current msgb */
82 space_left = msgb_tailroom(scons.cur_msg);
84 if (space_left <= bytes_left) {
85 write_num = space_left;
86 /* flush buffer when it is full */
87 flush = 1;
88 } else {
89 write_num = bytes_left;
90 flush = 0;
93 /* obtain pointer where to copy the data */
94 data = msgb_put(scons.cur_msg, write_num);
96 /* copy data while looking for \n line termination */
98 unsigned int i;
99 for (i = 0; i < write_num; i++) {
100 /* flush buffer at end of line, but skip
101 * flushing if we have a backlog in order to
102 * increase efficiency of msgb filling */
103 if (*s == '\n' &&
104 sercomm_tx_queue_depth(SC_DLCI_CONSOLE) < 4)
105 flush = 1;
106 *data++ = *s++;
109 bytes_left -= write_num;
111 if (flush) {
112 sercomm_sendmsg(SC_DLCI_CONSOLE, scons.cur_msg);
113 /* reset scons.cur_msg pointer to ensure we allocate
114 * a new one next round */
115 scons.cur_msg = NULL;
119 local_irq_restore(flags);
121 return len - 1;
124 int sercomm_putchar(int c)
126 char s[2];
127 int rc;
129 s[0] = c & 0xff;
130 s[1] = '\0';
132 rc = sercomm_puts(s);
133 if (rc < 0)
134 return rc;
136 return c;