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