summaryrefslogtreecommitdiffstats
path: root/src/target/firmware/comm/sercomm_cons.c
blob: fa08b50efaf2dfbd6b2e18a0ac79cd8f0d2563dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* Serial console layer, layered on top of sercomm HDLC */

/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
 *
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include <stdint.h>
#include <errno.h>
#include <string.h>

#include <calypso/uart.h>

#include <console.h>
#include <comm/msgb.h>
#include <comm/sercomm.h>
#include <comm/sercomm_cons.h>

static struct {
	struct msgb *cur_msg;
} scons;

static void raw_puts(const char *s)
{
	int i = strlen(s);
	while (i--)
		uart_putchar_wait(SERCOMM_UART_NR, *s++);
}

#ifdef DEBUG
#define raw_putd(x)	raw_puts(x)
#else
#define raw_putd(x)
#endif

int sercomm_puts(const char *s)
{
	const int len = strlen(s) + 1;
	unsigned int bytes_left = len;

	if (!sercomm_initialized()) {
		raw_putd("sercomm not initialized: ");
		raw_puts(s);
		return len - 1;
	}

	while (bytes_left > 0) {
		unsigned int write_num, space_left, flush;
		uint8_t *data;

		if (!scons.cur_msg)
			scons.cur_msg = sercomm_alloc_msgb(SERCOMM_CONS_ALLOC);

		if (!scons.cur_msg) {
			raw_putd("cannot allocate sercomm msgb: ");
			raw_puts(s);
			return -ENOMEM;
		}

		/* space left in the current msgb */
		space_left = msgb_tailroom(scons.cur_msg);

		if (space_left <= bytes_left) {
			write_num = space_left;
			/* flush buffer when it is full */
			flush = 1;
		} else {
			write_num = bytes_left;
			flush = 0;
		}

		/* obtain pointer where to copy the data */
		data = msgb_put(scons.cur_msg, write_num);

		/* copy data while looking for \n line termination */
		{
			unsigned int i;
			for (i = 0; i < write_num; i++) {
				/* flush buffer at end of line */
				if (*s == '\n')
					flush = 1;
				*data++ = *s++;
			}
		}
		bytes_left -= write_num;

		if (flush) {
			sercomm_sendmsg(SC_DLCI_CONSOLE, scons.cur_msg);
			/* reset scons.cur_msg pointer to ensure we allocate
			 * a new one next round */
			scons.cur_msg = NULL;
		}
	}

	return len - 1;
}

int sercomm_putchar(int c)
{
	char s[2];
	int rc;

	s[0] = c & 0xff;
	s[1] = '\0';

	rc = sercomm_puts(s);
	if (rc < 0)
		return rc;

	return c;
}