a stab at turning on rudimentary logging for telefiretwo
[fw/altos] / src / kernel / ao_stdio.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao.h"
20
21 /*
22  * Basic I/O functions to support SDCC stdio package
23  */
24
25 #ifndef USE_SERIAL_0_STDIN
26 #define USE_SERIAL_0_STDIN      0
27 #endif
28 #ifndef USE_SERIAL_1_STDIN
29 #define USE_SERIAL_1_STDIN      0
30 #endif
31 #ifndef USE_SERIAL_2_STDIN
32 #define USE_SERIAL_2_STDIN      0
33 #endif
34 #ifndef USE_SERIAL_3_STDIN
35 #define USE_SERIAL_3_STDIN      0
36 #endif
37 #ifndef USE_SERIAL_4_STDIN
38 #define USE_SERIAL_4_STDIN      0
39 #endif
40 #ifndef USE_SERIAL_5_STDIN
41 #define USE_SERIAL_5_STDIN      0
42 #endif
43 #ifndef USE_SERIAL_6_STDIN
44 #define USE_SERIAL_6_STDIN      0
45 #endif
46 #ifndef USE_SERIAL_7_STDIN
47 #define USE_SERIAL_7_STDIN      0
48 #endif
49 #ifndef USE_SERIAL_8_STDIN
50 #define USE_SERIAL_8_STDIN      0
51 #endif
52 #ifndef USE_SERIAL_9_STDIN
53 #define USE_SERIAL_9_STDIN      0
54 #endif
55 #ifndef PACKET_HAS_SLAVE
56 #define PACKET_HAS_SLAVE        0
57 #endif
58 #ifndef CONSOLE_STDIN
59 #define CONSOLE_STDIN           0
60 #endif
61
62 #define USE_SERIAL_STDIN (USE_SERIAL_0_STDIN +  \
63                           USE_SERIAL_1_STDIN +  \
64                           USE_SERIAL_2_STDIN +  \
65                           USE_SERIAL_3_STDIN +  \
66                           USE_SERIAL_4_STDIN +  \
67                           USE_SERIAL_5_STDIN +  \
68                           USE_SERIAL_6_STDIN +  \
69                           USE_SERIAL_7_STDIN +  \
70                           USE_SERIAL_8_STDIN +  \
71                           USE_SERIAL_9_STDIN)
72
73 #define AO_NUM_STDIOS   (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN + CONSOLE_STDIN)
74
75 __xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS];
76
77 #if AO_NUM_STDIOS > 1
78 __pdata int8_t ao_cur_stdio;
79 __pdata int8_t ao_num_stdios;
80 #else
81 __pdata int8_t ao_cur_stdio;
82 #define ao_cur_stdio    0
83 #define ao_num_stdios   0
84 #endif
85
86 void
87 putchar(char c)
88 {
89 #if LOW_LEVEL_DEBUG
90         if (!ao_cur_task) {
91                 extern void ao_debug_out(char c);
92                 if (c == '\n')
93                         ao_debug_out('\r');
94                 ao_debug_out(c);
95                 return;
96         }
97 #endif
98         if (c == '\n')
99                 (*ao_stdios[ao_cur_stdio].putchar)('\r');
100         (*ao_stdios[ao_cur_stdio].putchar)(c);
101 }
102
103 void
104 flush(void)
105 {
106         if (ao_stdios[ao_cur_stdio].flush)
107                 ao_stdios[ao_cur_stdio].flush();
108 }
109
110 __xdata uint8_t ao_stdin_ready;
111
112 char
113 getchar(void) __reentrant
114 {
115         int c;
116         int8_t stdio;
117
118         ao_arch_block_interrupts();
119         stdio = ao_cur_stdio;
120         for (;;) {
121                 c = ao_stdios[stdio]._pollchar();
122                 if (c != AO_READ_AGAIN)
123                         break;
124 #if AO_NUM_STDIOS > 1
125                 if (++stdio == ao_num_stdios)
126                         stdio = 0;
127                 if (stdio == ao_cur_stdio)
128 #endif
129                         ao_sleep(&ao_stdin_ready);
130         }
131 #if AO_NUM_STDIOS > 1
132         ao_cur_stdio = stdio;
133 #endif
134         ao_arch_release_interrupts();
135         return c;
136 }
137
138 uint8_t
139 ao_echo(void)
140 {
141         return ao_stdios[ao_cur_stdio].echo;
142 }
143
144 int8_t
145 ao_add_stdio(int (*_pollchar)(void),
146              void (*putchar)(char),
147              void (*flush)(void)) __reentrant
148 {
149         if (ao_num_stdios == AO_NUM_STDIOS)
150                 ao_panic(AO_PANIC_STDIO);
151         ao_stdios[ao_num_stdios]._pollchar = _pollchar;
152         ao_stdios[ao_num_stdios].putchar = putchar;
153         ao_stdios[ao_num_stdios].flush = flush;
154         ao_stdios[ao_num_stdios].echo = 1;
155 #if AO_NUM_STDIOS > 1
156         return ao_num_stdios++;
157 #else
158         return 0;
159 #endif
160 }