Switch from GPLv2 to GPLv2+
[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
59 #define USE_SERIAL_STDIN (USE_SERIAL_0_STDIN +  \
60                           USE_SERIAL_1_STDIN +  \
61                           USE_SERIAL_2_STDIN +  \
62                           USE_SERIAL_3_STDIN +  \
63                           USE_SERIAL_4_STDIN +  \
64                           USE_SERIAL_5_STDIN +  \
65                           USE_SERIAL_6_STDIN +  \
66                           USE_SERIAL_7_STDIN +  \
67                           USE_SERIAL_8_STDIN +  \
68                           USE_SERIAL_9_STDIN)
69
70 #define AO_NUM_STDIOS   (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN)
71
72 __xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS];
73
74 #if AO_NUM_STDIOS > 1
75 __pdata int8_t ao_cur_stdio;
76 __pdata int8_t ao_num_stdios;
77 #else
78 __pdata int8_t ao_cur_stdio;
79 #define ao_cur_stdio    0
80 #define ao_num_stdios   0
81 #endif
82
83 void
84 putchar(char c)
85 {
86 #if LOW_LEVEL_DEBUG
87         if (!ao_cur_task) {
88                 extern void ao_debug_out(char c);
89                 if (c == '\n')
90                         ao_debug_out('\r');
91                 ao_debug_out(c);
92                 return;
93         }
94 #endif
95         if (c == '\n')
96                 (*ao_stdios[ao_cur_stdio].putchar)('\r');
97         (*ao_stdios[ao_cur_stdio].putchar)(c);
98 }
99
100 void
101 flush(void)
102 {
103         if (ao_stdios[ao_cur_stdio].flush)
104                 ao_stdios[ao_cur_stdio].flush();
105 }
106
107 __xdata uint8_t ao_stdin_ready;
108
109 char
110 getchar(void) __reentrant
111 {
112         int c;
113         int8_t stdio;
114
115         ao_arch_block_interrupts();
116         stdio = ao_cur_stdio;
117         for (;;) {
118                 c = ao_stdios[stdio]._pollchar();
119                 if (c != AO_READ_AGAIN)
120                         break;
121 #if AO_NUM_STDIOS > 1
122                 if (++stdio == ao_num_stdios)
123                         stdio = 0;
124                 if (stdio == ao_cur_stdio)
125 #endif
126                         ao_sleep(&ao_stdin_ready);
127         }
128 #if AO_NUM_STDIOS > 1
129         ao_cur_stdio = stdio;
130 #endif
131         ao_arch_release_interrupts();
132         return c;
133 }
134
135 uint8_t
136 ao_echo(void)
137 {
138         return ao_stdios[ao_cur_stdio].echo;
139 }
140
141 int8_t
142 ao_add_stdio(int (*_pollchar)(void),
143              void (*putchar)(char),
144              void (*flush)(void)) __reentrant
145 {
146         if (ao_num_stdios == AO_NUM_STDIOS)
147                 ao_panic(AO_PANIC_STDIO);
148         ao_stdios[ao_num_stdios]._pollchar = _pollchar;
149         ao_stdios[ao_num_stdios].putchar = putchar;
150         ao_stdios[ao_num_stdios].flush = flush;
151         ao_stdios[ao_num_stdios].echo = 1;
152 #if AO_NUM_STDIOS > 1
153         return ao_num_stdios++;
154 #else
155         return 0;
156 #endif
157 }